| 737 | } |
| 738 | |
| 739 | void StackLayoutGenerator::fillInJunk(CFG::BasicBlock const& _block, CFG::FunctionInfo const* _functionInfo) |
| 740 | { |
| 741 | /// Recursively adds junk to the subgraph starting on @a _entry. |
| 742 | /// Since it is only called on cut-vertices, the full subgraph retains proper stack balance. |
| 743 | auto addJunkRecursive = [&](CFG::BasicBlock const* _entry, size_t _numJunk) { |
| 744 | util::BreadthFirstSearch<CFG::BasicBlock const*> breadthFirstSearch{{_entry}}; |
| 745 | breadthFirstSearch.run([&](CFG::BasicBlock const* _block, auto _addChild) { |
| 746 | auto& blockInfo = m_layout.blockInfos.at(_block); |
| 747 | blockInfo.entryLayout = Stack{_numJunk, JunkSlot{}} + std::move(blockInfo.entryLayout); |
| 748 | for (auto const& operation: _block->operations) |
| 749 | { |
| 750 | auto& operationEntryLayout = m_layout.operationEntryLayout.at(&operation); |
| 751 | operationEntryLayout = Stack{_numJunk, JunkSlot{}} + std::move(operationEntryLayout); |
| 752 | } |
| 753 | blockInfo.exitLayout = Stack{_numJunk, JunkSlot{}} + std::move(blockInfo.exitLayout); |
| 754 | |
| 755 | std::visit(util::GenericVisitor{ |
| 756 | [&](CFG::BasicBlock::MainExit const&) {}, |
| 757 | [&](CFG::BasicBlock::Jump const& _jump) |
| 758 | { |
| 759 | _addChild(_jump.target); |
| 760 | }, |
| 761 | [&](CFG::BasicBlock::ConditionalJump const& _conditionalJump) |
| 762 | { |
| 763 | _addChild(_conditionalJump.zero); |
| 764 | _addChild(_conditionalJump.nonZero); |
| 765 | }, |
| 766 | [&](CFG::BasicBlock::FunctionReturn const&) { yulAssert(!simulateFunctionsWithJumps()); }, |
| 767 | [&](CFG::BasicBlock::Terminated const&) {}, |
| 768 | }, _block->exit); |
| 769 | }); |
| 770 | }; |
| 771 | /// @returns the number of operations required to transform @a _source to @a _target. |
| 772 | auto evaluateTransform = [&](Stack _source, Stack const& _target) -> size_t { |
| 773 | size_t opGas = 0; |
| 774 | auto swap = [&](unsigned _swapDepth) |
| 775 | { |
| 776 | if (_swapDepth > reachableStackDepth()) |
| 777 | opGas += 1000; |
| 778 | else |
| 779 | opGas += evmasm::GasMeter::swapGas(_swapDepth, m_evmDialect.evmVersion()); |
| 780 | }; |
| 781 | auto dupOrPush = [&](StackSlot const& _slot) |
| 782 | { |
| 783 | if (canBeFreelyGenerated(_slot)) |
| 784 | opGas += evmasm::GasMeter::runGas(evmasm::pushInstruction(32), m_evmDialect.evmVersion()); |
| 785 | else |
| 786 | { |
| 787 | if (auto depth = util::findOffset(_source | ranges::views::reverse, _slot)) |
| 788 | { |
| 789 | if (*depth < reachableStackDepth()) |
| 790 | opGas += evmasm::GasMeter::dupGas(*depth + 1, m_evmDialect.evmVersion()); |
| 791 | else |
| 792 | opGas += 1000; |
| 793 | } |
| 794 | else |
| 795 | { |
| 796 | // This has to be a previously unassigned return variable. |
nothing calls this directly
no test coverage detected