void _free(void *ptr) { t_block *block; RETURN(!ptr || ptr > (void *)moreSpace(0, true)); block = GET_BLOCK(ptr); RETURN(block->isFree); mergeBlocks(&block); block->isFree = true; if (block == block->parent->lastBlock) { block->parent->lastBlock = block->prev; block->parent->freeSize += B_SIZE(block->size); if (!block->parent->next && block->parent->freeSize > PAGE_SIZE) { if (blocks != block->parent) { if (block->parent->prev) block->parent->prev->next = block->parent->next; brk(block->parent); } } } else if (block->parent->maxFreeSize < block->size) block->parent->maxFreeSize = block->size; }
void convertToJump(BasicBlock* block, BasicBlock* targetBlock) { ASSERT(targetBlock); ASSERT(targetBlock->isReachable); if (targetBlock->predecessors.size() == 1) { m_graph.dethread(); mergeBlocks(block, targetBlock, noBlocks()); } else { Node* branch = block->terminal(); ASSERT(branch->op() == Branch || branch->op() == Switch); block->replaceTerminal( m_graph, SpecNone, Jump, branch->origin, OpInfo(targetBlock)); } }
bool SimplifyControlFlowGraphPass::_mergeBlockIntoPredecessor(ir::IRKernel& k) { bool merged = false; report(" Merging blocks with predecessors..."); for(ir::ControlFlowGraph::iterator block = k.cfg()->begin(); block != k.cfg()->end(); ) { if(block == k.cfg()->get_entry_block()) { ++block; continue; } if(block == k.cfg()->get_exit_block()) { ++block; continue; } // Block has a single predecessor bool singlePredecessor = block->in_edges.size() == 1; if(!singlePredecessor) { ++block; continue; } // Predecessor has single successor auto predecessor = block->in_edges.back()->head; if(predecessor == k.cfg()->get_entry_block()) { ++block; continue; } bool singleSuccessor = predecessor->out_edges.size() == 1; if(!singleSuccessor) { ++block; continue; } report(" " << predecessor->label() << " <- " << block->label()); // Merge the blocks mergeBlocks(k, predecessor, block++); merged = true; } return merged; }
memPtrSize CHeapManager::mergeIteration(memPtrSize mergeBlock) { if (smallMemSet.size() > 0) { auto smallLowerBound = smallMemSet.lower_bound(mergeBlock); if (smallLowerBound != smallMemSet.end() && *smallLowerBound == mergeBlock) { smallLowerBound--; } auto smallUpperBound = smallMemSet.upper_bound(mergeBlock); if (smallUpperBound == smallMemSet.end()) { smallUpperBound--; } if (smallLowerBound != smallMemSet.end() && canMerge(*smallLowerBound, mergeBlock) == LMERGE) { memPtrSize newBlock = mergeBlocks(*smallLowerBound, mergeBlock); smallMemSet.erase(smallLowerBound); delFromMemSet(mergeBlock); addToMemSet(newBlock); return newBlock; } if (canMerge(mergeBlock, *smallUpperBound) == LMERGE) { memPtrSize newBlock = mergeBlocks(mergeBlock, *smallUpperBound); smallMemSet.erase(smallUpperBound); delFromMemSet(mergeBlock); addToMemSet(newBlock); return newBlock; } } if (mediumMemSet.size() > 0) { auto mediumLowerBound = mediumMemSet.lower_bound(mergeBlock); if (mediumLowerBound != mediumMemSet.end() && *mediumLowerBound == mergeBlock) { mediumLowerBound--; } auto mediumUpperBound = mediumMemSet.upper_bound(mergeBlock); if (mediumUpperBound == mediumMemSet.end()) { mediumUpperBound--; } if (mediumLowerBound != mediumMemSet.end() && canMerge(*mediumLowerBound, mergeBlock) == LMERGE) { memPtrSize newBlock = mergeBlocks(*mediumLowerBound, mergeBlock); mediumMemSet.erase(mediumLowerBound); delFromMemSet(mergeBlock); addToMemSet(newBlock); return newBlock; } if (canMerge(mergeBlock, *mediumUpperBound) == LMERGE) { memPtrSize newBlock = mergeBlocks(mergeBlock, *mediumUpperBound); mediumMemSet.erase(mediumUpperBound); delFromMemSet(mergeBlock); addToMemSet(newBlock); return newBlock; } } if (largeMemSet.size() > 0) { auto largeLowerBound = largeMemSet.lower_bound(mergeBlock); if (largeLowerBound != largeMemSet.end() && *largeLowerBound == mergeBlock) { largeLowerBound--; } auto largeUpperBound = largeMemSet.upper_bound(mergeBlock); if (largeUpperBound == largeMemSet.end()) { largeUpperBound--; } if (largeLowerBound != largeMemSet.end() && canMerge(*largeLowerBound, mergeBlock) == LMERGE) { memPtrSize newBlock = mergeBlocks(*largeLowerBound, mergeBlock); largeMemSet.erase(largeLowerBound); delFromMemSet(mergeBlock); addToMemSet(newBlock); return newBlock; } if (canMerge(mergeBlock, *largeUpperBound) == LMERGE) { memPtrSize newBlock = mergeBlocks(mergeBlock, *largeUpperBound); largeMemSet.erase(largeUpperBound); delFromMemSet(mergeBlock); addToMemSet(newBlock); return newBlock; } } return (std::make_pair((void *)NULL, -1)); }
bool MergedMiner::mine(std::string address1, std::string wallet1, std::string address2, std::string wallet2, size_t threads) { epee::net_utils::http::http_simple_client httpClient1; epee::net_utils::http::http_simple_client httpClient2; Miner miner; BlockTemplate blockTemplate1; BlockTemplate blockTemplate2; cryptonote::block block1; cryptonote::block block2; cryptonote::difficulty_type difficulty1; cryptonote::difficulty_type difficulty2; std::future<bool> request1; std::future<bool> request2; std::future<bool> mining; crypto::hash hash; std::chrono::steady_clock::time_point time1; uint64_t prefix1; cryptonote::account_public_address walletAddress1; if (!get_account_address_from_str(prefix1, walletAddress1, wallet1)) { std::lock_guard<std::mutex> lock(m_mutex); m_messages.push("Failed to parse donor wallet address"); return false; } uint64_t prefix2; cryptonote::account_public_address walletAddress2; if (!address2.empty() && !get_account_address_from_str(prefix2, walletAddress2, wallet2)) { std::lock_guard<std::mutex> lock(m_mutex); m_messages.push("Failed to parse acceptor wallet address"); return false; } m_blockCount = 0; for (;;) { miner.getHashCount(); if (m_stopped) { if (mining.valid()) { miner.stop(); mining.wait(); } return true; } request1 = std::async(std::launch::async, getBlockTemplate, &httpClient1, &address1, &wallet1, MERGE_MINING_TAG_RESERVED_SIZE, &blockTemplate1); if (!address2.empty()) { request2 = std::async(std::launch::async, getBlockTemplate, &httpClient2, &address2, &wallet2, MERGE_MINING_TAG_RESERVED_SIZE, &blockTemplate2); } if (!request1.get()) { std::lock_guard<std::mutex> lock(m_mutex); m_messages.push("Failed to get donor block"); continue; } if (!address2.empty()) { if (!request2.get()) { std::lock_guard<std::mutex> lock(m_mutex); m_messages.push("Failed to get acceptor block"); continue; } if (blockTemplate2.block.major_version != BLOCK_MAJOR_VERSION_2) { std::lock_guard<std::mutex> lock(m_mutex); m_messages.push("Unsupported block version received from acceptor network, merged mining is not possible"); if (mining.valid()) { miner.stop(); mining.wait(); } return false; } } if (mining.valid()) { miner.stop(); if (mining.get()) { if (cryptonote::check_hash(hash, difficulty1)) { if (submitBlock(httpClient1, address1, block1)) { std::lock_guard<std::mutex> lock(m_mutex); m_messages.push("Submitted donor block"); } else { std::lock_guard<std::mutex> lock(m_mutex); m_messages.push("Failed to submit donor block"); } } if (!address2.empty() && cryptonote::check_hash(hash, difficulty2)) { if (!mergeBlocks(block1, block2)) { std::lock_guard<std::mutex> lock(m_mutex); m_messages.push("Internal error"); return false; } if (submitBlock(httpClient2, address2, block2)) { std::lock_guard<std::mutex> lock(m_mutex); m_messages.push("Submitted acceptor block"); } else { std::lock_guard<std::mutex> lock(m_mutex); m_messages.push("Failed to submit acceptor block"); } } } std::chrono::steady_clock::time_point time2 = std::chrono::steady_clock::now(); std::ostringstream stream; stream << "Hashrate: " << miner.getHashCount() / std::chrono::duration_cast<std::chrono::duration<double>>(time2 - time1).count(); std::lock_guard<std::mutex> lock(m_mutex); m_messages.push(stream.str()); time1 = time2; miner.start(); } else { time1 = std::chrono::steady_clock::now(); } block1 = blockTemplate1.block; difficulty1 = blockTemplate1.difficulty; cryptonote::difficulty_type difficulty = difficulty1; if (!address2.empty()) { block2 = blockTemplate2.block; difficulty2 = blockTemplate2.difficulty; difficulty = std::min(difficulty, difficulty2); if (!fillExtra(block1, block2)) { std::lock_guard<std::mutex> lock(m_mutex); m_messages.push("Internal error"); return false; } } mining = std::async(std::launch::async, &Miner::findNonce, &miner, &block1, blockTemplate1.height, difficulty, threads, &hash); for (size_t i = 0; i < 50; ++i) { if (m_stopped || mining.wait_for(std::chrono::milliseconds(100)) == std::future_status::ready) { break; } } } }
bool run() { const bool extremeLogging = false; bool outerChanged = false; bool innerChanged; do { innerChanged = false; for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) { BasicBlock* block = m_graph.block(blockIndex); if (!block) continue; ASSERT(block->isReachable); switch (block->last()->op()) { case Jump: { // Successor with one predecessor -> merge. if (block->successor(0)->predecessors.size() == 1) { ASSERT(block->successor(0)->predecessors[0] == block); if (extremeLogging) m_graph.dump(); m_graph.dethread(); mergeBlocks(block, block->successor(0), noBlocks()); innerChanged = outerChanged = true; break; } // FIXME: Block only has a jump -> remove. This is tricky though because of // liveness. What we really want is to slam in a phantom at the end of the // block, after the terminal. But we can't right now. :-( // Idea: what if I slam the ghosties into my successor? Nope, that's // suboptimal, because if my successor has multiple predecessors then we'll // be keeping alive things on other predecessor edges unnecessarily. // What we really need is the notion of end-of-block ghosties! break; } case Branch: { // Branch on constant -> jettison the not-taken block and merge. if (isKnownDirection(block->cfaBranchDirection)) { bool condition = branchCondition(block->cfaBranchDirection); BasicBlock* targetBlock = block->successorForCondition(condition); BasicBlock* jettisonedBlock = block->successorForCondition(!condition); if (targetBlock->predecessors.size() == 1) { if (extremeLogging) m_graph.dump(); m_graph.dethread(); mergeBlocks(block, targetBlock, oneBlock(jettisonedBlock)); } else { if (extremeLogging) m_graph.dump(); m_graph.dethread(); ASSERT(block->last()->isTerminal()); CodeOrigin boundaryCodeOrigin = block->last()->codeOrigin; block->last()->convertToPhantom(); ASSERT(block->last()->refCount() == 1); jettisonBlock(block, jettisonedBlock, boundaryCodeOrigin); block->appendNode( m_graph, SpecNone, Jump, boundaryCodeOrigin, OpInfo(targetBlock)); } innerChanged = outerChanged = true; break; } if (block->successor(0) == block->successor(1)) { convertToJump(block, block->successor(0)); innerChanged = outerChanged = true; break; } // Branch to same destination -> jump. // FIXME: this will currently not be hit because of the lack of jump-only // block simplification. break; } case Switch: { SwitchData* data = block->last()->switchData(); // Prune out cases that end up jumping to default. for (unsigned i = 0; i < data->cases.size(); ++i) { if (data->cases[i].target == data->fallThrough) data->cases[i--] = data->cases.takeLast(); } // If there are no cases other than default then this turns // into a jump. if (data->cases.isEmpty()) { convertToJump(block, data->fallThrough); innerChanged = outerChanged = true; break; } // Switch on constant -> jettison all other targets and merge. if (block->last()->child1()->hasConstant()) { JSValue value = m_graph.valueOfJSConstant(block->last()->child1().node()); TriState found = FalseTriState; BasicBlock* targetBlock = 0; for (unsigned i = data->cases.size(); found == FalseTriState && i--;) { found = data->cases[i].value.strictEqual(value); if (found == TrueTriState) targetBlock = data->cases[i].target; } if (found == MixedTriState) break; if (found == FalseTriState) targetBlock = data->fallThrough; ASSERT(targetBlock); Vector<BasicBlock*, 1> jettisonedBlocks; for (unsigned i = block->numSuccessors(); i--;) { BasicBlock* jettisonedBlock = block->successor(i); if (jettisonedBlock != targetBlock) jettisonedBlocks.append(jettisonedBlock); } if (targetBlock->predecessors.size() == 1) { if (extremeLogging) m_graph.dump(); m_graph.dethread(); mergeBlocks(block, targetBlock, jettisonedBlocks); } else { if (extremeLogging) m_graph.dump(); m_graph.dethread(); CodeOrigin boundaryCodeOrigin = block->last()->codeOrigin; block->last()->convertToPhantom(); for (unsigned i = jettisonedBlocks.size(); i--;) jettisonBlock(block, jettisonedBlocks[i], boundaryCodeOrigin); block->appendNode( m_graph, SpecNone, Jump, boundaryCodeOrigin, OpInfo(targetBlock)); } innerChanged = outerChanged = true; break; } } default: break; } } if (innerChanged) { // Here's the reason for this pass: // Blocks: A, B, C, D, E, F // A -> B, C // B -> F // C -> D, E // D -> F // E -> F // // Assume that A's branch is determined to go to B. Then the rest of this phase // is smart enough to simplify down to: // A -> B // B -> F // C -> D, E // D -> F // E -> F // // We will also merge A and B. But then we don't have any other mechanism to // remove D, E as predecessors for F. Worse, the rest of this phase does not // know how to fix the Phi functions of F to ensure that they no longer refer // to variables in D, E. In general, we need a way to handle Phi simplification // upon: // 1) Removal of a predecessor due to branch simplification. The branch // simplifier already does that. // 2) Invalidation of a predecessor because said predecessor was rendered // unreachable. We do this here. // // This implies that when a block is unreachable, we must inspect its // successors' Phi functions to remove any references from them into the // removed block. m_graph.invalidateCFG(); m_graph.resetReachability(); m_graph.killUnreachableBlocks(); } if (Options::validateGraphAtEachPhase()) validate(m_graph); } while (innerChanged); return outerChanged; }
bool run() { const bool extremeLogging = false; bool outerChanged = false; bool innerChanged; do { innerChanged = false; for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) { BasicBlock* block = m_graph.m_blocks[blockIndex].get(); if (!block) continue; ASSERT(block->isReachable); switch (block->last()->op()) { case Jump: { // Successor with one predecessor -> merge. if (m_graph.m_blocks[m_graph.successor(block, 0)]->m_predecessors.size() == 1) { ASSERT(m_graph.m_blocks[m_graph.successor(block, 0)]->m_predecessors[0] == blockIndex); #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) dataLogF("CFGSimplify: Jump merge on Block #%u to Block #%u.\n", blockIndex, m_graph.successor(block, 0)); #endif if (extremeLogging) m_graph.dump(); m_graph.dethread(); mergeBlocks(blockIndex, m_graph.successor(block, 0), NoBlock); innerChanged = outerChanged = true; break; } else { #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) dataLogF("Not jump merging on Block #%u to Block #%u because predecessors = ", blockIndex, m_graph.successor(block, 0)); for (unsigned i = 0; i < m_graph.m_blocks[m_graph.successor(block, 0)]->m_predecessors.size(); ++i) { if (i) dataLogF(", "); dataLogF("#%u", m_graph.m_blocks[m_graph.successor(block, 0)]->m_predecessors[i]); } dataLogF(".\n"); #endif } // FIXME: Block only has a jump -> remove. This is tricky though because of // liveness. What we really want is to slam in a phantom at the end of the // block, after the terminal. But we can't right now. :-( // Idea: what if I slam the ghosties into my successor? Nope, that's // suboptimal, because if my successor has multiple predecessors then we'll // be keeping alive things on other predecessor edges unnecessarily. // What we really need is the notion of end-of-block ghosties! break; } case Branch: { // Branch on constant -> jettison the not-taken block and merge. if (isKnownDirection(block->cfaBranchDirection)) { bool condition = branchCondition(block->cfaBranchDirection); BasicBlock* targetBlock = m_graph.m_blocks[ m_graph.successorForCondition(block, condition)].get(); if (targetBlock->m_predecessors.size() == 1) { #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) dataLogF("CFGSimplify: Known condition (%s) branch merge on Block #%u to Block #%u, jettisoning Block #%u.\n", condition ? "true" : "false", blockIndex, m_graph.successorForCondition(block, condition), m_graph.successorForCondition(block, !condition)); #endif if (extremeLogging) m_graph.dump(); m_graph.dethread(); mergeBlocks( blockIndex, m_graph.successorForCondition(block, condition), m_graph.successorForCondition(block, !condition)); } else { #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) dataLogF("CFGSimplify: Known condition (%s) branch->jump conversion on Block #%u to Block #%u, jettisoning Block #%u.\n", condition ? "true" : "false", blockIndex, m_graph.successorForCondition(block, condition), m_graph.successorForCondition(block, !condition)); #endif if (extremeLogging) m_graph.dump(); m_graph.dethread(); BlockIndex takenBlockIndex = m_graph.successorForCondition(block, condition); BlockIndex notTakenBlockIndex = m_graph.successorForCondition(block, !condition); ASSERT(block->last()->isTerminal()); CodeOrigin boundaryCodeOrigin = block->last()->codeOrigin; block->last()->convertToPhantom(); ASSERT(block->last()->refCount() == 1); jettisonBlock(blockIndex, notTakenBlockIndex, boundaryCodeOrigin); block->appendNode( m_graph, SpecNone, Jump, boundaryCodeOrigin, OpInfo(takenBlockIndex)); } innerChanged = outerChanged = true; break; } if (m_graph.successor(block, 0) == m_graph.successor(block, 1)) { BlockIndex targetBlockIndex = m_graph.successor(block, 0); BasicBlock* targetBlock = m_graph.m_blocks[targetBlockIndex].get(); ASSERT(targetBlock); ASSERT(targetBlock->isReachable); if (targetBlock->m_predecessors.size() == 1) { #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) dataLogF("CFGSimplify: Branch to same successor merge on Block #%u to Block #%u.\n", blockIndex, targetBlockIndex); #endif m_graph.dethread(); mergeBlocks(blockIndex, targetBlockIndex, NoBlock); } else { #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) dataLogF("CFGSimplify: Branch->jump conversion to same successor on Block #%u to Block #%u.\n", blockIndex, targetBlockIndex); #endif Node* branch = block->last(); ASSERT(branch->isTerminal()); ASSERT(branch->op() == Branch); branch->convertToPhantom(); ASSERT(branch->refCount() == 1); block->appendNode( m_graph, SpecNone, Jump, branch->codeOrigin, OpInfo(targetBlockIndex)); } innerChanged = outerChanged = true; break; } #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) dataLogF("Not branch simplifying on Block #%u because the successors differ and the condition is not known.\n", blockIndex); #endif // Branch to same destination -> jump. // FIXME: this will currently not be hit because of the lack of jump-only // block simplification. break; } default: break; } } if (innerChanged) { // Here's the reason for this pass: // Blocks: A, B, C, D, E, F // A -> B, C // B -> F // C -> D, E // D -> F // E -> F // // Assume that A's branch is determined to go to B. Then the rest of this phase // is smart enough to simplify down to: // A -> B // B -> F // C -> D, E // D -> F // E -> F // // We will also merge A and B. But then we don't have any other mechanism to // remove D, E as predecessors for F. Worse, the rest of this phase does not // know how to fix the Phi functions of F to ensure that they no longer refer // to variables in D, E. In general, we need a way to handle Phi simplification // upon: // 1) Removal of a predecessor due to branch simplification. The branch // simplifier already does that. // 2) Invalidation of a predecessor because said predecessor was rendered // unreachable. We do this here. // // This implies that when a block is unreachable, we must inspect its // successors' Phi functions to remove any references from them into the // removed block. m_graph.resetReachability(); for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) { BasicBlock* block = m_graph.m_blocks[blockIndex].get(); if (!block) continue; if (block->isReachable) continue; killUnreachable(blockIndex); } } if (Options::validateGraphAtEachPhase()) validate(m_graph); } while (innerChanged); return outerChanged; }