diff --git a/libevmasm/Assembly.h b/libevmasm/Assembly.h index ad892a6ff..e16023ad9 100644 --- a/libevmasm/Assembly.h +++ b/libevmasm/Assembly.h @@ -73,7 +73,10 @@ public: void appendImmutable(std::string const& _identifier) { append(newPushImmutable(_identifier)); } void appendImmutableAssignment(std::string const& _identifier) { append(newImmutableAssignment(_identifier)); } - void appendVerbatim(bytes const& _data, int _stackDifference) { append(AssemblyItem(_data, _stackDifference)); } + void appendVerbatim(bytes _data, size_t _arguments, size_t _returnVariables) + { + append(AssemblyItem(std::move(_data), _arguments, _returnVariables)); + } AssemblyItem appendJump() { auto ret = append(newPushTag()); append(Instruction::JUMP); return ret; } AssemblyItem appendJumpI() { auto ret = append(newPushTag()); append(Instruction::JUMPI); return ret; } diff --git a/libevmasm/AssemblyItem.cpp b/libevmasm/AssemblyItem.cpp index e37859d98..b4acf6f87 100644 --- a/libevmasm/AssemblyItem.cpp +++ b/libevmasm/AssemblyItem.cpp @@ -92,7 +92,7 @@ size_t AssemblyItem::bytesRequired(size_t _addressLength) const else return 1 + (3 + 32) * 1024; // 1024 occurrences are beyond the maximum code size anyways. case VerbatimBytecode: - return m_verbatimBytecode->second.size(); + return std::get<2>(*m_verbatimBytecode).size(); default: break; } @@ -103,6 +103,8 @@ size_t AssemblyItem::arguments() const { if (type() == Operation) return static_cast(instructionInfo(instruction()).args); + else if (type() == VerbatimBytecode) + return get<0>(*m_verbatimBytecode); else if (type() == AssignImmutable) return 2; else @@ -128,6 +130,8 @@ size_t AssemblyItem::returnValues() const return 1; case Tag: return 0; + case VerbatimBytecode: + return get<1>(*m_verbatimBytecode); default: break; } @@ -244,7 +248,7 @@ string AssemblyItem::toAssemblyText(Assembly const& _assembly) const assertThrow(false, AssemblyException, "Invalid assembly item."); break; case VerbatimBytecode: - text = string("verbatimbytecode_") + util::toHex(m_verbatimBytecode->second); + text = string("verbatimbytecode_") + util::toHex(get<2>(*m_verbatimBytecode)); break; default: assertThrow(false, InvalidOpcode, ""); diff --git a/libevmasm/AssemblyItem.h b/libevmasm/AssemblyItem.h index 31a4627d0..5d810c02c 100644 --- a/libevmasm/AssemblyItem.h +++ b/libevmasm/AssemblyItem.h @@ -77,10 +77,10 @@ public: else m_data = std::make_shared(std::move(_data)); } - explicit AssemblyItem(bytes const& _verbatimData, int _deposit): + explicit AssemblyItem(bytes _verbatimData, size_t _arguments, size_t _returnVariables): m_type(VerbatimBytecode), m_instruction{}, - m_verbatimBytecode{{_deposit, _verbatimData}} + m_verbatimBytecode{{_arguments, _returnVariables, std::move(_verbatimData)}} {} AssemblyItem(AssemblyItem const&) = default; @@ -103,7 +103,7 @@ public: u256 const& data() const { assertThrow(m_type != Operation, util::Exception, ""); return *m_data; } void setData(u256 const& _data) { assertThrow(m_type != Operation, util::Exception, ""); m_data = std::make_shared(_data); } - bytes const& verbatimData() const { assertThrow(m_type == VerbatimBytecode, util::Exception, ""); return m_verbatimBytecode->second; } + bytes const& verbatimData() const { assertThrow(m_type == VerbatimBytecode, util::Exception, ""); return std::get<2>(*m_verbatimBytecode); } /// @returns the instruction of this item (only valid if type() == Operation) Instruction instruction() const { assertThrow(m_type == Operation, util::Exception, ""); return m_instruction; } @@ -151,7 +151,7 @@ public: size_t bytesRequired(size_t _addressLength) const; size_t arguments() const; size_t returnValues() const; - size_t deposit() const { return m_type == VerbatimBytecode ? static_cast(m_verbatimBytecode->first) : returnValues() - arguments(); } + size_t deposit() const { return returnValues() - arguments(); } /// @returns true if the assembly item can be used in a functional context. bool canBeFunctional() const; @@ -176,8 +176,9 @@ private: AssemblyItemType m_type; Instruction m_instruction; ///< Only valid if m_type == Operation std::shared_ptr m_data; ///< Only valid if m_type != Operation - /// If m_type == VerbatimBytecode, this holds stack difference and verbatim bytecode. - std::optional> m_verbatimBytecode; + /// If m_type == VerbatimBytecode, this holds number of arguments, number of + /// return variables and verbatim bytecode. + std::optional> m_verbatimBytecode; langutil::SourceLocation m_location; JumpType m_jumpType = JumpType::Ordinary; /// Pushed value for operations with data to be determined during assembly stage, diff --git a/libevmasm/KnownState.cpp b/libevmasm/KnownState.cpp index ebb36ff35..67445cb75 100644 --- a/libevmasm/KnownState.cpp +++ b/libevmasm/KnownState.cpp @@ -100,6 +100,24 @@ KnownState::StoreOperation KnownState::feedItem(AssemblyItem const& _item, bool feedItem(AssemblyItem(Instruction::POP), _copyItem); return feedItem(AssemblyItem(Instruction::POP), _copyItem); } + else if (_item.type() == VerbatimBytecode) + { + m_sequenceNumber += 2; + resetMemory(); + resetKnownKeccak256Hashes(); + resetStorage(); + // Consume all arguments and place unknown return values on the stack. + m_stackElements.erase( + m_stackElements.upper_bound(m_stackHeight - static_cast(_item.arguments())), + m_stackElements.end() + ); + m_stackHeight += static_cast(_item.deposit()); + for (size_t i = 0; i < _item.returnValues(); ++i) + setStackElement( + m_stackHeight - static_cast(i), + m_expressionClasses->newClass(_item.location()) + ); + } else if (_item.type() != Operation) { assertThrow(_item.deposit() == 1, InvalidDeposit, ""); diff --git a/libyul/backends/evm/AbstractAssembly.h b/libyul/backends/evm/AbstractAssembly.h index de20fb16c..1eb5a3fd8 100644 --- a/libyul/backends/evm/AbstractAssembly.h +++ b/libyul/backends/evm/AbstractAssembly.h @@ -78,7 +78,7 @@ public: virtual void appendLinkerSymbol(std::string const& _name) = 0; /// Append raw bytes that stay untouched by the optimizer. - virtual void appendVerbatim(bytes const& _data, int _stackDifference) = 0; + virtual void appendVerbatim(bytes _data, size_t _arguments, size_t _returnVariables) = 0; /// Append a jump instruction. /// @param _stackDiffAfter the stack adjustment after this instruction. diff --git a/libyul/backends/evm/AsmCodeGen.cpp b/libyul/backends/evm/AsmCodeGen.cpp index 42c97bd6e..fa9122fdc 100644 --- a/libyul/backends/evm/AsmCodeGen.cpp +++ b/libyul/backends/evm/AsmCodeGen.cpp @@ -99,9 +99,9 @@ void EthAssemblyAdapter::appendLinkerSymbol(std::string const& _linkerSymbol) m_assembly.appendLibraryAddress(_linkerSymbol); } -void EthAssemblyAdapter::appendVerbatim(bytes const& _data, int _stackDifference) +void EthAssemblyAdapter::appendVerbatim(bytes _data, size_t _arguments, size_t _returnVariables) { - m_assembly.appendVerbatim(_data, _stackDifference); + m_assembly.appendVerbatim(move(_data), _arguments, _returnVariables); } void EthAssemblyAdapter::appendJump(int _stackDiffAfter, JumpType _jumpType) diff --git a/libyul/backends/evm/AsmCodeGen.h b/libyul/backends/evm/AsmCodeGen.h index f31b44d73..cab2c4003 100644 --- a/libyul/backends/evm/AsmCodeGen.h +++ b/libyul/backends/evm/AsmCodeGen.h @@ -50,7 +50,7 @@ public: size_t newLabelId() override; size_t namedLabel(std::string const& _name) override; void appendLinkerSymbol(std::string const& _linkerSymbol) override; - void appendVerbatim(bytes const& _data, int _stackDifference) override; + void appendVerbatim(bytes _data, size_t _arguments, size_t _returnVariables) override; void appendJump(int _stackDiffAfter, JumpType _jumpType) override; void appendJumpTo(LabelID _labelId, int _stackDiffAfter, JumpType _jumpType) override; void appendJumpToIf(LabelID _labelId, JumpType _jumpType) override; diff --git a/libyul/backends/evm/EVMDialect.cpp b/libyul/backends/evm/EVMDialect.cpp index e67b2f25d..dda28f19e 100644 --- a/libyul/backends/evm/EVMDialect.cpp +++ b/libyul/backends/evm/EVMDialect.cpp @@ -382,8 +382,11 @@ BuiltinFunctionForEVM const* EVMDialect::verbatimFunction(size_t _arguments, siz for (Expression const& arg: _call.arguments | ranges::views::tail | ranges::views::reverse) _visitExpression(arg); Expression const& bytecode = _call.arguments.front(); - int diff = static_cast(_returnVariables) - static_cast(_arguments); - _assembly.appendVerbatim(asBytes(std::get(bytecode).value.str()), diff); + _assembly.appendVerbatim( + asBytes(std::get(bytecode).value.str()), + _arguments, + _returnVariables + ); } ).second; builtinFunction.isMSize = true; diff --git a/libyul/backends/evm/NoOutputAssembly.cpp b/libyul/backends/evm/NoOutputAssembly.cpp index 4b67aba24..50cbf1c78 100644 --- a/libyul/backends/evm/NoOutputAssembly.cpp +++ b/libyul/backends/evm/NoOutputAssembly.cpp @@ -69,9 +69,9 @@ void NoOutputAssembly::appendLinkerSymbol(string const&) yulAssert(false, "Linker symbols not yet implemented."); } -void NoOutputAssembly::appendVerbatim(bytes const&, int _stackDifference) +void NoOutputAssembly::appendVerbatim(bytes, size_t _arguments, size_t _returnVariables) { - m_stackHeight += _stackDifference; + m_stackHeight += static_cast(_returnVariables - _arguments); } void NoOutputAssembly::appendJump(int _stackDiffAfter, JumpType) diff --git a/libyul/backends/evm/NoOutputAssembly.h b/libyul/backends/evm/NoOutputAssembly.h index 4131da622..fbb51a9c6 100644 --- a/libyul/backends/evm/NoOutputAssembly.h +++ b/libyul/backends/evm/NoOutputAssembly.h @@ -58,7 +58,7 @@ public: LabelID newLabelId() override; LabelID namedLabel(std::string const& _name) override; void appendLinkerSymbol(std::string const& _name) override; - void appendVerbatim(bytes const& _data, int _stackDifference) override; + void appendVerbatim(bytes _data, size_t _arguments, size_t _returnVariables) override; void appendJump(int _stackDiffAfter, JumpType _jumpType) override; void appendJumpTo(LabelID _labelId, int _stackDiffAfter, JumpType _jumpType) override; diff --git a/test/cmdlineTests/yul_verbatim_msize/input.yul b/test/cmdlineTests/yul_verbatim_msize/input.yul index ad72cab5b..c9294e258 100644 --- a/test/cmdlineTests/yul_verbatim_msize/input.yul +++ b/test/cmdlineTests/yul_verbatim_msize/input.yul @@ -2,6 +2,6 @@ // The optimizer assumes verbatim could contain msize, // so it cannot optimize the mload away. let x := mload(0x2000) - verbatim_0i_0o("") + verbatim_0i_0o("aa") sstore(0, 2) }