diff --git a/libevmasm/AbstractAssemblyStack.h b/libevmasm/AbstractAssemblyStack.h new file mode 100644 index 000000000..6be78cbc7 --- /dev/null +++ b/libevmasm/AbstractAssemblyStack.h @@ -0,0 +1,54 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +// SPDX-License-Identifier: GPL-3.0 + +#pragma once + +#include + +#include +#include + +#include +#include + +namespace solidity::evmasm +{ + +class AbstractAssemblyStack +{ +public: + virtual ~AbstractAssemblyStack() {} + + virtual LinkerObject const& object(std::string const& _contractName) const = 0; + virtual LinkerObject const& runtimeObject(std::string const& _contractName) const = 0; + + virtual std::string const* sourceMapping(std::string const& _contractName) const = 0; + virtual std::string const* runtimeSourceMapping(std::string const& _contractName) const = 0; + + virtual Json::Value assemblyJSON(std::string const& _contractName) const = 0; + virtual std::string assemblyString(std::string const& _contractName, StringMap const& _sourceCodes) const = 0; + + virtual std::string const filesystemFriendlyName(std::string const& _contractName) const = 0; + + virtual std::vector contractNames() const = 0; + virtual std::vector sourceNames() const = 0; + + virtual bool compilationSuccessful() const = 0; +}; + +} // namespace solidity::evmasm diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index f524aad66..32998f121 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -34,13 +34,15 @@ #include #include -#include +#include +#include #include #include #include #include +#include using namespace solidity; using namespace solidity::evmasm; @@ -73,6 +75,210 @@ unsigned Assembly::codeSize(unsigned subTagSize) const } } +void Assembly::importAssemblyItemsFromJSON(Json::Value const& _code, std::vector const& _sourceList) +{ + solAssert(m_items.empty()); + solRequire(_code.isArray(), AssemblyImportException, "Supplied JSON is not an array."); + for (auto current = std::begin(_code); current != std::end(_code); ++current) + { + auto const& item = m_items.emplace_back(createAssemblyItemFromJSON(*current, _sourceList)); + if (item == Instruction::JUMPDEST) + solThrow(AssemblyImportException, "JUMPDEST instruction without a tag"); + else if (item.type() == AssemblyItemType::Tag) + { + ++current; + if (current != std::end(_code) && createAssemblyItemFromJSON(*current, _sourceList) != Instruction::JUMPDEST) + solThrow(AssemblyImportException, "JUMPDEST expected after tag."); + } + } +} + +AssemblyItem Assembly::createAssemblyItemFromJSON(Json::Value const& _json, std::vector const& _sourceList) +{ + solRequire(_json.isObject(), AssemblyImportException, "Supplied JSON is not an object."); + static std::set const validMembers{"name", "begin", "end", "source", "value", "modifierDepth", "jumpType"}; + for (auto const& member: _json.getMemberNames()) + solRequire( + validMembers.count(member), + AssemblyImportException, + "Unknown member '" + member + "'. Valid members are " + + solidity::util::joinHumanReadable(validMembers, ", ") + "." + ); + solRequire(isOfType(_json["name"]), AssemblyImportException, "Member 'name' missing or not of type string."); + solRequire(isOfTypeIfExists(_json, "begin"), AssemblyImportException, "Optional member 'begin' not of type int."); + solRequire(isOfTypeIfExists(_json, "end"), AssemblyImportException, "Optional member 'end' not of type int."); + solRequire(isOfTypeIfExists(_json, "source"), AssemblyImportException, "Optional member 'source' not of type int."); + solRequire(isOfTypeIfExists(_json, "value"), AssemblyImportException, "Optional member 'value' not of type string."); + solRequire( + isOfTypeIfExists(_json, "modifierDepth"), + AssemblyImportException, + "Optional member 'modifierDepth' not of type int." + ); + solRequire( + isOfTypeIfExists(_json, "jumpType"), + AssemblyImportException, + "Optional member 'jumpType' not of type string." + ); + + std::string name = get(_json["name"]); + solRequire(!name.empty(), AssemblyImportException, "Member 'name' was empty."); + + SourceLocation location; + location.start = get(_json["begin"]); + location.end = get(_json["end"]); + int srcIndex = getOrDefault(_json["source"], -1); + size_t modifierDepth = static_cast(getOrDefault(_json["modifierDepth"], 0)); + std::string value = getOrDefault(_json["value"], ""); + std::string jumpType = getOrDefault(_json["jumpType"], ""); + + auto updateUsedTags = [&](u256 const& data) + { + m_usedTags = std::max(m_usedTags, static_cast(data) + 1); + return data; + }; + + auto storeImmutableHash = [&](std::string const& _immutableName) -> h256 + { + h256 hash(util::keccak256(_immutableName)); + solAssert(m_immutables.count(hash) == 0 || m_immutables[hash] == _immutableName); + m_immutables[hash] = _immutableName; + return hash; + }; + + auto storeLibraryHash = [&](std::string const& _libraryName) -> h256 + { + h256 hash(util::keccak256(_libraryName)); + solAssert(m_libraries.count(hash) == 0 || m_libraries[hash] == _libraryName); + m_libraries[hash] = _libraryName; + return hash; + }; + + auto requireValueDefinedForInstruction = [&](std::string const& _name, std::string const& _value) + { + solRequire( + !_value.empty(), + AssemblyImportException, + "Member 'value' was not defined for instruction '" + _name + "', but the instruction needs a value." + ); + }; + + auto requireValueUndefinedForInstruction = [&](std::string const& _name, std::string const& _value) + { + solRequire( + _value.empty(), + AssemblyImportException, + "Member 'value' defined for instruction '" + _name + "', but the instruction does not need a value." + ); + }; + + solRequire(srcIndex >= -1 && srcIndex < static_cast(_sourceList.size()), AssemblyImportException, "srcIndex out of bound."); + if (srcIndex != -1) + { + static std::map> sharedSourceNames; + if (sharedSourceNames.find(_sourceList[static_cast(srcIndex)]) == sharedSourceNames.end()) + sharedSourceNames[_sourceList[static_cast(srcIndex)]] = std::make_shared(_sourceList[static_cast(srcIndex)]); + location.sourceName = sharedSourceNames[_sourceList[static_cast(srcIndex)]]; + } + + AssemblyItem result(0); + + if (c_instructions.count(name)) + { + AssemblyItem item{c_instructions.at(name), location}; + if (!jumpType.empty()) + { + if (item.instruction() == Instruction::JUMP || item.instruction() == Instruction::JUMPI) + item.setJumpType(jumpType); + else + solThrow( + AssemblyImportException, + "Member 'jumpType' set on instruction different from JUMP or JUMPI (was set on instruction '" + name + "')" + ); + } + requireValueUndefinedForInstruction(name, value); + result = item; + } + else + { + solRequire( + jumpType.empty(), + AssemblyImportException, + "Member 'jumpType' set on instruction different from JUMP or JUMPI (was set on instruction '" + name + "')" + ); + if (name == "PUSH") + { + requireValueDefinedForInstruction(name, value); + result = {AssemblyItemType::Push, u256("0x" + value)}; + } + else if (name == "PUSH [ErrorTag]") + { + requireValueUndefinedForInstruction(name, value); + result = {AssemblyItemType::PushTag, 0}; + } + else if (name == "PUSH [tag]") + { + requireValueDefinedForInstruction(name, value); + result = {AssemblyItemType::PushTag, updateUsedTags(u256(value))}; + } + else if (name == "PUSH [$]") + { + requireValueDefinedForInstruction(name, value); + result = {AssemblyItemType::PushSub, u256("0x" + value)}; + } + else if (name == "PUSH #[$]") + { + requireValueDefinedForInstruction(name, value); + result = {AssemblyItemType::PushSubSize, u256("0x" + value)}; + } + else if (name == "PUSHSIZE") + { + requireValueUndefinedForInstruction(name, value); + result = {AssemblyItemType::PushProgramSize, 0}; + } + else if (name == "PUSHLIB") + { + requireValueDefinedForInstruction(name, value); + result = {AssemblyItemType::PushLibraryAddress, storeLibraryHash(value)}; + } + else if (name == "PUSHDEPLOYADDRESS") + { + requireValueUndefinedForInstruction(name, value); + result = {AssemblyItemType::PushDeployTimeAddress, 0}; + } + else if (name == "PUSHIMMUTABLE") + { + requireValueDefinedForInstruction(name, value); + result = {AssemblyItemType::PushImmutable, storeImmutableHash(value)}; + } + else if (name == "ASSIGNIMMUTABLE") + { + requireValueDefinedForInstruction(name, value); + result = {AssemblyItemType::AssignImmutable, storeImmutableHash(value)}; + } + else if (name == "tag") + { + requireValueDefinedForInstruction(name, value); + result = {AssemblyItemType::Tag, updateUsedTags(u256(value))}; + } + else if (name == "PUSH data") + { + requireValueDefinedForInstruction(name, value); + result = {AssemblyItemType::PushData, u256("0x" + value)}; + } + else if (name == "VERBATIM") + { + requireValueDefinedForInstruction(name, value); + AssemblyItem item(fromHex(value), 0, 0); + result = item; + } + else + solThrow(InvalidOpcode, "Invalid opcode: " + name); + } + result.setLocation(location); + result.m_modifierDepth = modifierDepth; + return result; +} + namespace { @@ -221,7 +427,7 @@ std::string Assembly::assemblyString( return tmp.str(); } -Json::Value Assembly::assemblyJSON(std::map const& _sourceIndices, bool _includeSourceList) const +Json::Value Assembly::assemblyJSON(std::vector const& _sources, bool _includeSourceList) const { Json::Value root; root[".code"] = Json::arrayValue; @@ -230,11 +436,12 @@ Json::Value Assembly::assemblyJSON(std::map const& _sourc { int sourceIndex = -1; if (item.location().sourceName) - { - auto iter = _sourceIndices.find(*item.location().sourceName); - if (iter != _sourceIndices.end()) - sourceIndex = static_cast(iter->second); - } + for (size_t index = 0; index < _sources.size(); ++index) + if (_sources[index] == *item.location().sourceName) + { + sourceIndex = static_cast(index); + break; + } auto [name, data] = item.nameAndData(m_evmVersion); Json::Value jsonItem; @@ -267,12 +474,12 @@ Json::Value Assembly::assemblyJSON(std::map const& _sourc code.append(std::move(jumpdest)); } } - if (_includeSourceList) + if (!_sources.empty() && _includeSourceList) { root["sourceList"] = Json::arrayValue; Json::Value& jsonSourceList = root["sourceList"]; - for (auto const& [name, index]: _sourceIndices) - jsonSourceList[index] = name; + for (int index = 0; index < static_cast(_sources.size()); ++index) + jsonSourceList[index] = _sources[static_cast(index)]; } if (!m_data.empty() || !m_subs.empty()) @@ -287,7 +494,8 @@ Json::Value Assembly::assemblyJSON(std::map const& _sourc { std::stringstream hexStr; hexStr << std::hex << i; - data[hexStr.str()] = m_subs[i]->assemblyJSON(_sourceIndices, /*_includeSourceList = */false); + data[hexStr.str()] = m_subs[i]->assemblyJSON(_sources, false); + data[hexStr.str()]["index"] = static_cast(i); } } @@ -297,6 +505,130 @@ Json::Value Assembly::assemblyJSON(std::map const& _sourc return root; } +std::pair, std::vector> Assembly::fromJSON(Json::Value const& _json, std::vector const& _sourceList, int _level) +{ + solRequire(_json.isObject(), AssemblyImportException, "Supplied JSON is not an object."); + static std::set const validMembers{".code", ".data", ".auxdata", "sourceList", "index"}; + for (auto const& attribute: _json.getMemberNames()) + solRequire(validMembers.count(attribute), AssemblyImportException, "Unknown attribute '" + attribute + "'."); + solRequire(_json.isMember(".code"), AssemblyImportException, "Member '.code' does not exist."); + solRequire(_json[".code"].isArray(), AssemblyImportException, "Member '.code' is not an array."); + for (auto const& codeItem: _json[".code"]) + solRequire(codeItem.isObject(), AssemblyImportException, "Item of '.code' array is not an object."); + + if (_level == 0) + { + if (_json.isMember("sourceList")) + { + solRequire(_json["sourceList"].isArray(), AssemblyImportException, "Optional member 'sourceList' is not an array."); + for (auto const& sourceListItem: _json["sourceList"]) + solRequire(sourceListItem.isString(), AssemblyImportException, "Item of 'sourceList' array is not of type string."); + } + } else + solRequire( + !_json.isMember("sourceList"), + AssemblyImportException, + "Member 'sourceList' is only allowed in root JSON object." + ); + + std::shared_ptr result = std::make_shared(langutil::EVMVersion(), _level == 0, ""); + std::vector sourceList; + if (_json.isMember("sourceList")) + { + solAssert(_level == 0); + for (auto const& it: _json["sourceList"]) + { + solRequire( + std::find(sourceList.begin(), sourceList.end(), it.asString()) == sourceList.end(), + AssemblyImportException, + "Items in 'sourceList' array are not unique." + ); + sourceList.emplace_back(it.asString()); + } + } else + sourceList = _sourceList; + + result->importAssemblyItemsFromJSON(_json[".code"], sourceList); + if (_json[".auxdata"]) + { + solRequire(_json[".auxdata"].isString(), AssemblyImportException, "Optional member '.auxdata' is not of type string."); + bytes auxdata{fromHex(_json[".auxdata"].asString())}; + solRequire(!auxdata.empty(), AssemblyImportException, "Optional member '.auxdata' is not a valid hexadecimal string."); + result->m_auxiliaryData = auxdata; + } + + if (_json.isMember(".data")) + { + solRequire(_json[".data"].isObject(), AssemblyImportException, "Optional member '.data' is not an object."); + Json::Value const& data = _json[".data"]; + for (Json::ValueConstIterator dataIter = data.begin(); dataIter != data.end(); dataIter++) + { + solRequire(dataIter.key().isString(), AssemblyImportException, "Key inside '.data' is not of type string."); + std::string dataItemID = dataIter.key().asString(); + Json::Value const& code = data[dataItemID]; + if (code.isString()) + { + if (!code.asString().empty()) + { + bytes data_value{fromHex(code.asString())}; + solRequire( + !data_value.empty(), + AssemblyImportException, + "Member '.data' contains a value for '" + dataItemID + "' that is not a valid hexadecimal string."); + } + result->m_data[h256(fromHex(dataItemID))] = fromHex(code.asString()); + } + else if (code.isObject()) + { + solAssert(code.isMember("index")); + size_t index = static_cast(code["index"].asInt()); + if (result->m_subs.size() <= index) + result->m_subs.resize(index + 1); + std::shared_ptr subassembly(Assembly::fromJSON(code, sourceList, _level + 1).first); + solAssert(subassembly); + result->m_subs[index] = subassembly; + } + else + solThrow(AssemblyImportException, "Key inside '.data' '" + dataItemID + "' can only be a valid hex-string or an object."); + } + } + if (_level == 0) + result->updatePaths(); + return std::make_pair(result, sourceList); +} + +void Assembly::updatePaths(std::vector const& _parents, std::vector const& _absolutePathFromRoot) +{ + size_t subId = 0; + for (auto& assembly: this->m_subs) + { + std::vector parents{_parents}; + parents.push_back(this); + + std::vector absolutePathFromRoot{_absolutePathFromRoot}; + absolutePathFromRoot.emplace_back(subId); + + int pindex = 0; + for (auto& parent: parents) + { + if (pindex == 0) + parent->encodeSubPath(absolutePathFromRoot); + else + { + std::vector relativePath{absolutePathFromRoot}; + for (int i = 0; i < pindex; ++i) + relativePath.erase(relativePath.begin()); + parent->encodeSubPath(relativePath); + } + ++pindex; + } + + assembly->updatePaths(parents, absolutePathFromRoot); + + ++subId; + } +} + AssemblyItem Assembly::namedTag(std::string const& _name, size_t _params, size_t _returns, std::optional _sourceID) { assertThrow(!_name.empty(), AssemblyException, "Empty named tag."); diff --git a/libevmasm/Assembly.h b/libevmasm/Assembly.h index bd37b3a7f..12459b7da 100644 --- a/libevmasm/Assembly.h +++ b/libevmasm/Assembly.h @@ -150,10 +150,18 @@ public: ) const; /// Create a JSON representation of the assembly. - Json::Value assemblyJSON( - std::map const& _sourceIndices = std::map(), - bool _includeSourceList = true - ) const; + Json::Value assemblyJSON(std::vector const& _sources, bool _includeSourceList = true) const; + + /// Loads the JSON representation of assembly. + /// @param _json JSON object containing assembly in the format produced by assemblyJSON(). + /// @param _sourceList list of source names (used to supply the source-list from the root-assembly object to sub-assemblies). + /// @param _level this function might be called recursively, _level reflects the nesting level. + /// @returns Resulting Assembly object loaded from given json. + static std::pair, std::vector> fromJSON( + Json::Value const& _json, + std::vector const& _sourceList = {}, + int _level = 0 + ); /// Mark this assembly as invalid. Calling ``assemble`` on it will throw. void markAsInvalid() { m_invalid = true; } @@ -171,11 +179,25 @@ protected: unsigned codeSize(unsigned subTagSize) const; + /// Add all assembly items from given JSON array. This function imports the items by iterating through + /// the code array. This method only works on clean Assembly objects that don't have any items defined yet. + /// @param _json JSON array that contains assembly items (e.g. json['.code']) + /// @param _sourceList list of source names. + void importAssemblyItemsFromJSON(Json::Value const& _code, std::vector const& _sourceList); + + /// Creates an AssemblyItem from a given JSON representation. + /// @param _json JSON object that consists a single assembly item + /// @param _sourceList list of source names. + /// @returns AssemblyItem of _json argument. + AssemblyItem createAssemblyItemFromJSON(Json::Value const& _json, std::vector const& _sourceList); + private: bool m_invalid = false; Assembly const* subAssemblyById(size_t _subId) const; + void updatePaths(std::vector const& _parents = {}, std::vector const& _absolutePathFromRoot = {}); + protected: /// 0 is reserved for exception unsigned m_usedTags = 1; @@ -217,7 +239,6 @@ protected: /// Internal name of the assembly object, only used with the Yul backend /// currently std::string m_name; - langutil::SourceLocation m_currentSourceLocation; public: diff --git a/libevmasm/AssemblyItem.cpp b/libevmasm/AssemblyItem.cpp index 6c2b673c6..120f12a25 100644 --- a/libevmasm/AssemblyItem.cpp +++ b/libevmasm/AssemblyItem.cpp @@ -247,6 +247,18 @@ std::string AssemblyItem::getJumpTypeAsString() const } } +void AssemblyItem::setJumpType(std::string const& _jumpType) +{ + if (_jumpType == "[in]") + m_jumpType = JumpType::IntoFunction; + else if (_jumpType == "[out]") + m_jumpType = JumpType::OutOfFunction; + else if (_jumpType.empty()) + m_jumpType = JumpType::Ordinary; + else + solThrow(AssemblyImportException, "Invalid jump type."); +} + std::string AssemblyItem::toAssemblyText(Assembly const& _assembly) const { std::string text; diff --git a/libevmasm/AssemblyItem.h b/libevmasm/AssemblyItem.h index 077c1912d..742a011a4 100644 --- a/libevmasm/AssemblyItem.h +++ b/libevmasm/AssemblyItem.h @@ -174,6 +174,7 @@ public: langutil::SourceLocation const& location() const { return m_location; } void setJumpType(JumpType _jumpType) { m_jumpType = _jumpType; } + void setJumpType(std::string const& _jumpType); JumpType getJumpType() const { return m_jumpType; } std::string getJumpTypeAsString() const; diff --git a/libevmasm/CMakeLists.txt b/libevmasm/CMakeLists.txt index 6563b2c0f..c1918540e 100644 --- a/libevmasm/CMakeLists.txt +++ b/libevmasm/CMakeLists.txt @@ -1,8 +1,11 @@ set(sources + AbstractAssemblyStack.h Assembly.cpp Assembly.h AssemblyItem.cpp AssemblyItem.h + EVMAssemblyStack.cpp + EVMAssemblyStack.h BlockDeduplicator.cpp BlockDeduplicator.h CommonSubexpressionEliminator.cpp diff --git a/libevmasm/EVMAssemblyStack.cpp b/libevmasm/EVMAssemblyStack.cpp new file mode 100644 index 000000000..ea19226f3 --- /dev/null +++ b/libevmasm/EVMAssemblyStack.cpp @@ -0,0 +1,126 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +// SPDX-License-Identifier: GPL-3.0 + +#include + +#include +#include +#include + +using namespace solidity::util; +using namespace solidity::langutil; +using namespace solidity::frontend; + +namespace solidity::evmasm +{ + +void EVMAssemblyStack::parseAndAnalyze(std::string const& _sourceName, std::string const& _source) +{ + solAssert(!m_evmAssembly); + m_name = _sourceName; + solRequire(jsonParseStrict(_source, m_json), AssemblyImportException, "Could not parse JSON file."); + auto result = evmasm::Assembly::fromJSON(m_json); + m_evmAssembly = result.first; + m_sourceList = result.second; + solRequire(m_evmAssembly != nullptr, AssemblyImportException, "Could not create evm assembly object."); +} + +void EVMAssemblyStack::assemble() +{ + solAssert(m_evmAssembly); + solAssert(m_evmAssembly->isCreation()); + solAssert(!m_evmRuntimeAssembly); + + m_object = m_evmAssembly->assemble(); + m_sourceMapping = AssemblyItem::computeSourceMapping(m_evmAssembly->items(), sourceIndices()); + if (m_evmAssembly->numSubs() > 0) + { + m_evmRuntimeAssembly = std::make_shared(m_evmAssembly->sub(0)); + solAssert(m_evmRuntimeAssembly && !m_evmRuntimeAssembly->isCreation()); + m_runtimeSourceMapping = AssemblyItem::computeSourceMapping(m_evmRuntimeAssembly->items(), sourceIndices()); + m_runtimeObject = m_evmRuntimeAssembly->assemble(); + } +} + +LinkerObject const& EVMAssemblyStack::object(std::string const& _contractName) const +{ + solAssert(_contractName == m_name); + return m_object; +} + +LinkerObject const& EVMAssemblyStack::runtimeObject(std::string const& _contractName) const +{ + solAssert(_contractName == m_name); + return m_runtimeObject; +} + +std::map EVMAssemblyStack::sourceIndices() const +{ + solAssert(m_evmAssembly); + std::map indices; + unsigned index = 0; + for (auto const& s: m_sourceList) + if (s != CompilerContext::yulUtilityFileName()) + indices[s] = index++; + + if (indices.find(CompilerContext::yulUtilityFileName()) == indices.end()) + indices[CompilerContext::yulUtilityFileName()] = index++; + return indices; +} + +std::string const* EVMAssemblyStack::sourceMapping(std::string const& _contractName) const +{ + solAssert(_contractName == m_name); + return &m_sourceMapping; +} + +std::string const* EVMAssemblyStack::runtimeSourceMapping(std::string const& _contractName) const +{ + solAssert(_contractName == m_name); + return &m_runtimeSourceMapping; +} + +Json::Value EVMAssemblyStack::assemblyJSON(std::string const& _contractName) const +{ + solAssert(_contractName == m_name); + solAssert(m_evmAssembly); + std::vector sources = sourceNames(); + if (find(sources.begin(), sources.end(), CompilerContext::yulUtilityFileName()) == sources.end()) + sources.emplace_back(CompilerContext::yulUtilityFileName()); + return m_evmAssembly->assemblyJSON(sources); +} + +std::string EVMAssemblyStack::assemblyString(std::string const& _contractName, StringMap const& _sourceCodes) const +{ + solAssert(_contractName == m_name); + solAssert(m_evmAssembly); + return m_evmAssembly->assemblyString(m_debugInfoSelection, _sourceCodes); +} + +std::string const EVMAssemblyStack::filesystemFriendlyName(std::string const& _contractName) const +{ + solAssert(_contractName == m_name); + return m_name; +} + +std::vector EVMAssemblyStack::sourceNames() const +{ + return m_sourceList; +} + +} // namespace solidity::evmasm diff --git a/libevmasm/EVMAssemblyStack.h b/libevmasm/EVMAssemblyStack.h new file mode 100644 index 000000000..3f5b5d178 --- /dev/null +++ b/libevmasm/EVMAssemblyStack.h @@ -0,0 +1,86 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +// SPDX-License-Identifier: GPL-3.0 + +#pragma once + +#include +#include +#include + +#include + +#include +#include + +namespace solidity::evmasm +{ + +class EVMAssemblyStack: public AbstractAssemblyStack +{ +public: + explicit EVMAssemblyStack(langutil::EVMVersion _evmVersion): m_evmVersion(_evmVersion) {} + + /// Runs parsing and analysis steps. + /// Multiple calls overwrite the previous state. + /// @throws AssemblyImportException, if JSON could not be validated. + void parseAndAnalyze(std::string const& _sourceName, std::string const& _source); + + void assemble(); + + std::string const& name() const { return m_name; } + + virtual LinkerObject const& object(std::string const& _contractName) const override; + virtual LinkerObject const& runtimeObject(std::string const& _contractName) const override; + + std::shared_ptr const& evmAssembly() const { return m_evmAssembly; } + std::shared_ptr const& evmRuntimeAssembly() const { return m_evmRuntimeAssembly; } + + virtual std::string const* sourceMapping(std::string const& _contractName) const override; + virtual std::string const* runtimeSourceMapping(std::string const& _contractName) const override; + + virtual Json::Value assemblyJSON(std::string const& _contractName) const override; + virtual std::string assemblyString(std::string const& _contractName, StringMap const& _sourceCodes) const override; + + virtual std::string const filesystemFriendlyName(std::string const& _contractName) const override; + + virtual std::vector contractNames() const override { return {m_name}; } + virtual std::vector sourceNames() const override; + std::map sourceIndices() const; + + virtual bool compilationSuccessful() const override { return m_evmAssembly != nullptr; } + + void selectDebugInfo(langutil::DebugInfoSelection _debugInfoSelection) + { + m_debugInfoSelection = _debugInfoSelection; + } + +private: + langutil::EVMVersion m_evmVersion; + std::string m_name; + Json::Value m_json; + std::shared_ptr m_evmAssembly; + std::shared_ptr m_evmRuntimeAssembly; + evmasm::LinkerObject m_object; ///< Deployment object (includes the runtime sub-object). + evmasm::LinkerObject m_runtimeObject; ///< Runtime object. + std::vector m_sourceList; + langutil::DebugInfoSelection m_debugInfoSelection = langutil::DebugInfoSelection::Default(); + std::string m_sourceMapping; + std::string m_runtimeSourceMapping; +}; + +} // namespace solidity::evmasm diff --git a/libevmasm/Exceptions.h b/libevmasm/Exceptions.h index 027577576..ae6d1bf9c 100644 --- a/libevmasm/Exceptions.h +++ b/libevmasm/Exceptions.h @@ -28,6 +28,7 @@ namespace solidity::evmasm { struct AssemblyException: virtual util::Exception {}; +struct AssemblyImportException: virtual AssemblyException {}; struct OptimizerException: virtual AssemblyException {}; struct StackTooDeepException: virtual OptimizerException {}; struct ItemNotAvailableException: virtual OptimizerException {}; diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index 44413afdf..eea8450d9 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -74,7 +74,6 @@ #include #include -#include #include #include @@ -702,6 +701,7 @@ bool CompilerStack::isRequestedContract(ContractDefinition const& _contract) con bool CompilerStack::compile(State _stopAfter) { + solAssert(m_compilationSourceType != CompilationSourceType::EvmAssemblyJSON); m_stopAfter = _stopAfter; if (m_stackState < AnalysisSuccessful) if (!parseAndAnalyze(_stopAfter)) @@ -986,7 +986,12 @@ Json::Value CompilerStack::assemblyJSON(std::string const& _contractName) const Contract const& currentContract = contract(_contractName); if (currentContract.evmAssembly) - return currentContract.evmAssembly->assemblyJSON(sourceIndices()); + { + std::vector sources = sourceNames(); + if (find(sources.begin(), sources.end(), CompilerContext::yulUtilityFileName()) == sources.end()) + sources.emplace_back(CompilerContext::yulUtilityFileName()); + return currentContract.evmAssembly->assemblyJSON(sources); + } else return Json::Value(); } @@ -1001,9 +1006,11 @@ std::map CompilerStack::sourceIndices() const std::map indices; unsigned index = 0; for (auto const& s: m_sources) - indices[s.first] = index++; - solAssert(!indices.count(CompilerContext::yulUtilityFileName()), ""); - indices[CompilerContext::yulUtilityFileName()] = index++; + if (s.first != CompilerContext::yulUtilityFileName()) + indices[s.first] = index++; + + if (indices.find(CompilerContext::yulUtilityFileName()) == indices.end()) + indices[CompilerContext::yulUtilityFileName()] = index++; return indices; } @@ -1611,6 +1618,11 @@ std::string CompilerStack::createMetadata(Contract const& _contract, bool _forIR case CompilationSourceType::SolidityAST: sourceType = "SolidityAST"; break; + case CompilationSourceType::EvmAssemblyJSON: + sourceType = "EvmAssemblyJson"; + break; + default: + solAssert(false); } meta["language"] = sourceType; meta["compiler"]["version"] = VersionStringStrict; diff --git a/libsolidity/interface/CompilerStack.h b/libsolidity/interface/CompilerStack.h index 06c78b686..8c684076a 100644 --- a/libsolidity/interface/CompilerStack.h +++ b/libsolidity/interface/CompilerStack.h @@ -41,6 +41,7 @@ #include #include +#include #include #include @@ -91,7 +92,7 @@ class Analysis; * It holds state and can be used to either step through the compilation stages (and abort e.g. * before compilation to bytecode) or run the whole compilation in one call. */ -class CompilerStack: public langutil::CharStreamProvider +class CompilerStack: public langutil::CharStreamProvider, public evmasm::AbstractAssemblyStack { public: /// Noncopyable. @@ -123,7 +124,9 @@ public: /// Regular compilation from Solidity source files. Solidity, /// Compilation from an imported Solidity AST. - SolidityAST + SolidityAST, + /// Compilation from an imported EVM Assembly JSON. + EvmAssemblyJSON }; /// Creates a new compiler stack. @@ -139,6 +142,8 @@ public: /// @returns the current state. State state() const { return m_stackState; } + virtual bool compilationSuccessful() const override { return m_stackState >= CompilationSuccessful; } + /// Resets the compiler to an empty state. Unless @a _keepSettings is set to true, /// all settings are reset as well. void reset(bool _keepSettings = false); @@ -234,7 +239,7 @@ public: bool compile(State _stopAfter = State::CompilationSuccessful); /// @returns the list of sources (paths) used - std::vector sourceNames() const; + virtual std::vector sourceNames() const override; /// @returns a mapping assigning each source name its index inside the vector returned /// by sourceNames(). @@ -255,13 +260,13 @@ public: std::vector const& unhandledSMTLib2Queries() const { return m_unhandledSMTLib2Queries; } /// @returns a list of the contract names in the sources. - std::vector contractNames() const; + virtual std::vector contractNames() const override; /// @returns the name of the last contract. If _sourceName is defined the last contract of that source will be returned. std::string const lastContractName(std::optional const& _sourceName = std::nullopt) const; /// @returns either the contract's name or a mixture of its name and source file, sanitized for filesystem use - std::string const filesystemFriendlyName(std::string const& _contractName) const; + virtual std::string const filesystemFriendlyName(std::string const& _contractName) const override; /// @returns the IR representation of a contract. std::string const& yulIR(std::string const& _contractName) const; @@ -276,10 +281,10 @@ public: Json::Value const& yulIROptimizedAst(std::string const& _contractName) const; /// @returns the assembled object for a contract. - evmasm::LinkerObject const& object(std::string const& _contractName) const; + virtual evmasm::LinkerObject const& object(std::string const& _contractName) const override; /// @returns the runtime object for the contract. - evmasm::LinkerObject const& runtimeObject(std::string const& _contractName) const; + virtual evmasm::LinkerObject const& runtimeObject(std::string const& _contractName) const override; /// @returns normal contract assembly items evmasm::AssemblyItems const* assemblyItems(std::string const& _contractName) const; @@ -293,21 +298,21 @@ public: /// @returns the string that provides a mapping between bytecode and sourcecode or a nullptr /// if the contract does not (yet) have bytecode. - std::string const* sourceMapping(std::string const& _contractName) const; + virtual std::string const* sourceMapping(std::string const& _contractName) const override; /// @returns the string that provides a mapping between runtime bytecode and sourcecode. /// if the contract does not (yet) have bytecode. - std::string const* runtimeSourceMapping(std::string const& _contractName) const; + virtual std::string const* runtimeSourceMapping(std::string const& _contractName) const override; /// @return a verbose text representation of the assembly. /// @arg _sourceCodes is the map of input files to source code strings /// Prerequisite: Successful compilation. - std::string assemblyString(std::string const& _contractName, StringMap const& _sourceCodes = StringMap()) const; + virtual std::string assemblyString(std::string const& _contractName, StringMap const& _sourceCodes = StringMap()) const override; /// @returns a JSON representation of the assembly. /// @arg _sourceCodes is the map of input files to source code strings /// Prerequisite: Successful compilation. - Json::Value assemblyJSON(std::string const& _contractName) const; + virtual Json::Value assemblyJSON(std::string const& _contractName) const override; /// @returns a JSON representing the contract ABI. /// Prerequisite: Successful call to parse or compile. diff --git a/scripts/ASTImportTest.sh b/scripts/ASTImportTest.sh index c24526195..65a9e9901 100755 --- a/scripts/ASTImportTest.sh +++ b/scripts/ASTImportTest.sh @@ -23,13 +23,30 @@ # ast import/export tests: # - first exporting a .sol file to JSON, then loading it into the compiler # and exporting it again. The second JSON should be identical to the first. +# +# evm-assembly import/export tests: +# - first a .sol file will be exported to a combined json file, containing outputs +# for "asm" "bin" "bin-runtime" "opcodes" "srcmap" and "srcmap-runtime" (expected output). +# The "asm" output will then be used as import, where its output "bin" "bin-runtime" +# "opcodes" "srcmap" "srcmap-runtime" (obtained output) will be compared with the expected output. +# The expected output needs to be identical with the obtained output. +# +# Additionally to this, the direct import/export is tested by importing an +# evm-assembly json with --import-asm-json and directly exporting it again with +# --asm-json using the same solc invocation. The original asm json file used for the +# import and the resulting exported asm json file need to be identical. set -euo pipefail -READLINK=readlink -if [[ "$OSTYPE" == "darwin"* ]]; then - READLINK=greadlink +READLINK="readlink" +if [[ "${OSTYPE}" == "darwin"* ]]; then + READLINK="greadlink" fi +EXPR="expr" +if [[ "${OSTYPE}" == "darwin"* ]]; then + EXPR="gexpr" +fi + REPO_ROOT=$(${READLINK} -f "$(dirname "$0")"/..) SOLIDITY_BUILD_DIR=${SOLIDITY_BUILD_DIR:-${REPO_ROOT}/build} SOLC="${SOLIDITY_BUILD_DIR}/solc/solc" @@ -40,7 +57,7 @@ source "${REPO_ROOT}/scripts/common.sh" function print_usage { - echo "Usage: ${0} ast [--exit-on-error|--help]." + echo "Usage: ${0} ast|evm-assembly [--exit-on-error|--help]." } function print_used_commands @@ -48,6 +65,7 @@ function print_used_commands local test_directory="$1" local export_command="$2" local import_command="$3" + echo printError "You can find the files used for this test here: ${test_directory}" printError "Used commands for test:" printError "# export" @@ -61,34 +79,38 @@ function print_stderr_stdout local error_message="$1" local stderr_file="$2" local stdout_file="$3" - printError "$error_message" + printError "${error_message}" printError "" printError "stderr:" - cat "$stderr_file" >&2 + cat "${stderr_file}" >&2 printError "" printError "stdout:" - cat "$stdout_file" >&2 + cat "${stdout_file}" >&2 } function check_import_test_type_unset { - [[ -z "$IMPORT_TEST_TYPE" ]] || fail "ERROR: Import test type can only be set once. Aborting." + [[ -z "${IMPORT_TEST_TYPE}" ]] || fail "ERROR: Import test type can only be set once. Aborting." } IMPORT_TEST_TYPE= EXIT_ON_ERROR=0 for PARAM in "$@" do - case "$PARAM" in + case "${PARAM}" in ast) check_import_test_type_unset ; IMPORT_TEST_TYPE="ast" ;; + evm-assembly) check_import_test_type_unset ; IMPORT_TEST_TYPE="evm-assembly" ;; --help) print_usage ; exit 0 ;; --exit-on-error) EXIT_ON_ERROR=1 ;; - *) fail "Unknown option '$PARAM'. Aborting. $(print_usage)" ;; + *) fail "Unknown option '${PARAM}'. Aborting. $(print_usage || true)" ;; esac done SYNTAXTESTS_DIR="${REPO_ROOT}/test/libsolidity/syntaxTests" ASTJSONTESTS_DIR="${REPO_ROOT}/test/libsolidity/ASTJSON" +SEMANTICTESTS_DIR="${REPO_ROOT}/test/libsolidity/semanticTests" +YULTESTS_DIR="${REPO_ROOT}/test/libyul" + FAILED=0 UNCOMPILABLE=0 @@ -153,6 +175,281 @@ function test_ast_import_export_equivalence TESTED=$((TESTED + 1)) } +function split_combined_json +{ + local json_file="$1" + local output_path="$2" + local prefix="${3:-}" + for path_with_contract in $(jq '.contracts | keys | .[]' "${json_file}" 2> /dev/null) + do + local path=${path_with_contract} + local contract="" + local delimiter + delimiter=$("${EXPR}" index "${path}" ":") || true + if [[ -z "${prefix}" ]] + then + path=${path_with_contract:0:((${delimiter} - 1))} + contract=${path_with_contract:((${delimiter})):((${#path_with_contract} - ${delimiter} - 1))} + else + path=${path_with_contract} + contract="" + fi + for type in $(jq --raw-output ".contracts.${path_with_contract} | keys | .[]" "${json_file}" 2> /dev/null) + do + local output + output=$(jq --raw-output ".contracts.${path_with_contract}.\"${type}\"" "${json_file}") + if [[ -n "${output}" ]] + then + echo "${output}" > "${output_path}/${prefix}${contract}.${type}" + fi + done + done + rm "${json_file}" +} + +function run_solc +{ + local parameters=( "${@}" ) + + if ! "${SOLC}" "${parameters[@]}" > /dev/null 2> solc_stderr + then + printError "ERROR: ${parameters[*]}" + printError "${PWD}" + local SOLC_STDERR + SOLC_STDERR=$(cat "solc_stderr") + printError "${SOLC_STDERR}" + exit 1 + fi + rm -f solc_stderr + + return 0 +} + +function run_solc_store_stdout +{ + local output_file=$1 + local parameters=( "${@:2}" ) + + if ! "${SOLC}" "${parameters[@]}" > "${output_file}" 2> "${output_file}.error" + then + printError "ERROR: ${parameters[*]}" + printError "${PWD}" + local SOLC_STDERR + SOLC_STDERR=$(cat "${output_file}.error") + printError "${SOLC_STDERR}" + exit 1 + fi + rm -f "${output_file}.error" + + return 0 +} + +function test_evmjson_via_ir_and_yul_import_export +{ + local sol_file="$1" + local input_files=( "${@:2}" ) + + mkdir yul + # export found solidity contracts to yul. + run_solc --optimize --via-ir --ir-optimized "${input_files[@]}" --no-optimize-yul -o yul/ + for filename in yul/* + do + if [[ -s "${filename}" ]] + then + # remove '_opt' part of '_opt.yul' + mv "${filename}" "${filename/_opt/}" + else + # if file was empty, delete it. + rm -f "${filename}" + fi + done + + local export_command + local import_command + + mkdir sol + # create from a combined json from the supplied solidity contracts. + export_command=("${SOLC}" --combined-json "bin,bin-runtime,opcodes,asm,srcmap,srcmap-runtime" --optimize --via-ir --pretty-json --json-indent 4 --no-optimize-yul "${input_files[@]}" -o sol/) + run_solc --combined-json "bin,bin-runtime,opcodes,asm,srcmap,srcmap-runtime" --optimize --via-ir --pretty-json --json-indent 4 "${input_files[@]}" --no-optimize-yul -o sol/ + mkdir input + + # save the original supplied solidity contract sources for potential debugging purposes. + for file in "${input_files[@]}" + do + cat "${file}" >> "input/$(basename "${file}")" + done + # split the combined json into different files. + split_combined_json sol/combined.json sol/ + + # iterate through all yul files. + for yulfile in yul/* + do + # take the yul file and export it as evm assembly json. save the result in "$yulfile.asm.json". + run_solc_store_stdout "${yulfile}.asm.json" --strict-assembly "${yulfile}" --optimize --asm-json --pretty-json --json-indent 4 --no-optimize-yul + # remove the lines containing '=======', so that we just have a nice json file. + grep -v '^=======' "${yulfile}.asm.json" > tmpfile && mv tmpfile "${yulfile}.asm.json" + # import_command will just contain the last file in yul/*.asm - but it's still a good starting point ;) + import_command=("${SOLC}" --combined-json "bin,bin-runtime,opcodes,asm,srcmap,srcmap-runtime" --pretty-json --json-indent 4 --import-asm-json "${yulfile}.asm.json") + # import the created evm assembly json file and create a combined json out of it. + run_solc_store_stdout "${yulfile}.combined.json" --combined-json "bin,bin-runtime,opcodes,asm,srcmap,srcmap-runtime" --pretty-json --json-indent 4 --import-asm-json "${yulfile}.asm.json" + # split the combined json into different files. + split_combined_json "${yulfile}.combined.json" . "${yulfile}" + done + + # now iterate over all files in the sol/ output folder. + # the files stored here will normally look like e.g. "sol/C.asm", "sol/C.bin" + # they were generated by the split_combined_json call above and contain the contract + # name and the type (e.g. bin,bin-runtime,opcodes,asm,srcmap,srcmap-runtime) in the + # file-name. + for file in sol/* + do + local type + local delimiter + local yul + + # first just remove all path parts from the file and put it in the type. + # - "sol/C.asm" -> "C.asm" + type="$(basename "${file}")" + + # delimiter is just the position of that dot that is delimiting the contract + # name from it's type. + delimiter=$("${EXPR}" index "${type}" ".") + + # extract the type: for e.g. "C.asm" -> type will be "asm". + type=${type:((${delimiter})):((${#type} - ${delimiter}))} + + # now we want to know which is the corresponding yul file, that should have exactly + # the same content. e.g. file="sol/C.srcmap-runtime" -> yul="yul/C.yul.srcmap-runtime" + yul=${file/sol/yul} + yul=${yul/${type}/yul.${type}} + + # remember that we first exported the yul file from solidity contract files. + # then we generated and split the corresponding combined-json of that exported yul file. + # we also generated and split another combined-json file from the original + # solidity contract files. if the yul export to asm evm json and it's re-import + # will lead to the same content of the combined-json of the original solidity file, + # the yul export to asm evm json and it's reimport seem to work correctly. + + # we can ignore "asm" and "json" files here. "asm" is the exported evm asm json. + # between the yul and the sol assembly jsons we may have some subtile differences, + # e.g. in the source-lists. + # however, if the yul/sol outputs of e.g. bin,bin-runtime,opcodes,srcmap,srcmap-runtime + # is matching, we consider that the reimport was done correctly. + if [[ "${type}" == "asm" ]] || [[ "${type}" == "json" ]] + then + continue + fi + + # compare the files. e.g. "sol/C.srcmap-runtime" with "yul/C.yul.srcmap-runtime" + if ! diff_files "${file}" "${yul}" > diff_error + then + local diff_error + diff_error=$(cat diff_error) + printError "ERROR: diff failed ${file} ${yul}:\n ${diff_error}" + if (( EXIT_ON_ERROR == 1 )) + then + print_used_commands "${PWD}" "${export_command[*]}" "${import_command[*]}" + exit 1 + fi + return 1 + fi + done + + rm -rf sol + rm -rf yul + rm -rf input + + return 0 +} + +function test_evmjson_sol_import_export +{ + local sol_file="$1" + local input_files=( "${@:2}" ) + + mkdir -p sol + # create from a combined json from the supplied solidity contracts. + local export_command + local import_command + export_command=("${SOLC}" --combined-json "bin,bin-runtime,opcodes,asm,srcmap,srcmap-runtime" --pretty-json --json-indent 4 "${input_files[@]}" -o sol/) + + run_solc --combined-json "bin,bin-runtime,opcodes,asm,srcmap,srcmap-runtime" --pretty-json --json-indent 4 "${input_files[@]}" -o sol/ + mkdir input + # save the original supplied solidity contract sources for potential debugging purposes. + for file in "${input_files[@]}" + do + cat "${file}" >> "input/$(basename "${file}")" + done + # split the combined json into different files. + split_combined_json sol/combined.json sol/ + + mkdir -p imported-from-sol + for file in sol/*.asm + do + name=$(basename "${file}" .asm) + # import_command will just contain the last file in sol/*.asm - but it's still a good starting point ;) + import_command=("${SOLC}" --import-ast --combined-json "bin,bin-runtime,opcodes,asm,srcmap,srcmap-runtime" --pretty-json --json-indent 4 --import-asm-json "${file}") + run_solc_store_stdout "imported-from-sol/combined.json" --combined-json "bin,bin-runtime,opcodes,asm,srcmap,srcmap-runtime" --pretty-json --json-indent 4 --import-asm-json "${file}" + split_combined_json imported-from-sol/combined.json imported-from-sol/ "${name}" + done + + for file in sol/* + do + local imported + imported=${file/sol/imported-from-sol} + if ! diff_files "${file}" "${imported}" > diff_error + then + local diff_error + diff_error=$(cat diff_error) + printError "ERROR: diff failed ${file} ${imported}:\n ${diff_error}" + if (( EXIT_ON_ERROR == 1 )) + then + print_used_commands "${PWD}" "${export_command[*]}" "${import_command[*]}" + exit 1 + fi + return 1 + fi + done + + rm -rf sol + rm -rf imported-from-sol + rm -rf input + + return 0 +} + +function test_evmjson_import_export_equivalence +{ + local sol_file="$1" + local input_files=( "${@:2}" ) + local success=1 + + # export sol to yul. generate artefacts from sol and convert yul to asm json. + # import the yul asm json and check whether the sol artefacts are the same as for yul. + if ! test_evmjson_via_ir_and_yul_import_export "${sol_file}" "${input_files[@]}" + then + success=0 + fi + + # only run the next test-step, if the previous test was run correctly. + if (( success == 1 )) + then + # generate artefacts from sol. export sol to asm json. import that asm json and + # check whether the sol artefacts are the same as created by the asm json import. + if ! test_evmjson_sol_import_export "${sol_file}" "${input_files[@]}" + then + success=0 + fi + fi + + if (( success == 1 )) + then + TESTED=$((TESTED + 1)) + else + FAILED=$((FAILED + 1)) + fi +} + # function tests whether exporting and importing again is equivalent. # Results are recorded by incrementing the FAILED or UNCOMPILABLE global variable. # Also, in case of a mismatch a diff is printed @@ -166,21 +463,23 @@ function test_import_export_equivalence { local solc_return_code local compile_test - case "$IMPORT_TEST_TYPE" in + case "${IMPORT_TEST_TYPE}" in ast) compile_test="--ast-compact-json" ;; + evm-assembly) compile_test="--bin" ;; *) assertFail "Unknown import test type '${IMPORT_TEST_TYPE}'. Aborting." ;; esac set +e - output=$("$SOLC" "${compile_test}" "${input_files[@]}" 2>&1) + output=$("${SOLC}" "${compile_test}" "${input_files[@]}" 2>&1) solc_return_code=$? set -e # if input files where compilable with success if (( solc_return_code == 0 )) then - case "$IMPORT_TEST_TYPE" in + case "${IMPORT_TEST_TYPE}" in ast) test_ast_import_export_equivalence "${sol_file}" "${input_files[@]}" ;; + evm-assembly) test_evmjson_import_export_equivalence "${sol_file}" "${input_files[@]}" ;; *) assertFail "Unknown import test type '${IMPORT_TEST_TYPE}'. Aborting." ;; esac else @@ -191,70 +490,163 @@ function test_import_export_equivalence { # and print some details about the corresponding solc invocation. if (( solc_return_code == 2 )) then - fail "\n\nERROR: Uncaught Exception while executing '$SOLC ${compile_test} ${input_files[*]}':\n${output}\n" + # For the evm-assembly import/export tests, this script uses only the + # old code generator. Some semantic test can only be compiled with + # --via-ir (some need to be additionally compiled with --optimize). + # The tests that are meant to be compiled with --via-ir are throwing + # an UnimplementedFeatureError exception (e.g. Copying of type struct C.S + # memory[] memory to storage not yet supported, Copying nested calldata + # dynamic arrays to storage is not implemented in the old code generator.) + # We will just ignore these kind of exceptions for now. + # However, any other exception will be treated as a fatal error and the + # script execution will be terminated with an error. + if [[ "${output}" != *"UnimplementedFeatureError"* ]] + then + fail "\n\nERROR: Uncaught Exception while executing '${SOLC} ${compile_test} ${input_files[*]}':\n${output}\n" + fi fi fi } -WORKINGDIR=$PWD +function test_evmjson_import_from_yul_export +{ + local files="${*}" + for yulfile in $files + do + local export_command + local import_command + echo -n "·" -command_available "$SOLC" --version + # create a temporary sub-directory + FILETMP=$(mktemp -d) + cd "${FILETMP}" + + set +e + output=$("${SOLC}" "--strict-assembly" "${yulfile}" "--bin" "--optimize" 2>/dev/null) + solc_return_code=$? + set -e + + # if yul file got compiled with success. + if (( solc_return_code == 0 )) + then + yul_bin="$(basename "$yulfile").bin" + yul_json="$(basename "$yulfile").asm.json" + echo "$output" > "${yul_bin}" + # remove all lines starting with '=======' and 'Binary representation:'. + grep -v -e '^=======' -e '^Binary representation:' "${yul_bin}" > tmpfile && mv tmpfile "${yul_bin}" + # remove all white-spaces. we only want the binary. + tr -d '[:space:]' < "${yul_bin}" > tmpfile && mv tmpfile "${yul_bin}" + # only compare bytecode, if bytecode got generated. + if [[ -s "${yul_bin}" ]] + then + # take the yul file and export it as evm assembly json. save the result in "$yul_json". + export_command=("${SOLC}" --strict-assembly "${yulfile}" --optimize --asm-json --pretty-json --json-indent 4) + run_solc_store_stdout "${yul_json}" --strict-assembly "${yulfile}" --optimize --asm-json --pretty-json --json-indent 4 + # remove the lines containing '=======', so that we just have a nice json file. + grep -v '^=======' "${yul_json}" > tmpfile && mv tmpfile "${yul_json}" + + # import the created evm assembly json file and create a combined json out of it. + import_command=("${SOLC}" --combined-json "bin" --pretty-json --json-indent 4 --import-asm-json "${yul_json}") + run_solc_store_stdout "${yul_json}.combined.json" --combined-json "bin" --pretty-json --json-indent 4 --import-asm-json "${yul_json}" + # split the combined json into different files. + split_combined_json "${yul_json}.combined.json" . "compiled" + tr -d '[:space:]' < "compiled.bin" > tmpfile && mv tmpfile "compiled.bin" + + if ! diff_files compiled.bin "${yul_bin}" > diff_error + then + diff_error=$(cat diff_error) + printError "ERROR: diff failed ${yulfile}:\n ${diff_error}" + if (( EXIT_ON_ERROR == 1 )) + then + print_used_commands "${PWD}" "${export_command[*]}" "${import_command[*]}" + exit 1 + fi + FAILED=$((FAILED + 1)) + else + TESTED=$((TESTED + 1)) + fi + fi + fi + cd "${WORKINGDIR}" + # Delete temporary files + rm -rf "${FILETMP}" + done + echo +} + +WORKINGDIR=${PWD} + +command_available "${SOLC}" --version command_available jq --version +command_available "${EXPR}" --version +command_available "${READLINK}" --version -case "$IMPORT_TEST_TYPE" in +case "${IMPORT_TEST_TYPE}" in ast) TEST_DIRS=("${SYNTAXTESTS_DIR}" "${ASTJSONTESTS_DIR}") ;; - *) assertFail "Import test type not defined. $(print_usage)" ;; + evm-assembly) TEST_DIRS=("${SEMANTICTESTS_DIR}") ;; + *) assertFail "Import test type not defined. $(print_usage || true)}" ;; esac +YUL_NSOURCES=0 +if [[ "${IMPORT_TEST_TYPE}" == "evm-assembly" ]] +then + IMPORT_TEST_FILES=$(find "${YULTESTS_DIR}" -name "*.yul") + YUL_NSOURCES="$(echo "${IMPORT_TEST_FILES}" | wc -l)" + echo "Looking at ${YUL_NSOURCES} .yul files..." + test_evmjson_import_from_yul_export "${IMPORT_TEST_FILES[@]}" +fi + # boost_filesystem_bug specifically tests a local fix for a boost::filesystem # bug. Since the test involves a malformed path, there is no point in running # tests on it. See https://github.com/boostorg/filesystem/issues/176 IMPORT_TEST_FILES=$(find "${TEST_DIRS[@]}" -name "*.sol" -and -not -name "boost_filesystem_bug.sol" -not -path "*/experimental/*") -NSOURCES="$(echo "${IMPORT_TEST_FILES}" | wc -l)" -echo "Looking at ${NSOURCES} .sol files..." +SOL_NSOURCES="$(echo "${IMPORT_TEST_FILES}" | wc -l)" +echo "Looking at ${SOL_NSOURCES} .sol files..." -for solfile in $IMPORT_TEST_FILES +NSOURCES=$(( YUL_NSOURCES + SOL_NSOURCES )) + +for solfile in ${IMPORT_TEST_FILES} do echo -n "·" # create a temporary sub-directory FILETMP=$(mktemp -d) - cd "$FILETMP" + cd "${FILETMP}" set +e - OUTPUT=$("$SPLITSOURCES" "$solfile") + OUTPUT=$("${SPLITSOURCES}" "${solfile}") SPLITSOURCES_RC=$? set -e if (( SPLITSOURCES_RC == 0 )) then - IFS=' ' read -ra OUTPUT_ARRAY <<< "$OUTPUT" - test_import_export_equivalence "$solfile" "${OUTPUT_ARRAY[@]}" + IFS=' ' read -ra OUTPUT_ARRAY <<< "${OUTPUT}" + test_import_export_equivalence "${solfile}" "${OUTPUT_ARRAY[@]}" elif (( SPLITSOURCES_RC == 1 )) then - test_import_export_equivalence "$solfile" "$solfile" + test_import_export_equivalence "${solfile}" "${solfile}" elif (( SPLITSOURCES_RC == 2 )) then # The script will exit with return code 2, if an UnicodeDecodeError occurred. # This is the case if e.g. some tests are using invalid utf-8 sequences. We will ignore # these errors, but print the actual output of the script. printError "\n\n${OUTPUT}\n\n" - test_import_export_equivalence "$solfile" "$solfile" + test_import_export_equivalence "${solfile}" "${solfile}" else # All other return codes will be treated as critical errors. The script will exit. printError "\n\nGot unexpected return code ${SPLITSOURCES_RC} from '${SPLITSOURCES} ${solfile}'. Aborting." printError "\n\n${OUTPUT}\n\n" - cd "$WORKINGDIR" + cd "${WORKINGDIR}" # Delete temporary files - rm -rf "$FILETMP" + rm -rf "${FILETMP}" exit 1 fi - cd "$WORKINGDIR" + cd "${WORKINGDIR}" # Delete temporary files - rm -rf "$FILETMP" + rm -rf "${FILETMP}" done echo diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index c729e4591..c69c2e54a 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -92,6 +92,7 @@ namespace std::set const CompilerInputModes{ frontend::InputMode::Compiler, frontend::InputMode::CompilerWithASTImport, + frontend::InputMode::EVMAssemblerJSON }; } // anonymous namespace @@ -166,42 +167,77 @@ static bool coloredOutput(CommandLineOptions const& _options) (_options.formatting.coloredOutput.has_value() && _options.formatting.coloredOutput.value()); } +void CommandLineInterface::handleEVMAssembly(std::string const& _contract) +{ + solAssert(m_assemblyStack); + solAssert(CompilerInputModes.count(m_options.input.mode) == 1); + + if (m_options.compiler.outputs.asm_ || m_options.compiler.outputs.asmJson) + { + std::string assembly; + if (m_options.compiler.outputs.asmJson) + assembly = util::jsonPrint(removeNullMembers(m_assemblyStack->assemblyJSON(_contract)), m_options.formatting.json); + else + assembly = m_assemblyStack->assemblyString(_contract, m_fileReader.sourceUnits()); + + if (!m_options.output.dir.empty()) + createFile( + m_compiler->filesystemFriendlyName(_contract) + + (m_options.compiler.outputs.asmJson ? "_evm.json" : ".evm"), + assembly + ); + else + sout() << "EVM assembly:" << std::endl << assembly << std::endl; + } +} + void CommandLineInterface::handleBinary(std::string const& _contract) { + solAssert(m_assemblyStack); solAssert(CompilerInputModes.count(m_options.input.mode) == 1); + std::string binary; + std::string binaryRuntime; + if (m_options.compiler.outputs.binary) + binary = objectWithLinkRefsHex(m_assemblyStack->object(_contract)); + if (m_options.compiler.outputs.binaryRuntime) + binaryRuntime = objectWithLinkRefsHex(m_assemblyStack->runtimeObject(_contract)); + if (m_options.compiler.outputs.binary) { if (!m_options.output.dir.empty()) - createFile(m_compiler->filesystemFriendlyName(_contract) + ".bin", objectWithLinkRefsHex(m_compiler->object(_contract))); + createFile(m_assemblyStack->filesystemFriendlyName(_contract) + ".bin", binary); else { sout() << "Binary:" << std::endl; - sout() << objectWithLinkRefsHex(m_compiler->object(_contract)) << std::endl; + sout() << binary << std::endl; } } if (m_options.compiler.outputs.binaryRuntime) { if (!m_options.output.dir.empty()) - createFile(m_compiler->filesystemFriendlyName(_contract) + ".bin-runtime", objectWithLinkRefsHex(m_compiler->runtimeObject(_contract))); + createFile(m_assemblyStack->filesystemFriendlyName(_contract) + ".bin-runtime", binaryRuntime); else { sout() << "Binary of the runtime part:" << std::endl; - sout() << objectWithLinkRefsHex(m_compiler->runtimeObject(_contract)) << std::endl; + sout() << binaryRuntime << std::endl; } } } void CommandLineInterface::handleOpcode(std::string const& _contract) { + solAssert(m_assemblyStack); solAssert(CompilerInputModes.count(m_options.input.mode) == 1); + std::string opcodes{evmasm::disassemble(m_assemblyStack->object(_contract).bytecode, m_options.output.evmVersion)}; + if (!m_options.output.dir.empty()) - createFile(m_compiler->filesystemFriendlyName(_contract) + ".opcode", evmasm::disassemble(m_compiler->object(_contract).bytecode, m_options.output.evmVersion)); + createFile(m_assemblyStack->filesystemFriendlyName(_contract) + ".opcode", opcodes); else { sout() << "Opcodes:" << std::endl; - sout() << std::uppercase << evmasm::disassemble(m_compiler->object(_contract).bytecode, m_options.output.evmVersion); + sout() << std::uppercase << opcodes; sout() << std::endl; } } @@ -701,6 +737,12 @@ void CommandLineInterface::processInput() compile(); outputCompilationResults(); break; + case InputMode::EVMAssemblerJSON: + assembleFromEvmAssemblyJson(); + handleCombinedJSON(); + handleBytecode(m_assemblyStack->contractNames().front()); + handleEVMAssembly(m_assemblyStack->contractNames().front()); + break; } } @@ -717,11 +759,38 @@ void CommandLineInterface::printLicense() sout() << licenseText << std::endl; } +void CommandLineInterface::assembleFromEvmAssemblyJson() +{ + solAssert(m_options.input.mode == InputMode::EVMAssemblerJSON); + solAssert(!m_assemblyStack); + solAssert(!m_evmAssemblyStack && !m_compiler); + std::unique_ptr evmAssemblyStack; + solAssert(m_fileReader.sourceUnits().size() == 1); + auto&& [sourceUnitName, source] = *m_fileReader.sourceUnits().begin(); + try + { + evmAssemblyStack = std::make_unique(m_options.output.evmVersion); + evmAssemblyStack->parseAndAnalyze(sourceUnitName, source); + if (m_options.output.debugInfoSelection.has_value()) + evmAssemblyStack->selectDebugInfo(m_options.output.debugInfoSelection.value()); + evmAssemblyStack->assemble(); + m_evmAssemblyStack = std::move(evmAssemblyStack); + m_assemblyStack = m_evmAssemblyStack.get(); + } + catch (evmasm::AssemblyImportException const& _exception) + { + solThrow(CommandLineExecutionError, "Assembly Import Error: "s + _exception.what()); + } +} + void CommandLineInterface::compile() { solAssert(CompilerInputModes.count(m_options.input.mode) == 1); + solAssert(!m_assemblyStack); + solAssert(!m_evmAssemblyStack && !m_compiler); m_compiler = std::make_unique(m_universalCallback.callback()); + m_assemblyStack = m_compiler.get(); SourceReferenceFormatter formatter(serr(false), *m_compiler, coloredOutput(m_options), m_options.formatting.withErrorIds); @@ -831,6 +900,7 @@ void CommandLineInterface::compile() void CommandLineInterface::handleCombinedJSON() { + solAssert(m_assemblyStack); solAssert(CompilerInputModes.count(m_options.input.mode) == 1); if (!m_options.compiler.combinedJsonRequests.has_value()) @@ -839,63 +909,59 @@ void CommandLineInterface::handleCombinedJSON() Json::Value output(Json::objectValue); output[g_strVersion] = frontend::VersionString; - std::vector contracts = m_compiler->contractNames(); - - // NOTE: The state checks here are more strict that in Standard JSON. There we allow - // requesting certain outputs even if compilation fails as long as analysis went ok. - bool compilationSuccess = m_compiler->state() >= CompilerStack::State::CompilationSuccessful; + std::vector contracts = m_assemblyStack->contractNames(); if (!contracts.empty()) output[g_strContracts] = Json::Value(Json::objectValue); for (std::string const& contractName: contracts) { Json::Value& contractData = output[g_strContracts][contractName] = Json::objectValue; - if (m_options.compiler.combinedJsonRequests->abi && compilationSuccess) + if (m_options.compiler.combinedJsonRequests->abi && m_compiler->compilationSuccessful()) contractData[g_strAbi] = m_compiler->contractABI(contractName); - if (m_options.compiler.combinedJsonRequests->metadata && compilationSuccess) + if (m_options.compiler.combinedJsonRequests->metadata && m_compiler->compilationSuccessful()) contractData["metadata"] = m_compiler->metadata(contractName); - if (m_options.compiler.combinedJsonRequests->binary && compilationSuccess) - contractData[g_strBinary] = m_compiler->object(contractName).toHex(); - if (m_options.compiler.combinedJsonRequests->binaryRuntime && compilationSuccess) - contractData[g_strBinaryRuntime] = m_compiler->runtimeObject(contractName).toHex(); - if (m_options.compiler.combinedJsonRequests->opcodes && compilationSuccess) - contractData[g_strOpcodes] = evmasm::disassemble(m_compiler->object(contractName).bytecode, m_options.output.evmVersion); - if (m_options.compiler.combinedJsonRequests->asm_ && compilationSuccess) - contractData[g_strAsm] = m_compiler->assemblyJSON(contractName); - if (m_options.compiler.combinedJsonRequests->storageLayout && compilationSuccess) + if (m_options.compiler.combinedJsonRequests->binary && m_assemblyStack->compilationSuccessful()) + contractData[g_strBinary] = m_assemblyStack->object(contractName).toHex(); + if (m_options.compiler.combinedJsonRequests->binaryRuntime && m_assemblyStack->compilationSuccessful()) + contractData[g_strBinaryRuntime] = m_assemblyStack->runtimeObject(contractName).toHex(); + if (m_options.compiler.combinedJsonRequests->opcodes && m_assemblyStack->compilationSuccessful()) + contractData[g_strOpcodes] = evmasm::disassemble(m_assemblyStack->object(contractName).bytecode, m_options.output.evmVersion); + if (m_options.compiler.combinedJsonRequests->asm_ && m_assemblyStack->compilationSuccessful()) + contractData[g_strAsm] = m_assemblyStack->assemblyJSON(contractName); + + if (m_options.compiler.combinedJsonRequests->storageLayout && m_compiler->compilationSuccessful()) contractData[g_strStorageLayout] = m_compiler->storageLayout(contractName); - if (m_options.compiler.combinedJsonRequests->generatedSources && compilationSuccess) + if (m_options.compiler.combinedJsonRequests->generatedSources && m_compiler->compilationSuccessful()) contractData[g_strGeneratedSources] = m_compiler->generatedSources(contractName, false); - if (m_options.compiler.combinedJsonRequests->generatedSourcesRuntime && compilationSuccess) + if (m_options.compiler.combinedJsonRequests->generatedSourcesRuntime && m_compiler->compilationSuccessful()) contractData[g_strGeneratedSourcesRuntime] = m_compiler->generatedSources(contractName, true); - if (m_options.compiler.combinedJsonRequests->srcMap && compilationSuccess) + if (m_options.compiler.combinedJsonRequests->srcMap && m_assemblyStack->compilationSuccessful()) { - auto map = m_compiler->sourceMapping(contractName); + auto map = m_assemblyStack->sourceMapping(contractName); contractData[g_strSrcMap] = map ? *map : ""; } - if (m_options.compiler.combinedJsonRequests->srcMapRuntime && compilationSuccess) + if (m_options.compiler.combinedJsonRequests->srcMapRuntime && m_assemblyStack->compilationSuccessful()) { - auto map = m_compiler->runtimeSourceMapping(contractName); + auto map = m_assemblyStack->runtimeSourceMapping(contractName); contractData[g_strSrcMapRuntime] = map ? *map : ""; } - if (m_options.compiler.combinedJsonRequests->funDebug && compilationSuccess) + if (m_options.compiler.combinedJsonRequests->funDebug && m_assemblyStack->compilationSuccessful()) contractData[g_strFunDebug] = StandardCompiler::formatFunctionDebugData( - m_compiler->object(contractName).functionDebugData + m_assemblyStack->object(contractName).functionDebugData ); - if (m_options.compiler.combinedJsonRequests->funDebugRuntime && compilationSuccess) + if (m_options.compiler.combinedJsonRequests->funDebugRuntime && m_assemblyStack->compilationSuccessful()) contractData[g_strFunDebugRuntime] = StandardCompiler::formatFunctionDebugData( - m_compiler->runtimeObject(contractName).functionDebugData + m_assemblyStack->runtimeObject(contractName).functionDebugData ); - if (m_options.compiler.combinedJsonRequests->signatureHashes && compilationSuccess) + if (m_options.compiler.combinedJsonRequests->signatureHashes && m_compiler->compilationSuccessful()) contractData[g_strSignatureHashes] = m_compiler->interfaceSymbols(contractName)["methods"]; - if (m_options.compiler.combinedJsonRequests->natspecDev && compilationSuccess) + if (m_options.compiler.combinedJsonRequests->natspecDev && m_compiler->compilationSuccessful()) contractData[g_strNatspecDev] = m_compiler->natspecDev(contractName); - if (m_options.compiler.combinedJsonRequests->natspecUser && compilationSuccess) + if (m_options.compiler.combinedJsonRequests->natspecUser && m_compiler->compilationSuccessful()) contractData[g_strNatspecUser] = m_compiler->natspecUser(contractName); } - bool needsSourceList = - m_options.compiler.combinedJsonRequests->ast || + bool needsSourceList = m_options.compiler.combinedJsonRequests->ast || m_options.compiler.combinedJsonRequests->srcMap || m_options.compiler.combinedJsonRequests->srcMapRuntime; if (needsSourceList) @@ -903,7 +969,7 @@ void CommandLineInterface::handleCombinedJSON() // Indices into this array are used to abbreviate source names in source locations. output[g_strSourceList] = Json::Value(Json::arrayValue); - for (auto const& source: m_compiler->sourceNames()) + for (auto const& source: m_assemblyStack->sourceNames()) output[g_strSourceList].append(source); } @@ -1152,6 +1218,55 @@ void CommandLineInterface::assembleYul(yul::YulStack::Language _language, yul::Y else serr() << "No text representation found." << std::endl; } + + if (m_options.compiler.outputs.asmJson) + { + std::shared_ptr assembly{stack.assembleEVMWithDeployed().first}; + if (assembly) + { + std::function(yul::Object const&)> collectSourceIndices = + [&](yul::Object const& _object) -> std::map { + std::map sourceIndices; + if (_object.debugData && _object.debugData->sourceNames.has_value()) + for (auto const& iter: *_object.debugData->sourceNames) + sourceIndices[*iter.second] = iter.first; + for (auto const& sub: _object.subObjects) + { + auto subObject = dynamic_cast(sub.get()); + if (subObject) + for (auto const& [name, index]: collectSourceIndices(*subObject)) + sourceIndices[name] = index; + } + return sourceIndices; + }; + if (stack.parserResult() && stack.parserResult()->debugData) + { + std::map sourceIndices = collectSourceIndices(*stack.parserResult()); + // if sourceIndices are empty here, there were no source locations annotated in the yul source. + // in this case, we just add the filename of the yul file itself here. + if (sourceIndices.empty()) + sourceIndices[src.first] = 0; + size_t max_index = 0; + for (auto const& [name, index]: sourceIndices) + if (max_index < index) + max_index = index; + std::vector sourceList(max_index + 1); + uint32_t counter{0}; + for (auto& source: sourceList) + source = "unknown-source-" + std::to_string(counter++); + for (auto const& [name, index]: sourceIndices) + sourceList[index] = name; + sout() << util::jsonPrint( + removeNullMembers( + assembly->assemblyJSON(sourceList) + ), + m_options.formatting.json + ) << std::endl; + return; + } + } + serr() << "Could not create Assembly JSON representation." << std::endl; + } } } @@ -1177,20 +1292,7 @@ void CommandLineInterface::outputCompilationResults() if (needsHumanTargetedStdout(m_options)) sout() << std::endl << "======= " << contract << " =======" << std::endl; - // do we need EVM assembly? - if (m_options.compiler.outputs.asm_ || m_options.compiler.outputs.asmJson) - { - std::string ret; - if (m_options.compiler.outputs.asmJson) - ret = util::jsonPrint(removeNullMembers(m_compiler->assemblyJSON(contract)), m_options.formatting.json); - else - ret = m_compiler->assemblyString(contract, m_fileReader.sourceUnits()); - - if (!m_options.output.dir.empty()) - createFile(m_compiler->filesystemFriendlyName(contract) + (m_options.compiler.outputs.asmJson ? "_evm.json" : ".evm"), ret); - else - sout() << "EVM assembly:" << std::endl << ret << std::endl; - } + handleEVMAssembly(contract); if (m_options.compiler.estimateGas) handleGasEstimation(contract); diff --git a/solc/CommandLineInterface.h b/solc/CommandLineInterface.h index 5de69270b..81a6259be 100644 --- a/solc/CommandLineInterface.h +++ b/solc/CommandLineInterface.h @@ -24,6 +24,7 @@ #include +#include #include #include #include @@ -84,6 +85,7 @@ private: void printVersion(); void printLicense(); void compile(); + void assembleFromEvmAssemblyJson(); void serveLSP(); void link(); void writeLinkedFiles(); @@ -98,6 +100,7 @@ private: void handleCombinedJSON(); void handleAst(); + void handleEVMAssembly(std::string const& _contract); void handleBinary(std::string const& _contract); void handleOpcode(std::string const& _contract); void handleIR(std::string const& _contract); @@ -145,6 +148,8 @@ private: UniversalCallback m_universalCallback{m_fileReader, m_solverCommand}; std::optional m_standardJsonInput; std::unique_ptr m_compiler; + std::unique_ptr m_evmAssemblyStack; + evmasm::AbstractAssemblyStack* m_assemblyStack = nullptr; CommandLineOptions m_options; }; diff --git a/solc/CommandLineParser.cpp b/solc/CommandLineParser.cpp index 53f481ae8..56f78d280 100644 --- a/solc/CommandLineParser.cpp +++ b/solc/CommandLineParser.cpp @@ -30,6 +30,8 @@ #include #include +#include + using namespace solidity::langutil; namespace po = boost::program_options; @@ -50,6 +52,7 @@ static std::string const g_strExperimentalViaIR = "experimental-via-ir"; static std::string const g_strGas = "gas"; static std::string const g_strHelp = "help"; static std::string const g_strImportAst = "import-ast"; +static std::string const g_strImportEvmAssemblerJson = "import-asm-json"; static std::string const g_strInputFile = "input-file"; static std::string const g_strYul = "yul"; static std::string const g_strYulDialect = "yul-dialect"; @@ -140,6 +143,7 @@ static std::map const g_inputModeName = { {InputMode::StandardJson, "standard JSON"}, {InputMode::Linker, "linker"}, {InputMode::LanguageServer, "language server (LSP)"}, + {InputMode::EVMAssemblerJSON, "EVM assembler (JSON format)"}, }; void CommandLineParser::checkMutuallyExclusive(std::vector const& _optionNames) @@ -465,8 +469,15 @@ void CommandLineParser::parseOutputSelection() CompilerOutputs::componentName(&CompilerOutputs::binary), CompilerOutputs::componentName(&CompilerOutputs::irOptimized), CompilerOutputs::componentName(&CompilerOutputs::astCompactJson), + CompilerOutputs::componentName(&CompilerOutputs::asmJson), + }; + static std::set const evmAssemblyJsonImportModeOutputs = { + CompilerOutputs::componentName(&CompilerOutputs::asm_), + CompilerOutputs::componentName(&CompilerOutputs::binary), + CompilerOutputs::componentName(&CompilerOutputs::binaryRuntime), + CompilerOutputs::componentName(&CompilerOutputs::opcodes), + CompilerOutputs::componentName(&CompilerOutputs::asmJson), }; - switch (_mode) { case InputMode::Help: @@ -477,6 +488,8 @@ void CommandLineParser::parseOutputSelection() case InputMode::Compiler: case InputMode::CompilerWithASTImport: return util::contains(compilerModeOutputs, _outputName); + case InputMode::EVMAssemblerJSON: + return util::contains(evmAssemblyJsonImportModeOutputs, _outputName); case InputMode::Assembler: return util::contains(assemblerModeOutputs, _outputName); case InputMode::StandardJson: @@ -657,6 +670,10 @@ General Information)").c_str(), "Supported Inputs is the output of the --" + g_strStandardJSON + " or the one produced by " "--" + g_strCombinedJson + " " + CombinedJsonRequests::componentName(&CombinedJsonRequests::ast)).c_str() ) + ( + g_strImportEvmAssemblerJson.c_str(), + "Import EVM assembly from JSON. Assumes input is in the format used by --asm-json." + ) ( g_strLSP.c_str(), "Switch to language server mode (\"LSP\"). Allows the compiler to be used as an analysis backend " @@ -925,6 +942,7 @@ void CommandLineParser::processArgs() g_strYul, g_strImportAst, g_strLSP, + g_strImportEvmAssemblerJson, }); if (m_args.count(g_strHelp) > 0) @@ -943,6 +961,8 @@ void CommandLineParser::processArgs() m_options.input.mode = InputMode::Linker; else if (m_args.count(g_strImportAst) > 0) m_options.input.mode = InputMode::CompilerWithASTImport; + else if (m_args.count(g_strImportEvmAssemblerJson) > 0) + m_options.input.mode = InputMode::EVMAssemblerJSON; else m_options.input.mode = InputMode::Compiler; @@ -1002,9 +1022,39 @@ void CommandLineParser::processArgs() if (option != CompilerOutputs::componentName(&CompilerOutputs::astCompactJson)) checkMutuallyExclusive({g_strStopAfter, option}); + if (m_options.input.mode == InputMode::EVMAssemblerJSON) + { + static std::set const supportedByEvmAsmJsonImport{ + g_strImportEvmAssemblerJson, + CompilerOutputs::componentName(&CompilerOutputs::asm_), + CompilerOutputs::componentName(&CompilerOutputs::binary), + CompilerOutputs::componentName(&CompilerOutputs::binaryRuntime), + CompilerOutputs::componentName(&CompilerOutputs::asmJson), + CompilerOutputs::componentName(&CompilerOutputs::opcodes), + g_strCombinedJson, + g_strInputFile, + g_strJsonIndent, + g_strPrettyJson, + "srcmap", + "srcmap-runtime", + }; + + for (auto const& option: m_args) + if (!option.second.defaulted() && !supportedByEvmAsmJsonImport.count(option.first)) + solThrow( + CommandLineValidationError, + fmt::format( + "Option --{} is not supported with --{}.", + option.first, + g_strImportEvmAssemblerJson + ) + ); + } + if ( m_options.input.mode != InputMode::Compiler && m_options.input.mode != InputMode::CompilerWithASTImport && + m_options.input.mode != InputMode::EVMAssemblerJSON && m_options.input.mode != InputMode::Assembler ) { @@ -1362,7 +1412,11 @@ void CommandLineParser::processArgs() m_args.count(g_strModelCheckerTimeout); m_options.output.viaIR = (m_args.count(g_strExperimentalViaIR) > 0 || m_args.count(g_strViaIR) > 0); - solAssert(m_options.input.mode == InputMode::Compiler || m_options.input.mode == InputMode::CompilerWithASTImport); + solAssert( + m_options.input.mode == InputMode::Compiler || + m_options.input.mode == InputMode::CompilerWithASTImport || + m_options.input.mode == InputMode::EVMAssemblerJSON + ); } void CommandLineParser::parseCombinedJsonOption() @@ -1378,6 +1432,35 @@ void CommandLineParser::parseCombinedJsonOption() m_options.compiler.combinedJsonRequests = CombinedJsonRequests{}; for (auto&& [componentName, component]: CombinedJsonRequests::componentMap()) m_options.compiler.combinedJsonRequests.value().*component = (requests.count(componentName) > 0); + + if (m_options.input.mode == InputMode::EVMAssemblerJSON && m_options.compiler.combinedJsonRequests.has_value()) + { + static bool CombinedJsonRequests::* invalidOptions[]{ + &CombinedJsonRequests::abi, + &CombinedJsonRequests::ast, + &CombinedJsonRequests::funDebug, + &CombinedJsonRequests::funDebugRuntime, + &CombinedJsonRequests::generatedSources, + &CombinedJsonRequests::generatedSourcesRuntime, + &CombinedJsonRequests::metadata, + &CombinedJsonRequests::natspecDev, + &CombinedJsonRequests::natspecUser, + &CombinedJsonRequests::signatureHashes, + &CombinedJsonRequests::storageLayout + }; + + for (auto const invalidOption: invalidOptions) + if (m_options.compiler.combinedJsonRequests.value().*invalidOption) + solThrow( + CommandLineValidationError, + fmt::format( + "Invalid option to --{}: {} for --{}", + g_strCombinedJson, + CombinedJsonRequests::componentName(invalidOption), + g_strImportEvmAssemblerJson + ) + ); + } } size_t CommandLineParser::countEnabledOptions(std::vector const& _optionNames) const diff --git a/solc/CommandLineParser.h b/solc/CommandLineParser.h index 33cb7bb09..c0eba0780 100644 --- a/solc/CommandLineParser.h +++ b/solc/CommandLineParser.h @@ -57,6 +57,7 @@ enum class InputMode Linker, Assembler, LanguageServer, + EVMAssemblerJSON }; struct CompilerOutputs diff --git a/test/cmdlineTests/asm_json/output b/test/cmdlineTests/asm_json/output index f6a0a4b19..27673625d 100644 --- a/test/cmdlineTests/asm_json/output +++ b/test/cmdlineTests/asm_json/output @@ -1567,7 +1567,8 @@ EVM assembly: "name": "JUMP", "source": 1 } - ] + ], + "index": 0 } }, "sourceList": diff --git a/test/cmdlineTests/asm_json_export_yul_more_subobjects/args b/test/cmdlineTests/asm_json_export_yul_more_subobjects/args new file mode 100644 index 000000000..aa82dbacc --- /dev/null +++ b/test/cmdlineTests/asm_json_export_yul_more_subobjects/args @@ -0,0 +1 @@ +--strict-assembly - --asm-json --pretty-json diff --git a/test/cmdlineTests/asm_json_export_yul_more_subobjects/output b/test/cmdlineTests/asm_json_export_yul_more_subobjects/output new file mode 100644 index 000000000..79eed07c5 --- /dev/null +++ b/test/cmdlineTests/asm_json_export_yul_more_subobjects/output @@ -0,0 +1,388 @@ + +======= (EVM) ======= +{ + ".code": + [ + { + "begin": 37, + "end": 51, + "name": "PUSHSIZE", + "source": 0 + }, + { + "begin": 34, + "end": 35, + "name": "PUSH", + "source": 0, + "value": "0" + }, + { + "begin": 27, + "end": 52, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 67, + "end": 81, + "name": "PUSH #[$]", + "source": 0, + "value": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "begin": 64, + "end": 65, + "name": "PUSH", + "source": 0, + "value": "1" + }, + { + "begin": 57, + "end": 82, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 97, + "end": 114, + "name": "PUSH #[$]", + "source": 0, + "value": "000000000000000000000000000000000000000000000000ffffffffffffffff" + }, + { + "begin": 94, + "end": 95, + "name": "PUSH", + "source": 0, + "value": "2" + }, + { + "begin": 87, + "end": 115, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 130, + "end": 152, + "name": "PUSH #[$]", + "source": 0, + "value": "000000000000000000000000000000000000000000000000fffffffffffffffe" + }, + { + "begin": 127, + "end": 128, + "name": "PUSH", + "source": 0, + "value": "3" + }, + { + "begin": 120, + "end": 153, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 168, + "end": 190, + "name": "PUSH #[$]", + "source": 0, + "value": "000000000000000000000000000000000000000000000000fffffffffffffffd" + }, + { + "begin": 165, + "end": 166, + "name": "PUSH", + "source": 0, + "value": "4" + }, + { + "begin": 158, + "end": 191, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 206, + "end": 228, + "name": "PUSH #[$]", + "source": 0, + "value": "000000000000000000000000000000000000000000000000fffffffffffffffc" + }, + { + "begin": 203, + "end": 204, + "name": "PUSH", + "source": 0, + "value": "5" + }, + { + "begin": 196, + "end": 229, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 21, + "end": 233, + "name": "STOP", + "source": 0 + } + ], + ".data": + { + "0": + { + ".code": + [ + { + "begin": 278, + "end": 292, + "name": "PUSHSIZE", + "source": 0 + }, + { + "begin": 275, + "end": 276, + "name": "PUSH", + "source": 0, + "value": "6" + }, + { + "begin": 268, + "end": 293, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 310, + "end": 324, + "name": "PUSH #[$]", + "source": 0, + "value": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "begin": 307, + "end": 308, + "name": "PUSH", + "source": 0, + "value": "7" + }, + { + "begin": 300, + "end": 325, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 342, + "end": 361, + "name": "PUSH #[$]", + "source": 0, + "value": "000000000000000000000000000000000000000000000000ffffffffffffffff" + }, + { + "begin": 339, + "end": 340, + "name": "PUSH", + "source": 0, + "value": "8" + }, + { + "begin": 332, + "end": 362, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 379, + "end": 398, + "name": "PUSH #[$]", + "source": 0, + "value": "000000000000000000000000000000000000000000000000fffffffffffffffe" + }, + { + "begin": 376, + "end": 377, + "name": "PUSH", + "source": 0, + "value": "9" + }, + { + "begin": 369, + "end": 399, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 417, + "end": 436, + "name": "PUSH #[$]", + "source": 0, + "value": "000000000000000000000000000000000000000000000000fffffffffffffffd" + }, + { + "begin": 413, + "end": 415, + "name": "PUSH", + "source": 0, + "value": "A" + }, + { + "begin": 406, + "end": 437, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 260, + "end": 443, + "name": "STOP", + "source": 0 + } + ], + ".data": + { + "0": + { + ".code": + [ + { + "begin": 494, + "end": 508, + "name": "PUSHSIZE", + "source": 0 + }, + { + "begin": 490, + "end": 492, + "name": "PUSH", + "source": 0, + "value": "B" + }, + { + "begin": 483, + "end": 509, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 529, + "end": 545, + "name": "PUSH #[$]", + "source": 0, + "value": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "begin": 525, + "end": 527, + "name": "PUSH", + "source": 0, + "value": "C" + }, + { + "begin": 518, + "end": 546, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 566, + "end": 582, + "name": "PUSH #[$]", + "source": 0, + "value": "0000000000000000000000000000000000000000000000000000000000000001" + }, + { + "begin": 562, + "end": 564, + "name": "PUSH", + "source": 0, + "value": "D" + }, + { + "begin": 555, + "end": 583, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 603, + "end": 619, + "name": "PUSH #[$]", + "source": 0, + "value": "0000000000000000000000000000000000000000000000000000000000000002" + }, + { + "begin": 599, + "end": 601, + "name": "PUSH", + "source": 0, + "value": "E" + }, + { + "begin": 592, + "end": 620, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 473, + "end": 628, + "name": "STOP", + "source": 0 + } + ], + ".data": + { + "0": + { + ".code": + [ + { + "begin": 676, + "end": 685, + "name": "INVALID", + "source": 0 + } + ], + "index": 0 + }, + "1": + { + ".code": + [ + { + "begin": 751, + "end": 760, + "name": "INVALID", + "source": 0 + } + ], + "index": 1 + }, + "2": + { + ".code": + [ + { + "begin": 826, + "end": 835, + "name": "INVALID", + "source": 0 + } + ], + "index": 2 + } + }, + "index": 0 + } + }, + "index": 0 + } + }, + "sourceList": + [ + "" + ] +} diff --git a/test/cmdlineTests/asm_json_export_yul_more_subobjects/stdin b/test/cmdlineTests/asm_json_export_yul_more_subobjects/stdin new file mode 100644 index 000000000..1b08be852 --- /dev/null +++ b/test/cmdlineTests/asm_json_export_yul_more_subobjects/stdin @@ -0,0 +1,43 @@ +object "L0" { + code { + sstore(0, datasize("L0")) + sstore(1, datasize("L1")) + sstore(2, datasize("L1.L2")) + sstore(3, datasize("L1.L2.L2_0")) + sstore(4, datasize("L1.L2.L2_1")) + sstore(5, datasize("L1.L2.L2_2")) + } + + object "L1" { + code { + sstore(6, datasize("L1")) + sstore(7, datasize("L2")) + sstore(8, datasize("L2.L2_0")) + sstore(9, datasize("L2.L2_1")) + sstore(10, datasize("L2.L2_2")) + } + object "L2" { + code { + sstore(11, datasize("L2")) + sstore(12, datasize("L2_0")) + sstore(13, datasize("L2_1")) + sstore(14, datasize("L2_2")) + } + object "L2_0" { + code { + invalid() + } + } + object "L2_1" { + code { + invalid() + } + } + object "L2_2" { + code { + invalid() + } + } + } + } +} diff --git a/test/cmdlineTests/asm_json_export_yul_subobjects/args b/test/cmdlineTests/asm_json_export_yul_subobjects/args new file mode 100644 index 000000000..aa82dbacc --- /dev/null +++ b/test/cmdlineTests/asm_json_export_yul_subobjects/args @@ -0,0 +1 @@ +--strict-assembly - --asm-json --pretty-json diff --git a/test/cmdlineTests/asm_json_export_yul_subobjects/output b/test/cmdlineTests/asm_json_export_yul_subobjects/output new file mode 100644 index 000000000..6e8a0c0d5 --- /dev/null +++ b/test/cmdlineTests/asm_json_export_yul_subobjects/output @@ -0,0 +1,437 @@ + +======= (EVM) ======= +{ + ".code": + [ + { + "begin": 36, + "end": 51, + "name": "PUSH", + "source": 0, + "value": "0" + }, + { + "begin": 33, + "end": 34, + "name": "DUP1", + "source": 0 + }, + { + "begin": 26, + "end": 52, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 67, + "end": 80, + "name": "PUSHSIZE", + "source": 0 + }, + { + "begin": 64, + "end": 65, + "name": "PUSH", + "source": 0, + "value": "1" + }, + { + "begin": 57, + "end": 81, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 96, + "end": 111, + "name": "PUSH [$]", + "source": 0, + "value": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "begin": 93, + "end": 94, + "name": "PUSH", + "source": 0, + "value": "2" + }, + { + "begin": 86, + "end": 112, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 127, + "end": 140, + "name": "PUSH #[$]", + "source": 0, + "value": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "begin": 124, + "end": 125, + "name": "PUSH", + "source": 0, + "value": "3" + }, + { + "begin": 117, + "end": 141, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 156, + "end": 173, + "name": "PUSH [$]", + "source": 0, + "value": "000000000000000000000000000000000000000000000000ffffffffffffffff" + }, + { + "begin": 153, + "end": 154, + "name": "PUSH", + "source": 0, + "value": "4" + }, + { + "begin": 146, + "end": 174, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 189, + "end": 204, + "name": "PUSH #[$]", + "source": 0, + "value": "000000000000000000000000000000000000000000000000ffffffffffffffff" + }, + { + "begin": 186, + "end": 187, + "name": "PUSH", + "source": 0, + "value": "5" + }, + { + "begin": 179, + "end": 205, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 220, + "end": 237, + "name": "PUSH [$]", + "source": 0, + "value": "000000000000000000000000000000000000000000000000fffffffffffffffe" + }, + { + "begin": 217, + "end": 218, + "name": "PUSH", + "source": 0, + "value": "6" + }, + { + "begin": 210, + "end": 238, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 253, + "end": 268, + "name": "PUSH #[$]", + "source": 0, + "value": "000000000000000000000000000000000000000000000000fffffffffffffffe" + }, + { + "begin": 250, + "end": 251, + "name": "PUSH", + "source": 0, + "value": "7" + }, + { + "begin": 243, + "end": 269, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 284, + "end": 303, + "name": "PUSH [$]", + "source": 0, + "value": "000000000000000000000000000000000000000000000000fffffffffffffffd" + }, + { + "begin": 281, + "end": 282, + "name": "PUSH", + "source": 0, + "value": "8" + }, + { + "begin": 274, + "end": 304, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 319, + "end": 336, + "name": "PUSH #[$]", + "source": 0, + "value": "000000000000000000000000000000000000000000000000fffffffffffffffd" + }, + { + "begin": 316, + "end": 317, + "name": "PUSH", + "source": 0, + "value": "9" + }, + { + "begin": 309, + "end": 337, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 20, + "end": 341, + "name": "STOP", + "source": 0 + } + ], + ".data": + { + "0": + { + ".code": + [ + { + "begin": 418, + "end": 433, + "name": "PUSH [$]", + "source": 0, + "value": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "begin": 414, + "end": 416, + "name": "PUSH", + "source": 0, + "value": "A" + }, + { + "begin": 407, + "end": 434, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 452, + "end": 465, + "name": "PUSH #[$]", + "source": 0, + "value": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "begin": 448, + "end": 450, + "name": "PUSH", + "source": 0, + "value": "B" + }, + { + "begin": 441, + "end": 466, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 484, + "end": 499, + "name": "PUSH [$]", + "source": 0, + "value": "0000000000000000000000000000000000000000000000000000000000000001" + }, + { + "begin": 480, + "end": 482, + "name": "PUSH", + "source": 0, + "value": "C" + }, + { + "begin": 473, + "end": 500, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 518, + "end": 531, + "name": "PUSH #[$]", + "source": 0, + "value": "0000000000000000000000000000000000000000000000000000000000000001" + }, + { + "begin": 514, + "end": 516, + "name": "PUSH", + "source": 0, + "value": "D" + }, + { + "begin": 507, + "end": 532, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 550, + "end": 567, + "name": "PUSH [$]", + "source": 0, + "value": "000000000000000000000000000000000000000000000000ffffffffffffffff" + }, + { + "begin": 546, + "end": 548, + "name": "PUSH", + "source": 0, + "value": "E" + }, + { + "begin": 539, + "end": 568, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 586, + "end": 601, + "name": "PUSH #[$]", + "source": 0, + "value": "000000000000000000000000000000000000000000000000ffffffffffffffff" + }, + { + "begin": 582, + "end": 584, + "name": "PUSH", + "source": 0, + "value": "F" + }, + { + "begin": 575, + "end": 602, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 399, + "end": 608, + "name": "STOP", + "source": 0 + } + ], + ".data": + { + "0": + { + ".code": + [ + { + "begin": 658, + "end": 673, + "name": "PUSH [$]", + "source": 0, + "value": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "begin": 654, + "end": 656, + "name": "PUSH", + "source": 0, + "value": "10" + }, + { + "begin": 647, + "end": 674, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 694, + "end": 707, + "name": "PUSH #[$]", + "source": 0, + "value": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "begin": 690, + "end": 692, + "name": "PUSH", + "source": 0, + "value": "11" + }, + { + "begin": 683, + "end": 708, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 637, + "end": 716, + "name": "STOP", + "source": 0 + } + ], + ".data": + { + "0": + { + ".code": + [ + { + "begin": 761, + "end": 770, + "name": "INVALID", + "source": 0 + } + ], + "index": 0 + } + }, + "index": 0 + }, + "1": + { + ".code": + [ + { + "begin": 833, + "end": 842, + "name": "INVALID", + "source": 0 + } + ], + "index": 1 + } + }, + "index": 0 + }, + "ACAF3289D7B601CBD114FB36C4D29C85BBFD5E133F14CB355C3FD8D99367964F": "48656c6c6f2c20576f726c6421" + }, + "sourceList": + [ + "" + ] +} diff --git a/test/cmdlineTests/asm_json_export_yul_subobjects/stdin b/test/cmdlineTests/asm_json_export_yul_subobjects/stdin new file mode 100644 index 000000000..8ba3fd0ad --- /dev/null +++ b/test/cmdlineTests/asm_json_export_yul_subobjects/stdin @@ -0,0 +1,43 @@ +object "A" { + code { + sstore(0, dataoffset("A")) + sstore(1, datasize("A")) + sstore(2, dataoffset("B")) + sstore(3, datasize("B")) + sstore(4, dataoffset("B.C")) + sstore(5, datasize("B.C")) + sstore(6, dataoffset("B.E")) + sstore(7, datasize("B.E")) + sstore(8, dataoffset("B.C.D")) + sstore(9, datasize("B.C.D")) + } + + data "data1" "Hello, World!" + + object "B" { + code { + sstore(10, dataoffset("C")) + sstore(11, datasize("C")) + sstore(12, dataoffset("E")) + sstore(13, datasize("E")) + sstore(14, dataoffset("C.D")) + sstore(15, datasize("C.D")) + } + object "C" { + code { + sstore(16, dataoffset("D")) + sstore(17, datasize("D")) + } + object "D" { + code { + invalid() + } + } + } + object "E" { + code { + invalid() + } + } + } +} diff --git a/test/cmdlineTests/asm_json_export_yul_verbatim/args b/test/cmdlineTests/asm_json_export_yul_verbatim/args new file mode 100644 index 000000000..a639549cf --- /dev/null +++ b/test/cmdlineTests/asm_json_export_yul_verbatim/args @@ -0,0 +1 @@ +--strict-assembly - --asm-json diff --git a/test/cmdlineTests/asm_json_export_yul_verbatim/output b/test/cmdlineTests/asm_json_export_yul_verbatim/output new file mode 100644 index 000000000..675ea2087 --- /dev/null +++ b/test/cmdlineTests/asm_json_export_yul_verbatim/output @@ -0,0 +1,3 @@ + +======= (EVM) ======= +{".code":[{"begin":28,"end":29,"name":"PUSH","source":0,"value":"0"},{"begin":15,"end":30,"name":"CALLDATALOAD","source":0},{"begin":44,"end":46,"name":"PUSH","source":0,"value":"14"},{"begin":61,"end":62,"name":"DUP1","source":0},{"begin":58,"end":59,"name":"DUP3","source":0},{"begin":51,"end":63,"name":"SSTORE","source":0},{"begin":84,"end":86,"name":"PUSH","source":0,"value":"20"},{"begin":71,"end":87,"name":"CALLDATALOAD","source":0},{"begin":68,"end":188,"name":"ISZERO","source":0},{"begin":68,"end":188,"name":"PUSH [tag]","source":0,"value":"1"},{"begin":68,"end":188,"name":"JUMPI","source":0},{"begin":108,"end":109,"name":"DUP1","source":0},{"begin":105,"end":106,"name":"DUP3","source":0},{"begin":98,"end":110,"name":"SSTORE","source":0},{"begin":149,"end":150,"name":"PUSH","source":0,"value":"0"},{"begin":146,"end":147,"name":"DUP1","source":0},{"begin":143,"end":144,"name":"PUSH","source":0,"value":"0"},{"begin":140,"end":141,"name":"DUP1","source":0},{"begin":137,"end":138,"name":"PUSH","source":0,"value":"0"},{"begin":134,"end":135,"name":"DUP1","source":0},{"begin":123,"end":151,"name":"STATICCALL","source":0},{"begin":119,"end":152,"name":"POP","source":0},{"begin":161,"end":182,"name":"VERBATIM","source":0,"value":"78797a"},{"begin":68,"end":188,"name":"tag","source":0,"value":"1"},{"begin":68,"end":188,"name":"JUMPDEST","source":0},{"begin":203,"end":204,"name":"DUP1","source":0},{"begin":200,"end":201,"name":"DUP3","source":0},{"begin":193,"end":205,"name":"SSTORE","source":0},{"begin":0,"end":207,"name":"POP","source":0},{"begin":0,"end":207,"name":"POP","source":0}],"sourceList":[""]} diff --git a/test/cmdlineTests/asm_json_export_yul_verbatim/stdin b/test/cmdlineTests/asm_json_export_yul_verbatim/stdin new file mode 100644 index 000000000..eac2ef83d --- /dev/null +++ b/test/cmdlineTests/asm_json_export_yul_verbatim/stdin @@ -0,0 +1,11 @@ +{ + let a := calldataload(0) + let b := 20 + sstore(a, b) + if calldataload(32) { + sstore(a, b) + pop(staticcall(0, 0, 0, 0, 0, 0)) + verbatim_0i_0o("xyz") + } + sstore(a, b) +} diff --git a/test/cmdlineTests/asm_json_export_yul_with_debug/args b/test/cmdlineTests/asm_json_export_yul_with_debug/args new file mode 100644 index 000000000..a639549cf --- /dev/null +++ b/test/cmdlineTests/asm_json_export_yul_with_debug/args @@ -0,0 +1 @@ +--strict-assembly - --asm-json diff --git a/test/cmdlineTests/asm_json_export_yul_with_debug/output b/test/cmdlineTests/asm_json_export_yul_with_debug/output new file mode 100644 index 000000000..bf0d48414 --- /dev/null +++ b/test/cmdlineTests/asm_json_export_yul_with_debug/output @@ -0,0 +1,3 @@ + +======= (EVM) ======= +{".code":[{"begin":0,"end":125,"name":"PUSH","source":0,"value":"80"},{"begin":0,"end":125,"name":"DUP1","source":0},{"begin":0,"end":125,"name":"PUSH","source":0,"value":"40"},{"begin":0,"end":125,"name":"MSTORE","source":0},{"begin":0,"end":125,"name":"CALLVALUE","source":0},{"begin":0,"end":125,"name":"PUSH [tag]","source":0,"value":"1"},{"begin":0,"end":125,"name":"JUMPI","source":0},{"begin":56,"end":57,"name":"PUSH","source":0,"value":"2"},{"begin":33,"end":34,"name":"PUSH","source":0,"value":"0"},{"begin":0,"end":125,"name":"SSTORE","source":0},{"begin":33,"end":34,"name":"PUSH","source":0,"value":"0"},{"begin":33,"end":34,"name":"PUSH","source":0,"value":"1"},{"begin":0,"end":125,"name":"SSTORE","source":0},{"begin":0,"end":125,"name":"PUSH #[$]","source":0,"value":"0000000000000000000000000000000000000000000000000000000000000000"},{"begin":0,"end":125,"name":"SWAP1","source":0},{"begin":0,"end":125,"name":"DUP2","source":0},{"begin":0,"end":125,"name":"PUSH [$]","source":0,"value":"0000000000000000000000000000000000000000000000000000000000000000"},{"begin":0,"end":125,"name":"DUP3","source":0},{"begin":0,"end":125,"name":"CODECOPY","source":0},{"begin":0,"end":125,"name":"RETURN","source":0},{"begin":0,"end":125,"name":"tag","source":0,"value":"1"},{"begin":0,"end":125,"name":"JUMPDEST","source":0},{"begin":0,"end":125,"name":"PUSH","source":0,"value":"0"},{"begin":0,"end":125,"name":"DUP1","source":0},{"begin":0,"end":125,"name":"REVERT","source":0}],".data":{"0":{".auxdata":"",".code":[{"begin":0,"end":125,"name":"PUSH","source":0,"value":"80"},{"begin":0,"end":125,"name":"DUP1","source":0},{"begin":0,"end":125,"name":"PUSH","source":0,"value":"40"},{"begin":0,"end":125,"name":"MSTORE","source":0},{"begin":0,"end":125,"name":"PUSH","source":0,"value":"4"},{"begin":0,"end":125,"name":"CALLDATASIZE","source":0},{"begin":0,"end":125,"name":"LT","source":0},{"begin":0,"end":125,"name":"ISZERO","source":0},{"begin":0,"end":125,"name":"PUSH [tag]","source":0,"value":"1"},{"begin":0,"end":125,"name":"JUMPI","source":0},{"begin":-1,"end":-1,"name":"tag","source":-1,"value":"2"},{"begin":-1,"end":-1,"name":"JUMPDEST","source":-1},{"begin":0,"end":125,"name":"PUSH","source":0,"value":"0"},{"begin":0,"end":125,"name":"DUP1","source":0},{"begin":0,"end":125,"name":"REVERT","source":0},{"begin":0,"end":125,"name":"tag","source":0,"value":"1"},{"begin":0,"end":125,"name":"JUMPDEST","source":0},{"begin":0,"end":125,"name":"PUSH","source":0,"value":"0"},{"begin":0,"end":125,"name":"SWAP1","source":0},{"begin":0,"end":125,"name":"DUP2","source":0},{"begin":0,"end":125,"name":"CALLDATALOAD","source":0},{"begin":0,"end":125,"name":"PUSH","source":0,"value":"E0"},{"begin":0,"end":125,"name":"SHR","source":0},{"begin":0,"end":125,"name":"SWAP1","source":0},{"begin":0,"end":125,"name":"DUP2","source":0},{"begin":0,"end":125,"name":"PUSH","source":0,"value":"B4F40C61"},{"begin":0,"end":125,"name":"EQ","source":0},{"begin":0,"end":125,"name":"PUSH [tag]","source":0,"value":"3"},{"begin":0,"end":125,"name":"JUMPI","source":0},{"begin":0,"end":125,"name":"POP","source":0},{"begin":0,"end":125,"name":"PUSH","source":0,"value":"E5AA3D58"},{"begin":0,"end":125,"name":"SUB","source":0},{"begin":0,"end":125,"name":"PUSH [tag]","source":0,"value":"2"},{"begin":0,"end":125,"name":"JUMPI","source":0},{"begin":0,"end":125,"name":"CALLVALUE","source":0},{"begin":0,"end":125,"name":"PUSH [tag]","source":0,"value":"7"},{"begin":0,"end":125,"name":"JUMPI","source":0},{"begin":0,"end":125,"name":"DUP1","source":0},{"begin":0,"end":125,"name":"PUSH","source":0,"value":"3"},{"begin":0,"end":125,"name":"NOT","source":0},{"begin":0,"end":125,"name":"CALLDATASIZE","source":0},{"begin":0,"end":125,"name":"ADD","source":0},{"begin":0,"end":125,"name":"SLT","source":0},{"begin":0,"end":125,"name":"PUSH [tag]","source":0,"value":"9"},{"begin":0,"end":125,"name":"JUMPI","source":0},{"begin":0,"end":125,"name":"PUSH","source":0,"value":"20"},{"begin":0,"end":125,"name":"SWAP1","source":0},{"begin":0,"end":125,"name":"SLOAD","source":0},{"begin":0,"end":125,"name":"PUSH","source":0,"value":"40"},{"begin":0,"end":125,"name":"MLOAD","source":0},{"begin":0,"end":125,"name":"SWAP1","source":0},{"begin":0,"end":125,"name":"DUP2","source":0},{"begin":0,"end":125,"name":"MSTORE","source":0},{"begin":0,"end":125,"name":"RETURN","source":0},{"begin":0,"end":125,"name":"tag","source":0,"value":"9"},{"begin":0,"end":125,"name":"JUMPDEST","source":0},{"begin":0,"end":125,"name":"DUP1","source":0},{"begin":0,"end":125,"name":"REVERT","source":0},{"begin":0,"end":125,"name":"tag","source":0,"value":"7"},{"begin":0,"end":125,"name":"JUMPDEST","source":0},{"begin":0,"end":125,"name":"DUP1","source":0},{"begin":0,"end":125,"name":"REVERT","source":0},{"begin":0,"end":125,"name":"tag","source":0,"value":"3"},{"begin":0,"end":125,"name":"JUMPDEST","source":0},{"begin":0,"end":125,"name":"SWAP1","source":0},{"begin":0,"end":125,"name":"POP","source":0},{"begin":0,"end":125,"name":"CALLVALUE","source":0},{"begin":0,"end":125,"name":"PUSH [tag]","source":0,"value":"11"},{"begin":0,"end":125,"name":"JUMPI","source":0},{"begin":0,"end":125,"name":"DUP2","source":0},{"begin":0,"end":125,"name":"PUSH","source":0,"value":"3"},{"begin":0,"end":125,"name":"NOT","source":0},{"begin":0,"end":125,"name":"CALLDATASIZE","source":0},{"begin":0,"end":125,"name":"ADD","source":0},{"begin":0,"end":125,"name":"SLT","source":0},{"begin":0,"end":125,"name":"PUSH [tag]","source":0,"value":"13"},{"begin":0,"end":125,"name":"JUMPI","source":0},{"begin":0,"end":125,"name":"PUSH","source":0,"value":"20"},{"begin":0,"end":125,"name":"SWAP1","source":0},{"begin":40,"end":57,"name":"PUSH","source":0,"value":"1"},{"begin":0,"end":125,"name":"SLOAD","source":0},{"begin":0,"end":125,"name":"DUP2","source":0},{"begin":0,"end":125,"name":"MSTORE","source":0},{"begin":0,"end":125,"name":"RETURN","source":0},{"begin":0,"end":125,"name":"tag","source":0,"value":"13"},{"begin":0,"end":125,"name":"JUMPDEST","source":0},{"begin":0,"end":125,"name":"POP","source":0},{"begin":0,"end":125,"name":"DUP1","source":0},{"begin":0,"end":125,"name":"REVERT","source":0},{"begin":0,"end":125,"name":"tag","source":0,"value":"11"},{"begin":0,"end":125,"name":"JUMPDEST","source":0},{"begin":0,"end":125,"name":"POP","source":0},{"begin":0,"end":125,"name":"DUP1","source":0},{"begin":0,"end":125,"name":"REVERT","source":0}],"index":0}},"sourceList":["state_var_initialization.sol"]} diff --git a/test/cmdlineTests/asm_json_export_yul_with_debug/stdin b/test/cmdlineTests/asm_json_export_yul_with_debug/stdin new file mode 100644 index 000000000..76acea75c --- /dev/null +++ b/test/cmdlineTests/asm_json_export_yul_with_debug/stdin @@ -0,0 +1,50 @@ +/// @use-src 0:"state_var_initialization.sol" +object "C_23" { + code { + { + /// @src 0:0:125 "contract C {..." + let _1 := memoryguard(0x80) + mstore(64, _1) + if callvalue() { revert(0, 0) } + sstore(/** @src 0:33:34 "1" */ 0x00, /** @src 0:56:57 "2" */ 0x02) + /// @src 0:0:125 "contract C {..." + sstore(/** @src 0:33:34 "1" */ 0x01, 0x00) + /// @src 0:0:125 "contract C {..." + let _2 := datasize("C_23_deployed") + codecopy(_1, dataoffset("C_23_deployed"), _2) + return(_1, _2) + } + } + /// @use-src 0:"state_var_initialization.sol" + object "C_23_deployed" { + code { + { + /// @src 0:0:125 "contract C {..." + let _1 := memoryguard(0x80) + mstore(64, _1) + if iszero(lt(calldatasize(), 4)) + { + let _2 := 0 + switch shr(224, calldataload(_2)) + case 0xb4f40c61 { + if callvalue() { revert(_2, _2) } + if slt(add(calldatasize(), not(3)), _2) { revert(_2, _2) } + mstore(_1, sload(/** @src 0:40:57 "uint public k = 2" */ 1)) + /// @src 0:0:125 "contract C {..." + return(_1, 32) + } + case 0xe5aa3d58 { + if callvalue() { revert(_2, _2) } + if slt(add(calldatasize(), not(3)), _2) { revert(_2, _2) } + let _3 := sload(_2) + let memPos := mload(64) + mstore(memPos, _3) + return(memPos, 32) + } + } + revert(0, 0) + } + } + data ".metadata" hex"a2646970667358221220f04f800086d1bd95dea7e66c53d041963124c118e4dc70bc4b39a50865c2483f64736f6c63430008130033" + } +} \ No newline at end of file diff --git a/test/cmdlineTests/asm_json_export_yul_without_debug/args b/test/cmdlineTests/asm_json_export_yul_without_debug/args new file mode 100644 index 000000000..a639549cf --- /dev/null +++ b/test/cmdlineTests/asm_json_export_yul_without_debug/args @@ -0,0 +1 @@ +--strict-assembly - --asm-json diff --git a/test/cmdlineTests/asm_json_export_yul_without_debug/output b/test/cmdlineTests/asm_json_export_yul_without_debug/output new file mode 100644 index 000000000..ca76d1fdf --- /dev/null +++ b/test/cmdlineTests/asm_json_export_yul_without_debug/output @@ -0,0 +1,3 @@ + +======= (EVM) ======= +{".code":[{"begin":59,"end":76,"name":"PUSH","source":0,"value":"80"},{"begin":89,"end":103,"name":"DUP1","source":0},{"begin":96,"end":98,"name":"PUSH","source":0,"value":"40"},{"begin":89,"end":103,"name":"MSTORE","source":0},{"begin":119,"end":130,"name":"CALLVALUE","source":0},{"begin":116,"end":147,"name":"PUSH [tag]","source":0,"value":"1"},{"begin":116,"end":147,"name":"JUMPI","source":0},{"begin":173,"end":177,"name":"PUSH","source":0,"value":"2"},{"begin":167,"end":171,"name":"PUSH","source":0,"value":"0"},{"begin":160,"end":178,"name":"SSTORE","source":0},{"begin":204,"end":208,"name":"PUSH","source":0,"value":"0"},{"begin":198,"end":202,"name":"PUSH","source":0,"value":"1"},{"begin":191,"end":209,"name":"SSTORE","source":0},{"begin":232,"end":257,"name":"PUSH #[$]","source":0,"value":"0000000000000000000000000000000000000000000000000000000000000000"},{"begin":283,"end":310,"name":"SWAP1","source":0},{"begin":283,"end":310,"name":"DUP2","source":0},{"begin":283,"end":310,"name":"PUSH [$]","source":0,"value":"0000000000000000000000000000000000000000000000000000000000000000"},{"begin":270,"end":315,"name":"DUP3","source":0},{"begin":270,"end":315,"name":"CODECOPY","source":0},{"begin":328,"end":342,"name":"RETURN","source":0},{"begin":131,"end":147,"name":"tag","source":0,"value":"1"},{"begin":131,"end":147,"name":"JUMPDEST","source":0},{"begin":143,"end":144,"name":"PUSH","source":0,"value":"0"},{"begin":133,"end":145,"name":"DUP1","source":0},{"begin":133,"end":145,"name":"REVERT","source":0}],".data":{"0":{".auxdata":"",".code":[{"begin":443,"end":460,"name":"PUSH","source":0,"value":"80"},{"begin":477,"end":491,"name":"DUP1","source":0},{"begin":484,"end":486,"name":"PUSH","source":0,"value":"40"},{"begin":477,"end":491,"name":"MSTORE","source":0},{"begin":537,"end":538,"name":"PUSH","source":0,"value":"4"},{"begin":521,"end":535,"name":"CALLDATASIZE","source":0},{"begin":518,"end":539,"name":"LT","source":0},{"begin":511,"end":540,"name":"ISZERO","source":0},{"begin":508,"end":1367,"name":"PUSH [tag]","source":0,"value":"1"},{"begin":508,"end":1367,"name":"JUMPI","source":0},{"begin":401,"end":1420,"name":"tag","source":0,"value":"2"},{"begin":401,"end":1420,"name":"JUMPDEST","source":0},{"begin":1394,"end":1395,"name":"PUSH","source":0,"value":"0"},{"begin":1384,"end":1396,"name":"DUP1","source":0},{"begin":1384,"end":1396,"name":"REVERT","source":0},{"begin":557,"end":1367,"name":"tag","source":0,"value":"1"},{"begin":557,"end":1367,"name":"JUMPDEST","source":0},{"begin":589,"end":590,"name":"PUSH","source":0,"value":"0"},{"begin":627,"end":643,"name":"SWAP1","source":0},{"begin":627,"end":643,"name":"DUP2","source":0},{"begin":627,"end":643,"name":"CALLDATALOAD","source":0},{"begin":622,"end":625,"name":"PUSH","source":0,"value":"E0"},{"begin":618,"end":644,"name":"SHR","source":0},{"begin":665,"end":970,"name":"SWAP1","source":0},{"begin":665,"end":970,"name":"DUP2","source":0},{"begin":670,"end":680,"name":"PUSH","source":0,"value":"B4F40C61"},{"begin":665,"end":970,"name":"EQ","source":0},{"begin":665,"end":970,"name":"PUSH [tag]","source":0,"value":"3"},{"begin":665,"end":970,"name":"JUMPI","source":0},{"begin":991,"end":1349,"name":"POP","source":0},{"begin":996,"end":1006,"name":"PUSH","source":0,"value":"E5AA3D58"},{"begin":991,"end":1349,"name":"SUB","source":0},{"begin":557,"end":1367,"name":"PUSH [tag]","source":0,"value":"2"},{"begin":991,"end":1349,"name":"JUMPI","source":0},{"begin":1036,"end":1047,"name":"CALLVALUE","source":0},{"begin":1033,"end":1066,"name":"PUSH [tag]","source":0,"value":"7"},{"begin":1033,"end":1066,"name":"JUMPI","source":0},{"begin":1118,"end":1124,"name":"DUP1","source":0},{"begin":1122,"end":1123,"name":"PUSH","source":0,"value":"3"},{"begin":1118,"end":1124,"name":"NOT","source":0},{"begin":1102,"end":1116,"name":"CALLDATASIZE","source":0},{"begin":1098,"end":1125,"name":"ADD","source":0},{"begin":1094,"end":1130,"name":"SLT","source":0},{"begin":1091,"end":1149,"name":"PUSH [tag]","source":0,"value":"9"},{"begin":1091,"end":1149,"name":"JUMPI","source":0},{"begin":1324,"end":1326,"name":"PUSH","source":0,"value":"20"},{"begin":1184,"end":1193,"name":"SWAP1","source":0},{"begin":1184,"end":1193,"name":"SLOAD","source":0},{"begin":1238,"end":1240,"name":"PUSH","source":0,"value":"40"},{"begin":1232,"end":1241,"name":"MLOAD","source":0},{"begin":1266,"end":1284,"name":"SWAP1","source":0},{"begin":1266,"end":1284,"name":"DUP2","source":0},{"begin":1266,"end":1284,"name":"MSTORE","source":0},{"begin":1309,"end":1327,"name":"RETURN","source":0},{"begin":1131,"end":1149,"name":"tag","source":0,"value":"9"},{"begin":1131,"end":1149,"name":"JUMPDEST","source":0},{"begin":1133,"end":1147,"name":"DUP1","source":0},{"begin":1133,"end":1147,"name":"REVERT","source":0},{"begin":1048,"end":1066,"name":"tag","source":0,"value":"7"},{"begin":1048,"end":1066,"name":"JUMPDEST","source":0},{"begin":1050,"end":1064,"name":"DUP1","source":0},{"begin":1050,"end":1064,"name":"REVERT","source":0},{"begin":681,"end":970,"name":"tag","source":0,"value":"3"},{"begin":681,"end":970,"name":"JUMPDEST","source":0},{"begin":710,"end":721,"name":"SWAP1","source":0},{"begin":710,"end":721,"name":"POP","source":0},{"begin":710,"end":721,"name":"CALLVALUE","source":0},{"begin":707,"end":740,"name":"PUSH [tag]","source":0,"value":"11"},{"begin":707,"end":740,"name":"JUMPI","source":0},{"begin":792,"end":798,"name":"DUP2","source":0},{"begin":796,"end":797,"name":"PUSH","source":0,"value":"3"},{"begin":792,"end":798,"name":"NOT","source":0},{"begin":776,"end":790,"name":"CALLDATASIZE","source":0},{"begin":772,"end":799,"name":"ADD","source":0},{"begin":768,"end":804,"name":"SLT","source":0},{"begin":765,"end":823,"name":"PUSH [tag]","source":0,"value":"13"},{"begin":765,"end":823,"name":"JUMPI","source":0},{"begin":945,"end":947,"name":"PUSH","source":0,"value":"20"},{"begin":859,"end":908,"name":"SWAP1","source":0},{"begin":906,"end":907,"name":"PUSH","source":0,"value":"1"},{"begin":859,"end":908,"name":"SLOAD","source":0},{"begin":848,"end":909,"name":"DUP2","source":0},{"begin":848,"end":909,"name":"MSTORE","source":0},{"begin":934,"end":948,"name":"RETURN","source":0},{"begin":805,"end":823,"name":"tag","source":0,"value":"13"},{"begin":805,"end":823,"name":"JUMPDEST","source":0},{"begin":807,"end":821,"name":"POP","source":0},{"begin":807,"end":821,"name":"DUP1","source":0},{"begin":807,"end":821,"name":"REVERT","source":0},{"begin":722,"end":740,"name":"tag","source":0,"value":"11"},{"begin":722,"end":740,"name":"JUMPDEST","source":0},{"begin":724,"end":738,"name":"POP","source":0},{"begin":724,"end":738,"name":"DUP1","source":0},{"begin":724,"end":738,"name":"REVERT","source":0}],"index":0}},"sourceList":[""]} diff --git a/test/cmdlineTests/asm_json_export_yul_without_debug/stdin b/test/cmdlineTests/asm_json_export_yul_without_debug/stdin new file mode 100644 index 000000000..91fa43622 --- /dev/null +++ b/test/cmdlineTests/asm_json_export_yul_without_debug/stdin @@ -0,0 +1,43 @@ +object "C_23" { + code { + { + let _1 := memoryguard(0x80) + mstore(64, _1) + if callvalue() { revert(0, 0) } + sstore(0x00, 0x02) + sstore(0x01, 0x00) + let _2 := datasize("C_23_deployed") + codecopy(_1, dataoffset("C_23_deployed"), _2) + return(_1, _2) + } + } + object "C_23_deployed" { + code { + { + let _1 := memoryguard(0x80) + mstore(64, _1) + if iszero(lt(calldatasize(), 4)) + { + let _2 := 0 + switch shr(224, calldataload(_2)) + case 0xb4f40c61 { + if callvalue() { revert(_2, _2) } + if slt(add(calldatasize(), not(3)), _2) { revert(_2, _2) } + mstore(_1, sload(/** @src 0:40:57 "uint public k = 2" */ 1)) + return(_1, 32) + } + case 0xe5aa3d58 { + if callvalue() { revert(_2, _2) } + if slt(add(calldatasize(), not(3)), _2) { revert(_2, _2) } + let _3 := sload(_2) + let memPos := mload(64) + mstore(memPos, _3) + return(memPos, 32) + } + } + revert(0, 0) + } + } + data ".metadata" hex"a2646970667358221220f04f800086d1bd95dea7e66c53d041963124c118e4dc70bc4b39a50865c2483f64736f6c63430008130033" + } +} \ No newline at end of file diff --git a/test/cmdlineTests/asm_json_import_all_valid_flags/args b/test/cmdlineTests/asm_json_import_all_valid_flags/args new file mode 100644 index 000000000..e6010eac3 --- /dev/null +++ b/test/cmdlineTests/asm_json_import_all_valid_flags/args @@ -0,0 +1 @@ +--pretty-json --json-indent 4 --combined-json bin,bin-runtime,opcodes,asm,srcmap,srcmap-runtime --asm --bin --bin-runtime --asm-json --import-asm-json - diff --git a/test/cmdlineTests/asm_json_import_all_valid_flags/output b/test/cmdlineTests/asm_json_import_all_valid_flags/output new file mode 100644 index 000000000..a880afa5b --- /dev/null +++ b/test/cmdlineTests/asm_json_import_all_valid_flags/output @@ -0,0 +1,93 @@ +{ + "contracts": + { + "": + { + "asm": + { + ".code": + [ + { + "begin": 0, + "end": 0, + "name": "PUSH", + "source": -1, + "value": "0" + } + ], + ".data": + { + "0": + { + ".code": + [ + { + "begin": 0, + "end": 0, + "name": "PUSH", + "source": -1, + "value": "1" + } + ], + "index": 0 + } + }, + "sourceList": + [ + "contract.sol", + "#utility.yul" + ] + }, + "bin": "5ffe", + "bin-runtime": "6001", + "opcodes": "PUSH0 INVALID ", + "srcmap": "0:0::-:0", + "srcmap-runtime": "0:0::-:0" + } + }, + "sourceList": + [ + "contract.sol", + "#utility.yul" + ], + "version": "" +} +Binary: +5ffe +Binary of the runtime part: +6001 +EVM assembly: +{ + ".code": + [ + { + "begin": 0, + "end": 0, + "name": "PUSH", + "source": -1, + "value": "0" + } + ], + ".data": + { + "0": + { + ".code": + [ + { + "begin": 0, + "end": 0, + "name": "PUSH", + "source": -1, + "value": "1" + } + ], + "index": 0 + } + }, + "sourceList": + [ + "contract.sol", + "#utility.yul" + ] +} diff --git a/test/cmdlineTests/asm_json_import_all_valid_flags/stdin b/test/cmdlineTests/asm_json_import_all_valid_flags/stdin new file mode 100644 index 000000000..dbaac88fa --- /dev/null +++ b/test/cmdlineTests/asm_json_import_all_valid_flags/stdin @@ -0,0 +1,23 @@ +{ + ".code": [ + { + "name": "PUSH", + "value": "0" + } + ], + ".data": { + "0": { + ".code": [ + { + "name": "PUSH", + "value": "1" + } + ], + "index": 0 + } + }, + "sourceList": [ + "contract.sol", + "#utility.yul" + ] +} diff --git a/test/cmdlineTests/asm_json_import_difficulty_prevrandao/args b/test/cmdlineTests/asm_json_import_difficulty_prevrandao/args new file mode 100644 index 000000000..2b4b3a153 --- /dev/null +++ b/test/cmdlineTests/asm_json_import_difficulty_prevrandao/args @@ -0,0 +1 @@ +--import-asm-json - --opcodes --asm diff --git a/test/cmdlineTests/asm_json_import_difficulty_prevrandao/output b/test/cmdlineTests/asm_json_import_difficulty_prevrandao/output new file mode 100644 index 000000000..3d19f83d6 --- /dev/null +++ b/test/cmdlineTests/asm_json_import_difficulty_prevrandao/output @@ -0,0 +1,6 @@ +Opcodes: +PREVRANDAO PREVRANDAO +EVM assembly: + /* */ + prevrandao + prevrandao diff --git a/test/cmdlineTests/asm_json_import_difficulty_prevrandao/stdin b/test/cmdlineTests/asm_json_import_difficulty_prevrandao/stdin new file mode 100644 index 000000000..70d8d364e --- /dev/null +++ b/test/cmdlineTests/asm_json_import_difficulty_prevrandao/stdin @@ -0,0 +1,6 @@ +{ + ".code": [ + { "name": "DIFFICULTY" }, + { "name": "PREVRANDAO" } + ] +} diff --git a/test/cmdlineTests/asm_json_import_invalid_data_no_hex/args b/test/cmdlineTests/asm_json_import_invalid_data_no_hex/args new file mode 100644 index 000000000..2b4b3a153 --- /dev/null +++ b/test/cmdlineTests/asm_json_import_invalid_data_no_hex/args @@ -0,0 +1 @@ +--import-asm-json - --opcodes --asm diff --git a/test/cmdlineTests/asm_json_import_invalid_data_no_hex/err b/test/cmdlineTests/asm_json_import_invalid_data_no_hex/err new file mode 100644 index 000000000..a28903be7 --- /dev/null +++ b/test/cmdlineTests/asm_json_import_invalid_data_no_hex/err @@ -0,0 +1 @@ +Assembly Import Error: Member '.data' contains a value for '0' that is not a valid hexadecimal string. diff --git a/test/cmdlineTests/asm_json_import_invalid_data_no_hex/exit b/test/cmdlineTests/asm_json_import_invalid_data_no_hex/exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/test/cmdlineTests/asm_json_import_invalid_data_no_hex/exit @@ -0,0 +1 @@ +1 diff --git a/test/cmdlineTests/asm_json_import_invalid_data_no_hex/stdin b/test/cmdlineTests/asm_json_import_invalid_data_no_hex/stdin new file mode 100644 index 000000000..4b5fdd8f9 --- /dev/null +++ b/test/cmdlineTests/asm_json_import_invalid_data_no_hex/stdin @@ -0,0 +1,11 @@ +{ + ".code": [ + { + "name": "PUSH", + "value": "0" + } + ], + ".data": { + "0": "no-hex-string" + } +} diff --git a/test/cmdlineTests/asm_json_import_invalid_data_no_object/args b/test/cmdlineTests/asm_json_import_invalid_data_no_object/args new file mode 100644 index 000000000..2b4b3a153 --- /dev/null +++ b/test/cmdlineTests/asm_json_import_invalid_data_no_object/args @@ -0,0 +1 @@ +--import-asm-json - --opcodes --asm diff --git a/test/cmdlineTests/asm_json_import_invalid_data_no_object/err b/test/cmdlineTests/asm_json_import_invalid_data_no_object/err new file mode 100644 index 000000000..9192c875e --- /dev/null +++ b/test/cmdlineTests/asm_json_import_invalid_data_no_object/err @@ -0,0 +1 @@ +Assembly Import Error: Key inside '.data' '0' can only be a valid hex-string or an object. diff --git a/test/cmdlineTests/asm_json_import_invalid_data_no_object/exit b/test/cmdlineTests/asm_json_import_invalid_data_no_object/exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/test/cmdlineTests/asm_json_import_invalid_data_no_object/exit @@ -0,0 +1 @@ +1 diff --git a/test/cmdlineTests/asm_json_import_invalid_data_no_object/stdin b/test/cmdlineTests/asm_json_import_invalid_data_no_object/stdin new file mode 100644 index 000000000..d7f976ac6 --- /dev/null +++ b/test/cmdlineTests/asm_json_import_invalid_data_no_object/stdin @@ -0,0 +1,16 @@ +{ + ".code": [ + { + "name": "PUSH", + "value": "0" + } + ], + ".data": { + "0": [ + 0, + 1, + 2, + 3 + ] + } +} diff --git a/test/cmdlineTests/asm_json_import_invalid_jumptype_instruction/args b/test/cmdlineTests/asm_json_import_invalid_jumptype_instruction/args new file mode 100644 index 000000000..2b4b3a153 --- /dev/null +++ b/test/cmdlineTests/asm_json_import_invalid_jumptype_instruction/args @@ -0,0 +1 @@ +--import-asm-json - --opcodes --asm diff --git a/test/cmdlineTests/asm_json_import_invalid_jumptype_instruction/err b/test/cmdlineTests/asm_json_import_invalid_jumptype_instruction/err new file mode 100644 index 000000000..183518103 --- /dev/null +++ b/test/cmdlineTests/asm_json_import_invalid_jumptype_instruction/err @@ -0,0 +1 @@ +Assembly Import Error: Member 'jumpType' set on instruction different from JUMP or JUMPI (was set on instruction 'PUSH') diff --git a/test/cmdlineTests/asm_json_import_invalid_jumptype_instruction/exit b/test/cmdlineTests/asm_json_import_invalid_jumptype_instruction/exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/test/cmdlineTests/asm_json_import_invalid_jumptype_instruction/exit @@ -0,0 +1 @@ +1 diff --git a/test/cmdlineTests/asm_json_import_invalid_jumptype_instruction/stdin b/test/cmdlineTests/asm_json_import_invalid_jumptype_instruction/stdin new file mode 100644 index 000000000..923ce3ece --- /dev/null +++ b/test/cmdlineTests/asm_json_import_invalid_jumptype_instruction/stdin @@ -0,0 +1,9 @@ +{ + ".code": [ + { + "name": "PUSH", + "value": "0", + "jumpType": "[in]" + } + ] +} diff --git a/test/cmdlineTests/asm_json_import_invalid_value/args b/test/cmdlineTests/asm_json_import_invalid_value/args new file mode 100644 index 000000000..2b4b3a153 --- /dev/null +++ b/test/cmdlineTests/asm_json_import_invalid_value/args @@ -0,0 +1 @@ +--import-asm-json - --opcodes --asm diff --git a/test/cmdlineTests/asm_json_import_invalid_value/err b/test/cmdlineTests/asm_json_import_invalid_value/err new file mode 100644 index 000000000..c9fdeec82 --- /dev/null +++ b/test/cmdlineTests/asm_json_import_invalid_value/err @@ -0,0 +1 @@ +Assembly Import Error: Member 'value' defined for instruction 'DIFFICULTY', but the instruction does not need a value. diff --git a/test/cmdlineTests/asm_json_import_invalid_value/exit b/test/cmdlineTests/asm_json_import_invalid_value/exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/test/cmdlineTests/asm_json_import_invalid_value/exit @@ -0,0 +1 @@ +1 diff --git a/test/cmdlineTests/asm_json_import_invalid_value/stdin b/test/cmdlineTests/asm_json_import_invalid_value/stdin new file mode 100644 index 000000000..e8da44996 --- /dev/null +++ b/test/cmdlineTests/asm_json_import_invalid_value/stdin @@ -0,0 +1,8 @@ +{ + ".code": [ + { + "name": "DIFFICULTY", + "value": "0" + } + ] +} diff --git a/test/cmdlineTests/asm_json_import_no_optimiser/args b/test/cmdlineTests/asm_json_import_no_optimiser/args new file mode 100644 index 000000000..f649e9740 --- /dev/null +++ b/test/cmdlineTests/asm_json_import_no_optimiser/args @@ -0,0 +1 @@ +--optimize --import-asm-json - --opcodes --asm diff --git a/test/cmdlineTests/asm_json_import_no_optimiser/err b/test/cmdlineTests/asm_json_import_no_optimiser/err new file mode 100644 index 000000000..f9f4475ca --- /dev/null +++ b/test/cmdlineTests/asm_json_import_no_optimiser/err @@ -0,0 +1 @@ +Option --optimize is not supported with --import-asm-json. diff --git a/test/cmdlineTests/asm_json_import_no_optimiser/exit b/test/cmdlineTests/asm_json_import_no_optimiser/exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/test/cmdlineTests/asm_json_import_no_optimiser/exit @@ -0,0 +1 @@ +1 diff --git a/test/cmdlineTests/asm_json_import_no_optimiser/stdin b/test/cmdlineTests/asm_json_import_no_optimiser/stdin new file mode 100644 index 000000000..70d8d364e --- /dev/null +++ b/test/cmdlineTests/asm_json_import_no_optimiser/stdin @@ -0,0 +1,6 @@ +{ + ".code": [ + { "name": "DIFFICULTY" }, + { "name": "PREVRANDAO" } + ] +} diff --git a/test/cmdlineTests/asm_json_import_no_value/args b/test/cmdlineTests/asm_json_import_no_value/args new file mode 100644 index 000000000..2b4b3a153 --- /dev/null +++ b/test/cmdlineTests/asm_json_import_no_value/args @@ -0,0 +1 @@ +--import-asm-json - --opcodes --asm diff --git a/test/cmdlineTests/asm_json_import_no_value/err b/test/cmdlineTests/asm_json_import_no_value/err new file mode 100644 index 000000000..d229e07d3 --- /dev/null +++ b/test/cmdlineTests/asm_json_import_no_value/err @@ -0,0 +1 @@ +Assembly Import Error: Member 'value' was not defined for instruction 'PUSH', but the instruction needs a value. diff --git a/test/cmdlineTests/asm_json_import_no_value/exit b/test/cmdlineTests/asm_json_import_no_value/exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/test/cmdlineTests/asm_json_import_no_value/exit @@ -0,0 +1 @@ +1 diff --git a/test/cmdlineTests/asm_json_import_no_value/stdin b/test/cmdlineTests/asm_json_import_no_value/stdin new file mode 100644 index 000000000..5556712bd --- /dev/null +++ b/test/cmdlineTests/asm_json_import_no_value/stdin @@ -0,0 +1,5 @@ +{ + ".code": [ + { "name": "PUSH" } + ] +} diff --git a/test/cmdlineTests/asm_json_import_non_unique_sources/args b/test/cmdlineTests/asm_json_import_non_unique_sources/args new file mode 100644 index 000000000..d27cc7bb2 --- /dev/null +++ b/test/cmdlineTests/asm_json_import_non_unique_sources/args @@ -0,0 +1 @@ +--asm-json --import-asm-json - diff --git a/test/cmdlineTests/asm_json_import_non_unique_sources/err b/test/cmdlineTests/asm_json_import_non_unique_sources/err new file mode 100644 index 000000000..5ba74fc8a --- /dev/null +++ b/test/cmdlineTests/asm_json_import_non_unique_sources/err @@ -0,0 +1 @@ +Assembly Import Error: Items in 'sourceList' array are not unique. diff --git a/test/cmdlineTests/asm_json_import_non_unique_sources/exit b/test/cmdlineTests/asm_json_import_non_unique_sources/exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/test/cmdlineTests/asm_json_import_non_unique_sources/exit @@ -0,0 +1 @@ +1 diff --git a/test/cmdlineTests/asm_json_import_non_unique_sources/stdin b/test/cmdlineTests/asm_json_import_non_unique_sources/stdin new file mode 100644 index 000000000..8264c0c1d --- /dev/null +++ b/test/cmdlineTests/asm_json_import_non_unique_sources/stdin @@ -0,0 +1,23 @@ +{ + ".code": [ + { + "name": "PUSH", + "value": "0" + } + ], + ".data": { + "0": { + ".code": [ + { + "name": "PUSH", + "value": "1" + } + ] + } + }, + "sourceList": [ + "contract.sol", + "contract.sol", + "#utility.yul" + ] +} diff --git a/test/cmdlineTests/asm_json_import_other_fields/args b/test/cmdlineTests/asm_json_import_other_fields/args new file mode 100644 index 000000000..2b4b3a153 --- /dev/null +++ b/test/cmdlineTests/asm_json_import_other_fields/args @@ -0,0 +1 @@ +--import-asm-json - --opcodes --asm diff --git a/test/cmdlineTests/asm_json_import_other_fields/err b/test/cmdlineTests/asm_json_import_other_fields/err new file mode 100644 index 000000000..bcbfd631c --- /dev/null +++ b/test/cmdlineTests/asm_json_import_other_fields/err @@ -0,0 +1 @@ +Assembly Import Error: Unknown member '_name'. Valid members are begin, end, jumpType, modifierDepth, name, source, value. diff --git a/test/cmdlineTests/asm_json_import_other_fields/exit b/test/cmdlineTests/asm_json_import_other_fields/exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/test/cmdlineTests/asm_json_import_other_fields/exit @@ -0,0 +1 @@ +1 diff --git a/test/cmdlineTests/asm_json_import_other_fields/stdin b/test/cmdlineTests/asm_json_import_other_fields/stdin new file mode 100644 index 000000000..bb82f2de0 --- /dev/null +++ b/test/cmdlineTests/asm_json_import_other_fields/stdin @@ -0,0 +1,5 @@ +{ + ".code": [ + { "_name": "DIFFICULTY" } + ] +} diff --git a/test/cmdlineTests/asm_json_import_untagged_jumpdest/args b/test/cmdlineTests/asm_json_import_untagged_jumpdest/args new file mode 100644 index 000000000..2b4b3a153 --- /dev/null +++ b/test/cmdlineTests/asm_json_import_untagged_jumpdest/args @@ -0,0 +1 @@ +--import-asm-json - --opcodes --asm diff --git a/test/cmdlineTests/asm_json_import_untagged_jumpdest/err b/test/cmdlineTests/asm_json_import_untagged_jumpdest/err new file mode 100644 index 000000000..ff4cd27bc --- /dev/null +++ b/test/cmdlineTests/asm_json_import_untagged_jumpdest/err @@ -0,0 +1 @@ +Assembly Import Error: JUMPDEST instruction without a tag diff --git a/test/cmdlineTests/asm_json_import_untagged_jumpdest/exit b/test/cmdlineTests/asm_json_import_untagged_jumpdest/exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/test/cmdlineTests/asm_json_import_untagged_jumpdest/exit @@ -0,0 +1 @@ +1 diff --git a/test/cmdlineTests/asm_json_import_untagged_jumpdest/stdin b/test/cmdlineTests/asm_json_import_untagged_jumpdest/stdin new file mode 100644 index 000000000..a40284cdb --- /dev/null +++ b/test/cmdlineTests/asm_json_import_untagged_jumpdest/stdin @@ -0,0 +1,10 @@ +{ + ".code": [ + { + "name": "tag", + "value": "0x00" + }, + { "name": "JUMPDEST" }, + { "name": "JUMPDEST" } + ] +} diff --git a/test/cmdlineTests/asm_json_import_verbatim/args b/test/cmdlineTests/asm_json_import_verbatim/args new file mode 100644 index 000000000..2b4b3a153 --- /dev/null +++ b/test/cmdlineTests/asm_json_import_verbatim/args @@ -0,0 +1 @@ +--import-asm-json - --opcodes --asm diff --git a/test/cmdlineTests/asm_json_import_verbatim/output b/test/cmdlineTests/asm_json_import_verbatim/output new file mode 100644 index 000000000..cadab413f --- /dev/null +++ b/test/cmdlineTests/asm_json_import_verbatim/output @@ -0,0 +1,58 @@ +Opcodes: +PUSH0 CALLDATALOAD PUSH1 0x14 DUP1 DUP3 SSTORE PUSH1 0x20 CALLDATALOAD ISZERO PUSH1 0x1C JUMPI DUP1 DUP3 SSTORE PUSH0 DUP1 PUSH0 DUP1 PUSH0 DUP1 STATICCALL POP PUSH25 0x797A5B80825550500000000000000000000000000000000000 +EVM assembly: + /* "":28:29 b */ + 0x00 + /* "":15:30 {... */ + calldataload + /* "":44:46 */ + 0x14 + /* "":61:62 */ + dup1 + /* "":58:59 */ + dup3 + /* "":51:63 : 29,... */ + sstore + /* "":84:86 " */ + 0x20 + /* "":71:87 "PUSH",... */ + calldataload + /* "":68:188 ": "PUSH",... */ + iszero + tag_1 + jumpi + /* "":108:109 u */ + dup1 + /* "":105:106 v */ + dup3 + /* "":98:110 "value */ + sstore + /* "":149:150 */ + 0x00 + /* "":146:147 5 */ + dup1 + /* "":143:144 : */ + 0x00 + /* "":140:141 i */ + dup1 + /* "":137:138 b */ + 0x00 + /* "":134:135 */ + dup1 + /* "":123:151 ... */ + staticcall + /* "":119:152 },... */ + pop + /* "":161:182 30,... */ + verbatimbytecode_78797a + /* "":68:188 ": "PUSH",... */ +tag_1: + /* "":203:204 s */ + dup1 + /* "":200:201 */ + dup3 + /* "":193:205 ",... */ + sstore + /* "":0:207 {... */ + pop + pop diff --git a/test/cmdlineTests/asm_json_import_verbatim/stdin b/test/cmdlineTests/asm_json_import_verbatim/stdin new file mode 100644 index 000000000..8c1d7300e --- /dev/null +++ b/test/cmdlineTests/asm_json_import_verbatim/stdin @@ -0,0 +1,196 @@ +{ + ".code": [ + { + "begin": 28, + "end": 29, + "name": "PUSH", + "source": 0, + "value": "0" + }, + { + "begin": 15, + "end": 30, + "name": "CALLDATALOAD", + "source": 0 + }, + { + "begin": 44, + "end": 46, + "name": "PUSH", + "source": 0, + "value": "14" + }, + { + "begin": 61, + "end": 62, + "name": "DUP1", + "source": 0 + }, + { + "begin": 58, + "end": 59, + "name": "DUP3", + "source": 0 + }, + { + "begin": 51, + "end": 63, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 84, + "end": 86, + "name": "PUSH", + "source": 0, + "value": "20" + }, + { + "begin": 71, + "end": 87, + "name": "CALLDATALOAD", + "source": 0 + }, + { + "begin": 68, + "end": 188, + "name": "ISZERO", + "source": 0 + }, + { + "begin": 68, + "end": 188, + "name": "PUSH [tag]", + "source": 0, + "value": "1" + }, + { + "begin": 68, + "end": 188, + "name": "JUMPI", + "source": 0 + }, + { + "begin": 108, + "end": 109, + "name": "DUP1", + "source": 0 + }, + { + "begin": 105, + "end": 106, + "name": "DUP3", + "source": 0 + }, + { + "begin": 98, + "end": 110, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 149, + "end": 150, + "name": "PUSH", + "source": 0, + "value": "0" + }, + { + "begin": 146, + "end": 147, + "name": "DUP1", + "source": 0 + }, + { + "begin": 143, + "end": 144, + "name": "PUSH", + "source": 0, + "value": "0" + }, + { + "begin": 140, + "end": 141, + "name": "DUP1", + "source": 0 + }, + { + "begin": 137, + "end": 138, + "name": "PUSH", + "source": 0, + "value": "0" + }, + { + "begin": 134, + "end": 135, + "name": "DUP1", + "source": 0 + }, + { + "begin": 123, + "end": 151, + "name": "STATICCALL", + "source": 0 + }, + { + "begin": 119, + "end": 152, + "name": "POP", + "source": 0 + }, + { + "begin": 161, + "end": 182, + "name": "VERBATIM", + "source": 0, + "value": "78797a" + }, + { + "begin": 68, + "end": 188, + "name": "tag", + "source": 0, + "value": "1" + }, + { + "begin": 68, + "end": 188, + "name": "JUMPDEST", + "source": 0 + }, + { + "begin": 203, + "end": 204, + "name": "DUP1", + "source": 0 + }, + { + "begin": 200, + "end": 201, + "name": "DUP3", + "source": 0 + }, + { + "begin": 193, + "end": 205, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 0, + "end": 207, + "name": "POP", + "source": 0 + }, + { + "begin": 0, + "end": 207, + "name": "POP", + "source": 0 + } + ], + "sourceList": [ + "" + ] +} diff --git a/test/cmdlineTests/asm_json_import_yul_more_subobjects/args b/test/cmdlineTests/asm_json_import_yul_more_subobjects/args new file mode 100644 index 000000000..58dfc8cc7 --- /dev/null +++ b/test/cmdlineTests/asm_json_import_yul_more_subobjects/args @@ -0,0 +1 @@ +--import-asm-json - --opcodes diff --git a/test/cmdlineTests/asm_json_import_yul_more_subobjects/output b/test/cmdlineTests/asm_json_import_yul_more_subobjects/output new file mode 100644 index 000000000..81aa5b938 --- /dev/null +++ b/test/cmdlineTests/asm_json_import_yul_more_subobjects/output @@ -0,0 +1,2 @@ +Opcodes: +PUSH1 0x1E PUSH0 SSTORE PUSH1 0x1A PUSH1 0x1 SSTORE PUSH1 0x15 PUSH1 0x2 SSTORE PUSH1 0x1 PUSH1 0x3 SSTORE PUSH1 0x1 PUSH1 0x4 SSTORE PUSH1 0x1 PUSH1 0x5 SSTORE INVALID diff --git a/test/cmdlineTests/asm_json_import_yul_more_subobjects/stdin b/test/cmdlineTests/asm_json_import_yul_more_subobjects/stdin new file mode 100644 index 000000000..9d2f37aa6 --- /dev/null +++ b/test/cmdlineTests/asm_json_import_yul_more_subobjects/stdin @@ -0,0 +1,368 @@ +{ + ".code": + [ + { + "begin": 37, + "end": 51, + "name": "PUSHSIZE", + "source": 0 + }, + { + "begin": 34, + "end": 35, + "name": "PUSH", + "source": 0, + "value": "0" + }, + { + "begin": 27, + "end": 52, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 67, + "end": 81, + "name": "PUSH #[$]", + "source": 0, + "value": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "begin": 64, + "end": 65, + "name": "PUSH", + "source": 0, + "value": "1" + }, + { + "begin": 57, + "end": 82, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 97, + "end": 114, + "name": "PUSH #[$]", + "source": 0, + "value": "000000000000000000000000000000000000000000000000ffffffffffffffff" + }, + { + "begin": 94, + "end": 95, + "name": "PUSH", + "source": 0, + "value": "2" + }, + { + "begin": 87, + "end": 115, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 130, + "end": 152, + "name": "PUSH #[$]", + "source": 0, + "value": "000000000000000000000000000000000000000000000000fffffffffffffffe" + }, + { + "begin": 127, + "end": 128, + "name": "PUSH", + "source": 0, + "value": "3" + }, + { + "begin": 120, + "end": 153, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 168, + "end": 190, + "name": "PUSH #[$]", + "source": 0, + "value": "000000000000000000000000000000000000000000000000fffffffffffffffd" + }, + { + "begin": 165, + "end": 166, + "name": "PUSH", + "source": 0, + "value": "4" + }, + { + "begin": 158, + "end": 191, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 206, + "end": 228, + "name": "PUSH #[$]", + "source": 0, + "value": "000000000000000000000000000000000000000000000000fffffffffffffffc" + }, + { + "begin": 203, + "end": 204, + "name": "PUSH", + "source": 0, + "value": "5" + }, + { + "begin": 196, + "end": 229, + "name": "SSTORE", + "source": 0 + } + ], + ".data": + { + "0": + { + ".code": + [ + { + "begin": 278, + "end": 292, + "name": "PUSHSIZE", + "source": 0 + }, + { + "begin": 275, + "end": 276, + "name": "PUSH", + "source": 0, + "value": "6" + }, + { + "begin": 268, + "end": 293, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 310, + "end": 324, + "name": "PUSH #[$]", + "source": 0, + "value": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "begin": 307, + "end": 308, + "name": "PUSH", + "source": 0, + "value": "7" + }, + { + "begin": 300, + "end": 325, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 342, + "end": 361, + "name": "PUSH #[$]", + "source": 0, + "value": "000000000000000000000000000000000000000000000000ffffffffffffffff" + }, + { + "begin": 339, + "end": 340, + "name": "PUSH", + "source": 0, + "value": "8" + }, + { + "begin": 332, + "end": 362, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 379, + "end": 398, + "name": "PUSH #[$]", + "source": 0, + "value": "000000000000000000000000000000000000000000000000fffffffffffffffe" + }, + { + "begin": 376, + "end": 377, + "name": "PUSH", + "source": 0, + "value": "9" + }, + { + "begin": 369, + "end": 399, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 417, + "end": 436, + "name": "PUSH #[$]", + "source": 0, + "value": "000000000000000000000000000000000000000000000000fffffffffffffffd" + }, + { + "begin": 413, + "end": 415, + "name": "PUSH", + "source": 0, + "value": "A" + }, + { + "begin": 406, + "end": 437, + "name": "SSTORE", + "source": 0 + } + ], + "index": 0, + ".data": + { + "0": + { + ".code": + [ + { + "begin": 494, + "end": 508, + "name": "PUSHSIZE", + "source": 0 + }, + { + "begin": 490, + "end": 492, + "name": "PUSH", + "source": 0, + "value": "B" + }, + { + "begin": 483, + "end": 509, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 529, + "end": 545, + "name": "PUSH #[$]", + "source": 0, + "value": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "begin": 525, + "end": 527, + "name": "PUSH", + "source": 0, + "value": "C" + }, + { + "begin": 518, + "end": 546, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 566, + "end": 582, + "name": "PUSH #[$]", + "source": 0, + "value": "0000000000000000000000000000000000000000000000000000000000000001" + }, + { + "begin": 562, + "end": 564, + "name": "PUSH", + "source": 0, + "value": "D" + }, + { + "begin": 555, + "end": 583, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 603, + "end": 619, + "name": "PUSH #[$]", + "source": 0, + "value": "0000000000000000000000000000000000000000000000000000000000000002" + }, + { + "begin": 599, + "end": 601, + "name": "PUSH", + "source": 0, + "value": "E" + }, + { + "begin": 592, + "end": 620, + "name": "SSTORE", + "source": 0 + } + ], + "index": 0, + ".data": + { + "0": + { + ".code": + [ + { + "begin": 676, + "end": 685, + "name": "INVALID", + "source": 0 + } + ], + "index": 0 + }, + "1": + { + ".code": + [ + { + "begin": 751, + "end": 760, + "name": "INVALID", + "source": 0 + } + ], + "index": 1 + }, + "2": + { + ".code": + [ + { + "begin": 826, + "end": 835, + "name": "INVALID", + "source": 0 + } + ], + "index": 2 + } + } + } + } + } + }, + "sourceList": + [ + "" + ] +} diff --git a/test/cmdlineTests/asm_json_import_yul_subobjects/args b/test/cmdlineTests/asm_json_import_yul_subobjects/args new file mode 100644 index 000000000..58dfc8cc7 --- /dev/null +++ b/test/cmdlineTests/asm_json_import_yul_subobjects/args @@ -0,0 +1 @@ +--import-asm-json - --opcodes diff --git a/test/cmdlineTests/asm_json_import_yul_subobjects/output b/test/cmdlineTests/asm_json_import_yul_subobjects/output new file mode 100644 index 000000000..6aa2d0f64 --- /dev/null +++ b/test/cmdlineTests/asm_json_import_yul_subobjects/output @@ -0,0 +1,2 @@ +Opcodes: +PUSH0 DUP1 SSTORE PUSH1 0x6A PUSH1 0x1 SSTORE PUSH1 0x31 PUSH1 0x2 SSTORE PUSH1 0x2C PUSH1 0x3 SSTORE PUSH1 0x5E PUSH1 0x4 SSTORE PUSH1 0xC PUSH1 0x5 SSTORE PUSH1 0x5D PUSH1 0x6 SSTORE PUSH1 0x1 PUSH1 0x7 SSTORE PUSH1 0x5D PUSH1 0x8 SSTORE PUSH1 0x1 PUSH1 0x9 SSTORE INVALID PUSH1 0x1F PUSH1 0xA SSTORE PUSH1 0xC PUSH1 0xB SSTORE PUSH1 0x2B PUSH1 0xC SSTORE PUSH1 0x1 PUSH1 0xD SSTORE PUSH1 0x2B PUSH1 0xE SSTORE PUSH1 0x1 PUSH1 0xF SSTORE INVALID PUSH1 0xB PUSH1 0x10 SSTORE PUSH1 0x1 PUSH1 0x11 SSTORE INVALID INVALID INVALID INVALID PUSH1 0xB PUSH1 0x10 SSTORE PUSH1 0x1 PUSH1 0x11 SSTORE INVALID INVALID diff --git a/test/cmdlineTests/asm_json_import_yul_subobjects/stdin b/test/cmdlineTests/asm_json_import_yul_subobjects/stdin new file mode 100644 index 000000000..a50e4a4e5 --- /dev/null +++ b/test/cmdlineTests/asm_json_import_yul_subobjects/stdin @@ -0,0 +1,417 @@ +{ + ".code": + [ + { + "begin": 36, + "end": 51, + "name": "PUSH", + "source": 0, + "value": "0" + }, + { + "begin": 33, + "end": 34, + "name": "DUP1", + "source": 0 + }, + { + "begin": 26, + "end": 52, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 67, + "end": 80, + "name": "PUSHSIZE", + "source": 0 + }, + { + "begin": 64, + "end": 65, + "name": "PUSH", + "source": 0, + "value": "1" + }, + { + "begin": 57, + "end": 81, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 96, + "end": 111, + "name": "PUSH [$]", + "source": 0, + "value": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "begin": 93, + "end": 94, + "name": "PUSH", + "source": 0, + "value": "2" + }, + { + "begin": 86, + "end": 112, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 127, + "end": 140, + "name": "PUSH #[$]", + "source": 0, + "value": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "begin": 124, + "end": 125, + "name": "PUSH", + "source": 0, + "value": "3" + }, + { + "begin": 117, + "end": 141, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 156, + "end": 173, + "name": "PUSH [$]", + "source": 0, + "value": "000000000000000000000000000000000000000000000000ffffffffffffffff" + }, + { + "begin": 153, + "end": 154, + "name": "PUSH", + "source": 0, + "value": "4" + }, + { + "begin": 146, + "end": 174, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 189, + "end": 204, + "name": "PUSH #[$]", + "source": 0, + "value": "000000000000000000000000000000000000000000000000ffffffffffffffff" + }, + { + "begin": 186, + "end": 187, + "name": "PUSH", + "source": 0, + "value": "5" + }, + { + "begin": 179, + "end": 205, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 220, + "end": 237, + "name": "PUSH [$]", + "source": 0, + "value": "000000000000000000000000000000000000000000000000fffffffffffffffe" + }, + { + "begin": 217, + "end": 218, + "name": "PUSH", + "source": 0, + "value": "6" + }, + { + "begin": 210, + "end": 238, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 253, + "end": 268, + "name": "PUSH #[$]", + "source": 0, + "value": "000000000000000000000000000000000000000000000000fffffffffffffffe" + }, + { + "begin": 250, + "end": 251, + "name": "PUSH", + "source": 0, + "value": "7" + }, + { + "begin": 243, + "end": 269, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 284, + "end": 303, + "name": "PUSH [$]", + "source": 0, + "value": "000000000000000000000000000000000000000000000000fffffffffffffffd" + }, + { + "begin": 281, + "end": 282, + "name": "PUSH", + "source": 0, + "value": "8" + }, + { + "begin": 274, + "end": 304, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 319, + "end": 336, + "name": "PUSH #[$]", + "source": 0, + "value": "000000000000000000000000000000000000000000000000fffffffffffffffd" + }, + { + "begin": 316, + "end": 317, + "name": "PUSH", + "source": 0, + "value": "9" + }, + { + "begin": 309, + "end": 337, + "name": "SSTORE", + "source": 0 + } + ], + ".data": + { + "0": + { + ".code": + [ + { + "begin": 418, + "end": 433, + "name": "PUSH [$]", + "source": 0, + "value": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "begin": 414, + "end": 416, + "name": "PUSH", + "source": 0, + "value": "A" + }, + { + "begin": 407, + "end": 434, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 452, + "end": 465, + "name": "PUSH #[$]", + "source": 0, + "value": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "begin": 448, + "end": 450, + "name": "PUSH", + "source": 0, + "value": "B" + }, + { + "begin": 441, + "end": 466, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 484, + "end": 499, + "name": "PUSH [$]", + "source": 0, + "value": "0000000000000000000000000000000000000000000000000000000000000001" + }, + { + "begin": 480, + "end": 482, + "name": "PUSH", + "source": 0, + "value": "C" + }, + { + "begin": 473, + "end": 500, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 518, + "end": 531, + "name": "PUSH #[$]", + "source": 0, + "value": "0000000000000000000000000000000000000000000000000000000000000001" + }, + { + "begin": 514, + "end": 516, + "name": "PUSH", + "source": 0, + "value": "D" + }, + { + "begin": 507, + "end": 532, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 550, + "end": 567, + "name": "PUSH [$]", + "source": 0, + "value": "000000000000000000000000000000000000000000000000ffffffffffffffff" + }, + { + "begin": 546, + "end": 548, + "name": "PUSH", + "source": 0, + "value": "E" + }, + { + "begin": 539, + "end": 568, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 586, + "end": 601, + "name": "PUSH #[$]", + "source": 0, + "value": "000000000000000000000000000000000000000000000000ffffffffffffffff" + }, + { + "begin": 582, + "end": 584, + "name": "PUSH", + "source": 0, + "value": "F" + }, + { + "begin": 575, + "end": 602, + "name": "SSTORE", + "source": 0 + } + ], + "index": 0, + ".data": + { + "0": + { + ".code": + [ + { + "begin": 658, + "end": 673, + "name": "PUSH [$]", + "source": 0, + "value": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "begin": 654, + "end": 656, + "name": "PUSH", + "source": 0, + "value": "10" + }, + { + "begin": 647, + "end": 674, + "name": "SSTORE", + "source": 0 + }, + { + "begin": 694, + "end": 707, + "name": "PUSH #[$]", + "source": 0, + "value": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "begin": 690, + "end": 692, + "name": "PUSH", + "source": 0, + "value": "11" + }, + { + "begin": 683, + "end": 708, + "name": "SSTORE", + "source": 0 + } + ], + "index": 0, + ".data": + { + "0": + { + ".code": + [ + { + "begin": 761, + "end": 770, + "name": "INVALID", + "source": 0 + } + ], + "index": 0 + } + } + }, + "1": + { + ".code": + [ + { + "begin": 833, + "end": 842, + "name": "INVALID", + "source": 0 + } + ], + "index": 1 + } + } + }, + "ACAF3289D7B601CBD114FB36C4D29C85BBFD5E133F14CB355C3FD8D99367964F": "48656c6c6f2c20576f726c6421" + }, + "sourceList": + [ + "" + ] +} diff --git a/test/cmdlineTests/asm_json_no_pretty_print/output b/test/cmdlineTests/asm_json_no_pretty_print/output index b713097bb..893b6a222 100644 --- a/test/cmdlineTests/asm_json_no_pretty_print/output +++ b/test/cmdlineTests/asm_json_no_pretty_print/output @@ -1,4 +1,4 @@ ======= asm_json_no_pretty_print/input.sol:C ======= EVM assembly: -{".code":[{"begin":60,"end":160,"name":"PUSH","source":0,"value":"80"},{"begin":60,"end":160,"name":"PUSH","source":0,"value":"40"},{"begin":60,"end":160,"name":"MSTORE","source":0},{"begin":60,"end":160,"name":"CALLVALUE","source":0},{"begin":60,"end":160,"name":"DUP1","source":0},{"begin":60,"end":160,"name":"ISZERO","source":0},{"begin":60,"end":160,"name":"PUSH [tag]","source":0,"value":"1"},{"begin":60,"end":160,"name":"JUMPI","source":0},{"begin":60,"end":160,"name":"PUSH","source":0,"value":"0"},{"begin":60,"end":160,"name":"DUP1","source":0},{"begin":60,"end":160,"name":"REVERT","source":0},{"begin":60,"end":160,"name":"tag","source":0,"value":"1"},{"begin":60,"end":160,"name":"JUMPDEST","source":0},{"begin":60,"end":160,"name":"POP","source":0},{"begin":60,"end":160,"name":"PUSH #[$]","source":0,"value":"0000000000000000000000000000000000000000000000000000000000000000"},{"begin":60,"end":160,"name":"DUP1","source":0},{"begin":60,"end":160,"name":"PUSH [$]","source":0,"value":"0000000000000000000000000000000000000000000000000000000000000000"},{"begin":60,"end":160,"name":"PUSH","source":0,"value":"0"},{"begin":60,"end":160,"name":"CODECOPY","source":0},{"begin":60,"end":160,"name":"PUSH","source":0,"value":"0"},{"begin":60,"end":160,"name":"RETURN","source":0}],".data":{"0":{".auxdata":"",".code":[{"begin":60,"end":160,"name":"PUSH","source":0,"value":"80"},{"begin":60,"end":160,"name":"PUSH","source":0,"value":"40"},{"begin":60,"end":160,"name":"MSTORE","source":0},{"begin":60,"end":160,"name":"CALLVALUE","source":0},{"begin":60,"end":160,"name":"DUP1","source":0},{"begin":60,"end":160,"name":"ISZERO","source":0},{"begin":60,"end":160,"name":"PUSH [tag]","source":0,"value":"1"},{"begin":60,"end":160,"name":"JUMPI","source":0},{"begin":60,"end":160,"name":"PUSH","source":0,"value":"0"},{"begin":60,"end":160,"name":"DUP1","source":0},{"begin":60,"end":160,"name":"REVERT","source":0},{"begin":60,"end":160,"name":"tag","source":0,"value":"1"},{"begin":60,"end":160,"name":"JUMPDEST","source":0},{"begin":60,"end":160,"name":"POP","source":0},{"begin":60,"end":160,"name":"PUSH","source":0,"value":"4"},{"begin":60,"end":160,"name":"CALLDATASIZE","source":0},{"begin":60,"end":160,"name":"LT","source":0},{"begin":60,"end":160,"name":"PUSH [tag]","source":0,"value":"2"},{"begin":60,"end":160,"name":"JUMPI","source":0},{"begin":60,"end":160,"name":"PUSH","source":0,"value":"0"},{"begin":60,"end":160,"name":"CALLDATALOAD","source":0},{"begin":60,"end":160,"name":"PUSH","source":0,"value":"E0"},{"begin":60,"end":160,"name":"SHR","source":0},{"begin":60,"end":160,"name":"DUP1","source":0},{"begin":60,"end":160,"name":"PUSH","source":0,"value":"B3DE648B"},{"begin":60,"end":160,"name":"EQ","source":0},{"begin":60,"end":160,"name":"PUSH [tag]","source":0,"value":"3"},{"begin":60,"end":160,"name":"JUMPI","source":0},{"begin":60,"end":160,"name":"tag","source":0,"value":"2"},{"begin":60,"end":160,"name":"JUMPDEST","source":0},{"begin":60,"end":160,"name":"PUSH","source":0,"value":"0"},{"begin":60,"end":160,"name":"DUP1","source":0},{"begin":60,"end":160,"name":"REVERT","source":0},{"begin":77,"end":158,"name":"tag","source":0,"value":"3"},{"begin":77,"end":158,"name":"JUMPDEST","source":0},{"begin":77,"end":158,"name":"PUSH [tag]","source":0,"value":"4"},{"begin":77,"end":158,"name":"PUSH","source":0,"value":"4"},{"begin":77,"end":158,"name":"DUP1","source":0},{"begin":77,"end":158,"name":"CALLDATASIZE","source":0},{"begin":77,"end":158,"name":"SUB","source":0},{"begin":77,"end":158,"name":"DUP2","source":0},{"begin":77,"end":158,"name":"ADD","source":0},{"begin":77,"end":158,"name":"SWAP1","source":0},{"begin":77,"end":158,"name":"PUSH [tag]","source":0,"value":"5"},{"begin":77,"end":158,"name":"SWAP2","source":0},{"begin":77,"end":158,"name":"SWAP1","source":0},{"begin":77,"end":158,"name":"PUSH [tag]","source":0,"value":"6"},{"begin":77,"end":158,"jumpType":"[in]","name":"JUMP","source":0},{"begin":77,"end":158,"name":"tag","source":0,"value":"5"},{"begin":77,"end":158,"name":"JUMPDEST","source":0},{"begin":77,"end":158,"name":"PUSH [tag]","source":0,"value":"7"},{"begin":77,"end":158,"jumpType":"[in]","name":"JUMP","source":0},{"begin":77,"end":158,"name":"tag","source":0,"value":"4"},{"begin":77,"end":158,"name":"JUMPDEST","source":0},{"begin":77,"end":158,"name":"STOP","source":0},{"begin":77,"end":158,"name":"tag","source":0,"value":"7"},{"begin":77,"end":158,"name":"JUMPDEST","source":0},{"begin":123,"end":125,"name":"PUSH","source":0,"value":"2A"},{"begin":118,"end":125,"name":"DUP2","source":0},{"begin":118,"end":125,"name":"PUSH [tag]","source":0,"value":"9"},{"begin":118,"end":125,"name":"SWAP2","source":0},{"begin":118,"end":125,"name":"SWAP1","source":0},{"begin":118,"end":125,"name":"PUSH [tag]","source":0,"value":"10"},{"begin":118,"end":125,"jumpType":"[in]","name":"JUMP","source":0},{"begin":118,"end":125,"name":"tag","source":0,"value":"9"},{"begin":118,"end":125,"name":"JUMPDEST","source":0},{"begin":118,"end":125,"name":"SWAP1","source":0},{"begin":118,"end":125,"name":"POP","source":0},{"begin":147,"end":150,"name":"PUSH","source":0,"value":"64"},{"begin":143,"end":144,"name":"DUP2","source":0},{"begin":143,"end":150,"name":"GT","source":0},{"begin":135,"end":151,"name":"PUSH [tag]","source":0,"value":"11"},{"begin":135,"end":151,"name":"JUMPI","source":0},{"begin":135,"end":151,"name":"PUSH","source":0,"value":"0"},{"begin":135,"end":151,"name":"DUP1","source":0},{"begin":135,"end":151,"name":"REVERT","source":0},{"begin":135,"end":151,"name":"tag","source":0,"value":"11"},{"begin":135,"end":151,"name":"JUMPDEST","source":0},{"begin":77,"end":158,"name":"POP","source":0},{"begin":77,"end":158,"jumpType":"[out]","name":"JUMP","source":0},{"begin":88,"end":205,"name":"tag","source":1,"value":"13"},{"begin":88,"end":205,"name":"JUMPDEST","source":1},{"begin":197,"end":198,"name":"PUSH","source":1,"value":"0"},{"begin":194,"end":195,"name":"DUP1","source":1},{"begin":187,"end":199,"name":"REVERT","source":1},{"begin":334,"end":411,"name":"tag","source":1,"value":"15"},{"begin":334,"end":411,"name":"JUMPDEST","source":1},{"begin":371,"end":378,"name":"PUSH","source":1,"value":"0"},{"begin":400,"end":405,"name":"DUP2","source":1},{"begin":389,"end":405,"name":"SWAP1","source":1},{"begin":389,"end":405,"name":"POP","source":1},{"begin":334,"end":411,"name":"SWAP2","source":1},{"begin":334,"end":411,"name":"SWAP1","source":1},{"begin":334,"end":411,"name":"POP","source":1},{"begin":334,"end":411,"jumpType":"[out]","name":"JUMP","source":1},{"begin":417,"end":539,"name":"tag","source":1,"value":"16"},{"begin":417,"end":539,"name":"JUMPDEST","source":1},{"begin":490,"end":514,"name":"PUSH [tag]","source":1,"value":"25"},{"begin":508,"end":513,"name":"DUP2","source":1},{"begin":490,"end":514,"name":"PUSH [tag]","source":1,"value":"15"},{"begin":490,"end":514,"jumpType":"[in]","name":"JUMP","source":1},{"begin":490,"end":514,"name":"tag","source":1,"value":"25"},{"begin":490,"end":514,"name":"JUMPDEST","source":1},{"begin":483,"end":488,"name":"DUP2","source":1},{"begin":480,"end":515,"name":"EQ","source":1},{"begin":470,"end":533,"name":"PUSH [tag]","source":1,"value":"26"},{"begin":470,"end":533,"name":"JUMPI","source":1},{"begin":529,"end":530,"name":"PUSH","source":1,"value":"0"},{"begin":526,"end":527,"name":"DUP1","source":1},{"begin":519,"end":531,"name":"REVERT","source":1},{"begin":470,"end":533,"name":"tag","source":1,"value":"26"},{"begin":470,"end":533,"name":"JUMPDEST","source":1},{"begin":417,"end":539,"name":"POP","source":1},{"begin":417,"end":539,"jumpType":"[out]","name":"JUMP","source":1},{"begin":545,"end":684,"name":"tag","source":1,"value":"17"},{"begin":545,"end":684,"name":"JUMPDEST","source":1},{"begin":591,"end":596,"name":"PUSH","source":1,"value":"0"},{"begin":629,"end":635,"name":"DUP2","source":1},{"begin":616,"end":636,"name":"CALLDATALOAD","source":1},{"begin":607,"end":636,"name":"SWAP1","source":1},{"begin":607,"end":636,"name":"POP","source":1},{"begin":645,"end":678,"name":"PUSH [tag]","source":1,"value":"28"},{"begin":672,"end":677,"name":"DUP2","source":1},{"begin":645,"end":678,"name":"PUSH [tag]","source":1,"value":"16"},{"begin":645,"end":678,"jumpType":"[in]","name":"JUMP","source":1},{"begin":645,"end":678,"name":"tag","source":1,"value":"28"},{"begin":645,"end":678,"name":"JUMPDEST","source":1},{"begin":545,"end":684,"name":"SWAP3","source":1},{"begin":545,"end":684,"name":"SWAP2","source":1},{"begin":545,"end":684,"name":"POP","source":1},{"begin":545,"end":684,"name":"POP","source":1},{"begin":545,"end":684,"jumpType":"[out]","name":"JUMP","source":1},{"begin":690,"end":1019,"name":"tag","source":1,"value":"6"},{"begin":690,"end":1019,"name":"JUMPDEST","source":1},{"begin":749,"end":755,"name":"PUSH","source":1,"value":"0"},{"begin":798,"end":800,"name":"PUSH","source":1,"value":"20"},{"begin":786,"end":795,"name":"DUP3","source":1},{"begin":777,"end":784,"name":"DUP5","source":1},{"begin":773,"end":796,"name":"SUB","source":1},{"begin":769,"end":801,"name":"SLT","source":1},{"begin":766,"end":885,"name":"ISZERO","source":1},{"begin":766,"end":885,"name":"PUSH [tag]","source":1,"value":"30"},{"begin":766,"end":885,"name":"JUMPI","source":1},{"begin":804,"end":883,"name":"PUSH [tag]","source":1,"value":"31"},{"begin":804,"end":883,"name":"PUSH [tag]","source":1,"value":"13"},{"begin":804,"end":883,"jumpType":"[in]","name":"JUMP","source":1},{"begin":804,"end":883,"name":"tag","source":1,"value":"31"},{"begin":804,"end":883,"name":"JUMPDEST","source":1},{"begin":766,"end":885,"name":"tag","source":1,"value":"30"},{"begin":766,"end":885,"name":"JUMPDEST","source":1},{"begin":924,"end":925,"name":"PUSH","source":1,"value":"0"},{"begin":949,"end":1002,"name":"PUSH [tag]","source":1,"value":"32"},{"begin":994,"end":1001,"name":"DUP5","source":1},{"begin":985,"end":991,"name":"DUP3","source":1},{"begin":974,"end":983,"name":"DUP6","source":1},{"begin":970,"end":992,"name":"ADD","source":1},{"begin":949,"end":1002,"name":"PUSH [tag]","source":1,"value":"17"},{"begin":949,"end":1002,"jumpType":"[in]","name":"JUMP","source":1},{"begin":949,"end":1002,"name":"tag","source":1,"value":"32"},{"begin":949,"end":1002,"name":"JUMPDEST","source":1},{"begin":939,"end":1002,"name":"SWAP2","source":1},{"begin":939,"end":1002,"name":"POP","source":1},{"begin":895,"end":1012,"name":"POP","source":1},{"begin":690,"end":1019,"name":"SWAP3","source":1},{"begin":690,"end":1019,"name":"SWAP2","source":1},{"begin":690,"end":1019,"name":"POP","source":1},{"begin":690,"end":1019,"name":"POP","source":1},{"begin":690,"end":1019,"jumpType":"[out]","name":"JUMP","source":1},{"begin":1025,"end":1205,"name":"tag","source":1,"value":"18"},{"begin":1025,"end":1205,"name":"JUMPDEST","source":1},{"begin":1073,"end":1150,"name":"PUSH","source":1,"value":"4E487B7100000000000000000000000000000000000000000000000000000000"},{"begin":1070,"end":1071,"name":"PUSH","source":1,"value":"0"},{"begin":1063,"end":1151,"name":"MSTORE","source":1},{"begin":1170,"end":1174,"name":"PUSH","source":1,"value":"11"},{"begin":1167,"end":1168,"name":"PUSH","source":1,"value":"4"},{"begin":1160,"end":1175,"name":"MSTORE","source":1},{"begin":1194,"end":1198,"name":"PUSH","source":1,"value":"24"},{"begin":1191,"end":1192,"name":"PUSH","source":1,"value":"0"},{"begin":1184,"end":1199,"name":"REVERT","source":1},{"begin":1211,"end":1402,"name":"tag","source":1,"value":"10"},{"begin":1211,"end":1402,"name":"JUMPDEST","source":1},{"begin":1251,"end":1254,"name":"PUSH","source":1,"value":"0"},{"begin":1270,"end":1290,"name":"PUSH [tag]","source":1,"value":"35"},{"begin":1288,"end":1289,"name":"DUP3","source":1},{"begin":1270,"end":1290,"name":"PUSH [tag]","source":1,"value":"15"},{"begin":1270,"end":1290,"jumpType":"[in]","name":"JUMP","source":1},{"begin":1270,"end":1290,"name":"tag","source":1,"value":"35"},{"begin":1270,"end":1290,"name":"JUMPDEST","source":1},{"begin":1265,"end":1290,"name":"SWAP2","source":1},{"begin":1265,"end":1290,"name":"POP","source":1},{"begin":1304,"end":1324,"name":"PUSH [tag]","source":1,"value":"36"},{"begin":1322,"end":1323,"name":"DUP4","source":1},{"begin":1304,"end":1324,"name":"PUSH [tag]","source":1,"value":"15"},{"begin":1304,"end":1324,"jumpType":"[in]","name":"JUMP","source":1},{"begin":1304,"end":1324,"name":"tag","source":1,"value":"36"},{"begin":1304,"end":1324,"name":"JUMPDEST","source":1},{"begin":1299,"end":1324,"name":"SWAP3","source":1},{"begin":1299,"end":1324,"name":"POP","source":1},{"begin":1347,"end":1348,"name":"DUP3","source":1},{"begin":1344,"end":1345,"name":"DUP3","source":1},{"begin":1340,"end":1349,"name":"ADD","source":1},{"begin":1333,"end":1349,"name":"SWAP1","source":1},{"begin":1333,"end":1349,"name":"POP","source":1},{"begin":1368,"end":1371,"name":"DUP1","source":1},{"begin":1365,"end":1366,"name":"DUP3","source":1},{"begin":1362,"end":1372,"name":"GT","source":1},{"begin":1359,"end":1395,"name":"ISZERO","source":1},{"begin":1359,"end":1395,"name":"PUSH [tag]","source":1,"value":"37"},{"begin":1359,"end":1395,"name":"JUMPI","source":1},{"begin":1375,"end":1393,"name":"PUSH [tag]","source":1,"value":"38"},{"begin":1375,"end":1393,"name":"PUSH [tag]","source":1,"value":"18"},{"begin":1375,"end":1393,"jumpType":"[in]","name":"JUMP","source":1},{"begin":1375,"end":1393,"name":"tag","source":1,"value":"38"},{"begin":1375,"end":1393,"name":"JUMPDEST","source":1},{"begin":1359,"end":1395,"name":"tag","source":1,"value":"37"},{"begin":1359,"end":1395,"name":"JUMPDEST","source":1},{"begin":1211,"end":1402,"name":"SWAP3","source":1},{"begin":1211,"end":1402,"name":"SWAP2","source":1},{"begin":1211,"end":1402,"name":"POP","source":1},{"begin":1211,"end":1402,"name":"POP","source":1},{"begin":1211,"end":1402,"jumpType":"[out]","name":"JUMP","source":1}]}},"sourceList":["asm_json_no_pretty_print/input.sol","#utility.yul"]} +{".code":[{"begin":60,"end":160,"name":"PUSH","source":0,"value":"80"},{"begin":60,"end":160,"name":"PUSH","source":0,"value":"40"},{"begin":60,"end":160,"name":"MSTORE","source":0},{"begin":60,"end":160,"name":"CALLVALUE","source":0},{"begin":60,"end":160,"name":"DUP1","source":0},{"begin":60,"end":160,"name":"ISZERO","source":0},{"begin":60,"end":160,"name":"PUSH [tag]","source":0,"value":"1"},{"begin":60,"end":160,"name":"JUMPI","source":0},{"begin":60,"end":160,"name":"PUSH","source":0,"value":"0"},{"begin":60,"end":160,"name":"DUP1","source":0},{"begin":60,"end":160,"name":"REVERT","source":0},{"begin":60,"end":160,"name":"tag","source":0,"value":"1"},{"begin":60,"end":160,"name":"JUMPDEST","source":0},{"begin":60,"end":160,"name":"POP","source":0},{"begin":60,"end":160,"name":"PUSH #[$]","source":0,"value":"0000000000000000000000000000000000000000000000000000000000000000"},{"begin":60,"end":160,"name":"DUP1","source":0},{"begin":60,"end":160,"name":"PUSH [$]","source":0,"value":"0000000000000000000000000000000000000000000000000000000000000000"},{"begin":60,"end":160,"name":"PUSH","source":0,"value":"0"},{"begin":60,"end":160,"name":"CODECOPY","source":0},{"begin":60,"end":160,"name":"PUSH","source":0,"value":"0"},{"begin":60,"end":160,"name":"RETURN","source":0}],".data":{"0":{".auxdata":"",".code":[{"begin":60,"end":160,"name":"PUSH","source":0,"value":"80"},{"begin":60,"end":160,"name":"PUSH","source":0,"value":"40"},{"begin":60,"end":160,"name":"MSTORE","source":0},{"begin":60,"end":160,"name":"CALLVALUE","source":0},{"begin":60,"end":160,"name":"DUP1","source":0},{"begin":60,"end":160,"name":"ISZERO","source":0},{"begin":60,"end":160,"name":"PUSH [tag]","source":0,"value":"1"},{"begin":60,"end":160,"name":"JUMPI","source":0},{"begin":60,"end":160,"name":"PUSH","source":0,"value":"0"},{"begin":60,"end":160,"name":"DUP1","source":0},{"begin":60,"end":160,"name":"REVERT","source":0},{"begin":60,"end":160,"name":"tag","source":0,"value":"1"},{"begin":60,"end":160,"name":"JUMPDEST","source":0},{"begin":60,"end":160,"name":"POP","source":0},{"begin":60,"end":160,"name":"PUSH","source":0,"value":"4"},{"begin":60,"end":160,"name":"CALLDATASIZE","source":0},{"begin":60,"end":160,"name":"LT","source":0},{"begin":60,"end":160,"name":"PUSH [tag]","source":0,"value":"2"},{"begin":60,"end":160,"name":"JUMPI","source":0},{"begin":60,"end":160,"name":"PUSH","source":0,"value":"0"},{"begin":60,"end":160,"name":"CALLDATALOAD","source":0},{"begin":60,"end":160,"name":"PUSH","source":0,"value":"E0"},{"begin":60,"end":160,"name":"SHR","source":0},{"begin":60,"end":160,"name":"DUP1","source":0},{"begin":60,"end":160,"name":"PUSH","source":0,"value":"B3DE648B"},{"begin":60,"end":160,"name":"EQ","source":0},{"begin":60,"end":160,"name":"PUSH [tag]","source":0,"value":"3"},{"begin":60,"end":160,"name":"JUMPI","source":0},{"begin":60,"end":160,"name":"tag","source":0,"value":"2"},{"begin":60,"end":160,"name":"JUMPDEST","source":0},{"begin":60,"end":160,"name":"PUSH","source":0,"value":"0"},{"begin":60,"end":160,"name":"DUP1","source":0},{"begin":60,"end":160,"name":"REVERT","source":0},{"begin":77,"end":158,"name":"tag","source":0,"value":"3"},{"begin":77,"end":158,"name":"JUMPDEST","source":0},{"begin":77,"end":158,"name":"PUSH [tag]","source":0,"value":"4"},{"begin":77,"end":158,"name":"PUSH","source":0,"value":"4"},{"begin":77,"end":158,"name":"DUP1","source":0},{"begin":77,"end":158,"name":"CALLDATASIZE","source":0},{"begin":77,"end":158,"name":"SUB","source":0},{"begin":77,"end":158,"name":"DUP2","source":0},{"begin":77,"end":158,"name":"ADD","source":0},{"begin":77,"end":158,"name":"SWAP1","source":0},{"begin":77,"end":158,"name":"PUSH [tag]","source":0,"value":"5"},{"begin":77,"end":158,"name":"SWAP2","source":0},{"begin":77,"end":158,"name":"SWAP1","source":0},{"begin":77,"end":158,"name":"PUSH [tag]","source":0,"value":"6"},{"begin":77,"end":158,"jumpType":"[in]","name":"JUMP","source":0},{"begin":77,"end":158,"name":"tag","source":0,"value":"5"},{"begin":77,"end":158,"name":"JUMPDEST","source":0},{"begin":77,"end":158,"name":"PUSH [tag]","source":0,"value":"7"},{"begin":77,"end":158,"jumpType":"[in]","name":"JUMP","source":0},{"begin":77,"end":158,"name":"tag","source":0,"value":"4"},{"begin":77,"end":158,"name":"JUMPDEST","source":0},{"begin":77,"end":158,"name":"STOP","source":0},{"begin":77,"end":158,"name":"tag","source":0,"value":"7"},{"begin":77,"end":158,"name":"JUMPDEST","source":0},{"begin":123,"end":125,"name":"PUSH","source":0,"value":"2A"},{"begin":118,"end":125,"name":"DUP2","source":0},{"begin":118,"end":125,"name":"PUSH [tag]","source":0,"value":"9"},{"begin":118,"end":125,"name":"SWAP2","source":0},{"begin":118,"end":125,"name":"SWAP1","source":0},{"begin":118,"end":125,"name":"PUSH [tag]","source":0,"value":"10"},{"begin":118,"end":125,"jumpType":"[in]","name":"JUMP","source":0},{"begin":118,"end":125,"name":"tag","source":0,"value":"9"},{"begin":118,"end":125,"name":"JUMPDEST","source":0},{"begin":118,"end":125,"name":"SWAP1","source":0},{"begin":118,"end":125,"name":"POP","source":0},{"begin":147,"end":150,"name":"PUSH","source":0,"value":"64"},{"begin":143,"end":144,"name":"DUP2","source":0},{"begin":143,"end":150,"name":"GT","source":0},{"begin":135,"end":151,"name":"PUSH [tag]","source":0,"value":"11"},{"begin":135,"end":151,"name":"JUMPI","source":0},{"begin":135,"end":151,"name":"PUSH","source":0,"value":"0"},{"begin":135,"end":151,"name":"DUP1","source":0},{"begin":135,"end":151,"name":"REVERT","source":0},{"begin":135,"end":151,"name":"tag","source":0,"value":"11"},{"begin":135,"end":151,"name":"JUMPDEST","source":0},{"begin":77,"end":158,"name":"POP","source":0},{"begin":77,"end":158,"jumpType":"[out]","name":"JUMP","source":0},{"begin":88,"end":205,"name":"tag","source":1,"value":"13"},{"begin":88,"end":205,"name":"JUMPDEST","source":1},{"begin":197,"end":198,"name":"PUSH","source":1,"value":"0"},{"begin":194,"end":195,"name":"DUP1","source":1},{"begin":187,"end":199,"name":"REVERT","source":1},{"begin":334,"end":411,"name":"tag","source":1,"value":"15"},{"begin":334,"end":411,"name":"JUMPDEST","source":1},{"begin":371,"end":378,"name":"PUSH","source":1,"value":"0"},{"begin":400,"end":405,"name":"DUP2","source":1},{"begin":389,"end":405,"name":"SWAP1","source":1},{"begin":389,"end":405,"name":"POP","source":1},{"begin":334,"end":411,"name":"SWAP2","source":1},{"begin":334,"end":411,"name":"SWAP1","source":1},{"begin":334,"end":411,"name":"POP","source":1},{"begin":334,"end":411,"jumpType":"[out]","name":"JUMP","source":1},{"begin":417,"end":539,"name":"tag","source":1,"value":"16"},{"begin":417,"end":539,"name":"JUMPDEST","source":1},{"begin":490,"end":514,"name":"PUSH [tag]","source":1,"value":"25"},{"begin":508,"end":513,"name":"DUP2","source":1},{"begin":490,"end":514,"name":"PUSH [tag]","source":1,"value":"15"},{"begin":490,"end":514,"jumpType":"[in]","name":"JUMP","source":1},{"begin":490,"end":514,"name":"tag","source":1,"value":"25"},{"begin":490,"end":514,"name":"JUMPDEST","source":1},{"begin":483,"end":488,"name":"DUP2","source":1},{"begin":480,"end":515,"name":"EQ","source":1},{"begin":470,"end":533,"name":"PUSH [tag]","source":1,"value":"26"},{"begin":470,"end":533,"name":"JUMPI","source":1},{"begin":529,"end":530,"name":"PUSH","source":1,"value":"0"},{"begin":526,"end":527,"name":"DUP1","source":1},{"begin":519,"end":531,"name":"REVERT","source":1},{"begin":470,"end":533,"name":"tag","source":1,"value":"26"},{"begin":470,"end":533,"name":"JUMPDEST","source":1},{"begin":417,"end":539,"name":"POP","source":1},{"begin":417,"end":539,"jumpType":"[out]","name":"JUMP","source":1},{"begin":545,"end":684,"name":"tag","source":1,"value":"17"},{"begin":545,"end":684,"name":"JUMPDEST","source":1},{"begin":591,"end":596,"name":"PUSH","source":1,"value":"0"},{"begin":629,"end":635,"name":"DUP2","source":1},{"begin":616,"end":636,"name":"CALLDATALOAD","source":1},{"begin":607,"end":636,"name":"SWAP1","source":1},{"begin":607,"end":636,"name":"POP","source":1},{"begin":645,"end":678,"name":"PUSH [tag]","source":1,"value":"28"},{"begin":672,"end":677,"name":"DUP2","source":1},{"begin":645,"end":678,"name":"PUSH [tag]","source":1,"value":"16"},{"begin":645,"end":678,"jumpType":"[in]","name":"JUMP","source":1},{"begin":645,"end":678,"name":"tag","source":1,"value":"28"},{"begin":645,"end":678,"name":"JUMPDEST","source":1},{"begin":545,"end":684,"name":"SWAP3","source":1},{"begin":545,"end":684,"name":"SWAP2","source":1},{"begin":545,"end":684,"name":"POP","source":1},{"begin":545,"end":684,"name":"POP","source":1},{"begin":545,"end":684,"jumpType":"[out]","name":"JUMP","source":1},{"begin":690,"end":1019,"name":"tag","source":1,"value":"6"},{"begin":690,"end":1019,"name":"JUMPDEST","source":1},{"begin":749,"end":755,"name":"PUSH","source":1,"value":"0"},{"begin":798,"end":800,"name":"PUSH","source":1,"value":"20"},{"begin":786,"end":795,"name":"DUP3","source":1},{"begin":777,"end":784,"name":"DUP5","source":1},{"begin":773,"end":796,"name":"SUB","source":1},{"begin":769,"end":801,"name":"SLT","source":1},{"begin":766,"end":885,"name":"ISZERO","source":1},{"begin":766,"end":885,"name":"PUSH [tag]","source":1,"value":"30"},{"begin":766,"end":885,"name":"JUMPI","source":1},{"begin":804,"end":883,"name":"PUSH [tag]","source":1,"value":"31"},{"begin":804,"end":883,"name":"PUSH [tag]","source":1,"value":"13"},{"begin":804,"end":883,"jumpType":"[in]","name":"JUMP","source":1},{"begin":804,"end":883,"name":"tag","source":1,"value":"31"},{"begin":804,"end":883,"name":"JUMPDEST","source":1},{"begin":766,"end":885,"name":"tag","source":1,"value":"30"},{"begin":766,"end":885,"name":"JUMPDEST","source":1},{"begin":924,"end":925,"name":"PUSH","source":1,"value":"0"},{"begin":949,"end":1002,"name":"PUSH [tag]","source":1,"value":"32"},{"begin":994,"end":1001,"name":"DUP5","source":1},{"begin":985,"end":991,"name":"DUP3","source":1},{"begin":974,"end":983,"name":"DUP6","source":1},{"begin":970,"end":992,"name":"ADD","source":1},{"begin":949,"end":1002,"name":"PUSH [tag]","source":1,"value":"17"},{"begin":949,"end":1002,"jumpType":"[in]","name":"JUMP","source":1},{"begin":949,"end":1002,"name":"tag","source":1,"value":"32"},{"begin":949,"end":1002,"name":"JUMPDEST","source":1},{"begin":939,"end":1002,"name":"SWAP2","source":1},{"begin":939,"end":1002,"name":"POP","source":1},{"begin":895,"end":1012,"name":"POP","source":1},{"begin":690,"end":1019,"name":"SWAP3","source":1},{"begin":690,"end":1019,"name":"SWAP2","source":1},{"begin":690,"end":1019,"name":"POP","source":1},{"begin":690,"end":1019,"name":"POP","source":1},{"begin":690,"end":1019,"jumpType":"[out]","name":"JUMP","source":1},{"begin":1025,"end":1205,"name":"tag","source":1,"value":"18"},{"begin":1025,"end":1205,"name":"JUMPDEST","source":1},{"begin":1073,"end":1150,"name":"PUSH","source":1,"value":"4E487B7100000000000000000000000000000000000000000000000000000000"},{"begin":1070,"end":1071,"name":"PUSH","source":1,"value":"0"},{"begin":1063,"end":1151,"name":"MSTORE","source":1},{"begin":1170,"end":1174,"name":"PUSH","source":1,"value":"11"},{"begin":1167,"end":1168,"name":"PUSH","source":1,"value":"4"},{"begin":1160,"end":1175,"name":"MSTORE","source":1},{"begin":1194,"end":1198,"name":"PUSH","source":1,"value":"24"},{"begin":1191,"end":1192,"name":"PUSH","source":1,"value":"0"},{"begin":1184,"end":1199,"name":"REVERT","source":1},{"begin":1211,"end":1402,"name":"tag","source":1,"value":"10"},{"begin":1211,"end":1402,"name":"JUMPDEST","source":1},{"begin":1251,"end":1254,"name":"PUSH","source":1,"value":"0"},{"begin":1270,"end":1290,"name":"PUSH [tag]","source":1,"value":"35"},{"begin":1288,"end":1289,"name":"DUP3","source":1},{"begin":1270,"end":1290,"name":"PUSH [tag]","source":1,"value":"15"},{"begin":1270,"end":1290,"jumpType":"[in]","name":"JUMP","source":1},{"begin":1270,"end":1290,"name":"tag","source":1,"value":"35"},{"begin":1270,"end":1290,"name":"JUMPDEST","source":1},{"begin":1265,"end":1290,"name":"SWAP2","source":1},{"begin":1265,"end":1290,"name":"POP","source":1},{"begin":1304,"end":1324,"name":"PUSH [tag]","source":1,"value":"36"},{"begin":1322,"end":1323,"name":"DUP4","source":1},{"begin":1304,"end":1324,"name":"PUSH [tag]","source":1,"value":"15"},{"begin":1304,"end":1324,"jumpType":"[in]","name":"JUMP","source":1},{"begin":1304,"end":1324,"name":"tag","source":1,"value":"36"},{"begin":1304,"end":1324,"name":"JUMPDEST","source":1},{"begin":1299,"end":1324,"name":"SWAP3","source":1},{"begin":1299,"end":1324,"name":"POP","source":1},{"begin":1347,"end":1348,"name":"DUP3","source":1},{"begin":1344,"end":1345,"name":"DUP3","source":1},{"begin":1340,"end":1349,"name":"ADD","source":1},{"begin":1333,"end":1349,"name":"SWAP1","source":1},{"begin":1333,"end":1349,"name":"POP","source":1},{"begin":1368,"end":1371,"name":"DUP1","source":1},{"begin":1365,"end":1366,"name":"DUP3","source":1},{"begin":1362,"end":1372,"name":"GT","source":1},{"begin":1359,"end":1395,"name":"ISZERO","source":1},{"begin":1359,"end":1395,"name":"PUSH [tag]","source":1,"value":"37"},{"begin":1359,"end":1395,"name":"JUMPI","source":1},{"begin":1375,"end":1393,"name":"PUSH [tag]","source":1,"value":"38"},{"begin":1375,"end":1393,"name":"PUSH [tag]","source":1,"value":"18"},{"begin":1375,"end":1393,"jumpType":"[in]","name":"JUMP","source":1},{"begin":1375,"end":1393,"name":"tag","source":1,"value":"38"},{"begin":1375,"end":1393,"name":"JUMPDEST","source":1},{"begin":1359,"end":1395,"name":"tag","source":1,"value":"37"},{"begin":1359,"end":1395,"name":"JUMPDEST","source":1},{"begin":1211,"end":1402,"name":"SWAP3","source":1},{"begin":1211,"end":1402,"name":"SWAP2","source":1},{"begin":1211,"end":1402,"name":"POP","source":1},{"begin":1211,"end":1402,"name":"POP","source":1},{"begin":1211,"end":1402,"jumpType":"[out]","name":"JUMP","source":1}],"index":0}},"sourceList":["asm_json_no_pretty_print/input.sol","#utility.yul"]} diff --git a/test/cmdlineTests/strict_asm_output_selection_invalid/err b/test/cmdlineTests/strict_asm_output_selection_invalid/err index 9c9104482..fd6ffc1c7 100644 --- a/test/cmdlineTests/strict_asm_output_selection_invalid/err +++ b/test/cmdlineTests/strict_asm_output_selection_invalid/err @@ -1 +1 @@ -The following outputs are not supported in assembler mode: --abi, --asm-json, --bin-runtime, --devdoc, --hashes, --ir, --metadata, --opcodes, --storage-layout, --userdoc. +The following outputs are not supported in assembler mode: --abi, --bin-runtime, --devdoc, --hashes, --ir, --metadata, --opcodes, --storage-layout, --userdoc. diff --git a/test/cmdlineTests/~evmasm_import_export/test.sh b/test/cmdlineTests/~evmasm_import_export/test.sh new file mode 100755 index 000000000..60cbe29f1 --- /dev/null +++ b/test/cmdlineTests/~evmasm_import_export/test.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail + +# shellcheck source=scripts/common.sh +source "${REPO_ROOT}/scripts/common.sh" + +SOLTMPDIR=$(mktemp -d -t "cmdline-test-evmasm-import-export-XXXXXX") +( + cd "$SOLTMPDIR" + if ! "$REPO_ROOT/scripts/ASTImportTest.sh" evm-assembly + then + rm -r "$SOLTMPDIR" + fail + fi +) +rm -r "$SOLTMPDIR" diff --git a/test/libevmasm/Assembler.cpp b/test/libevmasm/Assembler.cpp index 2b01ae03c..c8955f6fd 100644 --- a/test/libevmasm/Assembler.cpp +++ b/test/libevmasm/Assembler.cpp @@ -55,11 +55,6 @@ BOOST_AUTO_TEST_SUITE(Assembler) BOOST_AUTO_TEST_CASE(all_assembly_items) { - std::map indices = { - { "root.asm", 0 }, - { "sub.asm", 1 }, - { "verbatim.asm", 2 } - }; EVMVersion evmVersion = solidity::test::CommonOptions::get().evmVersion(); Assembly _assembly{evmVersion, false, {}}; auto root_asm = std::make_shared("root.asm"); @@ -203,16 +198,16 @@ BOOST_AUTO_TEST_CASE(all_assembly_items) "{\"begin\":6,\"end\":8,\"name\":\"PUSHIMMUTABLE\",\"source\":1,\"value\":\"someImmutable\"}," "{\"begin\":6,\"end\":8,\"name\":\"PUSH [ErrorTag]\",\"source\":1}," "{\"begin\":6,\"end\":8,\"name\":\"INVALID\",\"source\":1}" - "]}," + "],\"index\":0}," "\"1\":{\".code\":[" "{\"begin\":8,\"end\":18,\"name\":\"VERBATIM\",\"source\":2,\"value\":\"ffff\"}," "{\"begin\":8,\"end\":18,\"name\":\"VERBATIM\",\"source\":2,\"value\":\"74657374\"}," "{\"begin\":8,\"end\":18,\"name\":\"MSTORE\",\"source\":2}" - "]},\"A6885B3731702DA62E8E4A8F584AC46A7F6822F4E2BA50FBA902F67B1588D23B\":\"01020304\"},\"sourceList\":[\"root.asm\",\"sub.asm\",\"verbatim.asm\"]}" + "],\"index\":1},\"A6885B3731702DA62E8E4A8F584AC46A7F6822F4E2BA50FBA902F67B1588D23B\":\"01020304\"},\"sourceList\":[\"root.asm\",\"sub.asm\",\"verbatim.asm\"]}" }; Json::Value jsonValue; BOOST_CHECK(util::jsonParseStrict(json, jsonValue)); - BOOST_CHECK_EQUAL(util::jsonCompactPrint(_assembly.assemblyJSON(indices)), util::jsonCompactPrint(jsonValue)); + BOOST_CHECK_EQUAL(util::jsonCompactPrint(_assembly.assemblyJSON({"root.asm", "sub.asm", "verbatim.asm"})), util::jsonCompactPrint(jsonValue)); } BOOST_AUTO_TEST_CASE(immutables_and_its_source_maps) @@ -301,10 +296,6 @@ BOOST_AUTO_TEST_CASE(immutables_and_its_source_maps) BOOST_AUTO_TEST_CASE(immutable) { - std::map indices = { - { "root.asm", 0 }, - { "sub.asm", 1 } - }; EVMVersion evmVersion = solidity::test::CommonOptions::get().evmVersion(); Assembly _assembly{evmVersion, true, {}}; auto root_asm = std::make_shared("root.asm"); @@ -383,7 +374,7 @@ BOOST_AUTO_TEST_CASE(immutable) "}\n" ); BOOST_CHECK_EQUAL( - util::jsonCompactPrint(_assembly.assemblyJSON(indices)), + util::jsonCompactPrint(_assembly.assemblyJSON({"root.asm", "sub.asm"})), "{\".code\":[" "{\"begin\":1,\"end\":3,\"name\":\"PUSH\",\"source\":0,\"value\":\"2A\"}," "{\"begin\":1,\"end\":3,\"name\":\"PUSH\",\"source\":0,\"value\":\"0\"}," @@ -397,7 +388,7 @@ BOOST_AUTO_TEST_CASE(immutable) "{\"begin\":6,\"end\":8,\"name\":\"PUSHIMMUTABLE\",\"source\":1,\"value\":\"someImmutable\"}," "{\"begin\":6,\"end\":8,\"name\":\"PUSHIMMUTABLE\",\"source\":1,\"value\":\"someOtherImmutable\"}," "{\"begin\":6,\"end\":8,\"name\":\"PUSHIMMUTABLE\",\"source\":1,\"value\":\"someImmutable\"}" - "]}},\"sourceList\":[\"root.asm\",\"sub.asm\"]}" + "],\"index\":0}},\"sourceList\":[\"root.asm\",\"sub.asm\"]}" ); } diff --git a/test/libyul/objectCompiler/manySubObjects.yul b/test/libyul/objectCompiler/manySubObjects.yul new file mode 100644 index 000000000..89faa7497 --- /dev/null +++ b/test/libyul/objectCompiler/manySubObjects.yul @@ -0,0 +1,475 @@ +object "root" { + code { + sstore(0, datasize("root")) + sstore(1, datasize("0")) + sstore(2, datasize("1")) + sstore(3, datasize("2")) + sstore(4, datasize("3")) + sstore(5, datasize("4")) + sstore(6, datasize("5")) + sstore(7, datasize("6")) + sstore(8, datasize("7")) + sstore(9, datasize("8")) + sstore(10, datasize("9")) + sstore(11, datasize("a")) + sstore(12, datasize("b")) + sstore(13, datasize("c")) + sstore(14, datasize("d")) + sstore(15, datasize("e")) + sstore(16, datasize("f")) + sstore(17, datasize("10")) + } + + object "0" { + code { + sstore(100, 0) + sstore(200, datasize("sub0")) + } + object "sub0" { + code { + sstore(300, 0) + } + } + } + + object "1" { + code { + sstore(100, 1) + } + } + + object "2" { + code { + sstore(101, 2) + } + } + + object "3" { + code { + sstore(102, 3) + } + } + + object "4" { + code { + sstore(103, 4) + } + } + + object "5" { + code { + sstore(104, 5) + } + } + + object "6" { + code { + sstore(105, 6) + } + } + + object "7" { + code { + sstore(106, 7) + } + } + + object "8" { + code { + sstore(107, 8) + } + } + + object "9" { + code { + sstore(108, 9) + } + } + + object "a" { + code { + sstore(109, 10) + } + } + + object "b" { + code { + sstore(110, 11) + } + } + + object "c" { + code { + sstore(111, 12) + } + } + + object "d" { + code { + sstore(112, 13) + } + } + + object "e" { + code { + sstore(113, 14) + } + } + + object "f" { + code { + sstore(114, 15) + } + } + + object "10" { + code { + sstore(115, 16) + sstore(201, datasize("sub10")) + } + object "sub10" { + code { + sstore(300, 16) + } + } + } +} +// ---- +// Assembly: +// /* "source":41:57 */ +// bytecodeSize +// /* "source":38:39 */ +// 0x00 +// /* "source":31:58 */ +// sstore +// /* "source":75:88 */ +// dataSize(sub_0) +// /* "source":72:73 */ +// 0x01 +// /* "source":65:89 */ +// sstore +// /* "source":106:119 */ +// dataSize(sub_1) +// /* "source":103:104 */ +// 0x02 +// /* "source":96:120 */ +// sstore +// /* "source":137:150 */ +// dataSize(sub_2) +// /* "source":134:135 */ +// 0x03 +// /* "source":127:151 */ +// sstore +// /* "source":168:181 */ +// dataSize(sub_3) +// /* "source":165:166 */ +// 0x04 +// /* "source":158:182 */ +// sstore +// /* "source":199:212 */ +// dataSize(sub_4) +// /* "source":196:197 */ +// 0x05 +// /* "source":189:213 */ +// sstore +// /* "source":230:243 */ +// dataSize(sub_5) +// /* "source":227:228 */ +// 0x06 +// /* "source":220:244 */ +// sstore +// /* "source":261:274 */ +// dataSize(sub_6) +// /* "source":258:259 */ +// 0x07 +// /* "source":251:275 */ +// sstore +// /* "source":292:305 */ +// dataSize(sub_7) +// /* "source":289:290 */ +// 0x08 +// /* "source":282:306 */ +// sstore +// /* "source":323:336 */ +// dataSize(sub_8) +// /* "source":320:321 */ +// 0x09 +// /* "source":313:337 */ +// sstore +// /* "source":355:368 */ +// dataSize(sub_9) +// /* "source":351:353 */ +// 0x0a +// /* "source":344:369 */ +// sstore +// /* "source":387:400 */ +// dataSize(sub_10) +// /* "source":383:385 */ +// 0x0b +// /* "source":376:401 */ +// sstore +// /* "source":419:432 */ +// dataSize(sub_11) +// /* "source":415:417 */ +// 0x0c +// /* "source":408:433 */ +// sstore +// /* "source":451:464 */ +// dataSize(sub_12) +// /* "source":447:449 */ +// 0x0d +// /* "source":440:465 */ +// sstore +// /* "source":483:496 */ +// dataSize(sub_13) +// /* "source":479:481 */ +// 0x0e +// /* "source":472:497 */ +// sstore +// /* "source":515:528 */ +// dataSize(sub_14) +// /* "source":511:513 */ +// 0x0f +// /* "source":504:529 */ +// sstore +// /* "source":547:560 */ +// dataSize(sub_15) +// /* "source":543:545 */ +// 0x10 +// /* "source":536:561 */ +// sstore +// /* "source":579:593 */ +// dataSize(sub_16) +// /* "source":575:577 */ +// 0x11 +// /* "source":568:594 */ +// sstore +// /* "source":23:598 */ +// stop +// stop +// +// sub_0: assembly { +// /* "source":644:645 */ +// 0x00 +// /* "source":639:642 */ +// 0x64 +// /* "source":632:646 */ +// sstore +// /* "source":665:681 */ +// dataSize(sub_0) +// /* "source":660:663 */ +// 0xc8 +// /* "source":653:682 */ +// sstore +// /* "source":624:688 */ +// stop +// stop +// +// sub_0: assembly { +// /* "source":742:743 */ +// 0x00 +// /* "source":737:740 */ +// 0x012c +// /* "source":730:744 */ +// sstore +// /* "source":720:752 */ +// stop +// } +// } +// +// sub_1: assembly { +// /* "source":808:809 */ +// 0x01 +// /* "source":803:806 */ +// 0x64 +// /* "source":796:810 */ +// sstore +// /* "source":788:816 */ +// stop +// } +// +// sub_2: assembly { +// /* "source":866:867 */ +// 0x02 +// /* "source":861:864 */ +// 0x65 +// /* "source":854:868 */ +// sstore +// /* "source":846:874 */ +// stop +// } +// +// sub_3: assembly { +// /* "source":924:925 */ +// 0x03 +// /* "source":919:922 */ +// 0x66 +// /* "source":912:926 */ +// sstore +// /* "source":904:932 */ +// stop +// } +// +// sub_4: assembly { +// /* "source":982:983 */ +// 0x04 +// /* "source":977:980 */ +// 0x67 +// /* "source":970:984 */ +// sstore +// /* "source":962:990 */ +// stop +// } +// +// sub_5: assembly { +// /* "source":1040:1041 */ +// 0x05 +// /* "source":1035:1038 */ +// 0x68 +// /* "source":1028:1042 */ +// sstore +// /* "source":1020:1048 */ +// stop +// } +// +// sub_6: assembly { +// /* "source":1098:1099 */ +// 0x06 +// /* "source":1093:1096 */ +// 0x69 +// /* "source":1086:1100 */ +// sstore +// /* "source":1078:1106 */ +// stop +// } +// +// sub_7: assembly { +// /* "source":1156:1157 */ +// 0x07 +// /* "source":1151:1154 */ +// 0x6a +// /* "source":1144:1158 */ +// sstore +// /* "source":1136:1164 */ +// stop +// } +// +// sub_8: assembly { +// /* "source":1214:1215 */ +// 0x08 +// /* "source":1209:1212 */ +// 0x6b +// /* "source":1202:1216 */ +// sstore +// /* "source":1194:1222 */ +// stop +// } +// +// sub_9: assembly { +// /* "source":1272:1273 */ +// 0x09 +// /* "source":1267:1270 */ +// 0x6c +// /* "source":1260:1274 */ +// sstore +// /* "source":1252:1280 */ +// stop +// } +// +// sub_10: assembly { +// /* "source":1330:1332 */ +// 0x0a +// /* "source":1325:1328 */ +// 0x6d +// /* "source":1318:1333 */ +// sstore +// /* "source":1310:1339 */ +// stop +// } +// +// sub_11: assembly { +// /* "source":1389:1391 */ +// 0x0b +// /* "source":1384:1387 */ +// 0x6e +// /* "source":1377:1392 */ +// sstore +// /* "source":1369:1398 */ +// stop +// } +// +// sub_12: assembly { +// /* "source":1448:1450 */ +// 0x0c +// /* "source":1443:1446 */ +// 0x6f +// /* "source":1436:1451 */ +// sstore +// /* "source":1428:1457 */ +// stop +// } +// +// sub_13: assembly { +// /* "source":1507:1509 */ +// 0x0d +// /* "source":1502:1505 */ +// 0x70 +// /* "source":1495:1510 */ +// sstore +// /* "source":1487:1516 */ +// stop +// } +// +// sub_14: assembly { +// /* "source":1566:1568 */ +// 0x0e +// /* "source":1561:1564 */ +// 0x71 +// /* "source":1554:1569 */ +// sstore +// /* "source":1546:1575 */ +// stop +// } +// +// sub_15: assembly { +// /* "source":1625:1627 */ +// 0x0f +// /* "source":1620:1623 */ +// 0x72 +// /* "source":1613:1628 */ +// sstore +// /* "source":1605:1634 */ +// stop +// } +// +// sub_16: assembly { +// /* "source":1685:1687 */ +// 0x10 +// /* "source":1680:1683 */ +// 0x73 +// /* "source":1673:1688 */ +// sstore +// /* "source":1707:1724 */ +// dataSize(sub_0) +// /* "source":1702:1705 */ +// 0xc9 +// /* "source":1695:1725 */ +// sstore +// /* "source":1665:1731 */ +// stop +// stop +// +// sub_0: assembly { +// /* "source":1786:1788 */ +// 0x10 +// /* "source":1781:1784 */ +// 0x012c +// /* "source":1774:1789 */ +// sstore +// /* "source":1764:1797 */ +// stop +// } +// } +// Bytecode: 61005c5f55600b600155600660025560066003556006600455600660055560066006556006600755600660085560066009556006600a556006600b556006600c556006600d556006600e556006600f556006601055600c60115500fe +// Opcodes: PUSH2 0x5C PUSH0 SSTORE PUSH1 0xB PUSH1 0x1 SSTORE PUSH1 0x6 PUSH1 0x2 SSTORE PUSH1 0x6 PUSH1 0x3 SSTORE PUSH1 0x6 PUSH1 0x4 SSTORE PUSH1 0x6 PUSH1 0x5 SSTORE PUSH1 0x6 PUSH1 0x6 SSTORE PUSH1 0x6 PUSH1 0x7 SSTORE PUSH1 0x6 PUSH1 0x8 SSTORE PUSH1 0x6 PUSH1 0x9 SSTORE PUSH1 0x6 PUSH1 0xA SSTORE PUSH1 0x6 PUSH1 0xB SSTORE PUSH1 0x6 PUSH1 0xC SSTORE PUSH1 0x6 PUSH1 0xD SSTORE PUSH1 0x6 PUSH1 0xE SSTORE PUSH1 0x6 PUSH1 0xF SSTORE PUSH1 0x6 PUSH1 0x10 SSTORE PUSH1 0xC PUSH1 0x11 SSTORE STOP INVALID +// SourceMappings: 41:16:0:-:0;38:1;31:27;75:13;72:1;65:24;106:13;103:1;96:24;137:13;134:1;127:24;168:13;165:1;158:24;199:13;196:1;189:24;230:13;227:1;220:24;261:13;258:1;251:24;292:13;289:1;282:24;323:13;320:1;313:24;355:13;351:2;344:25;387:13;383:2;376:25;419:13;415:2;408:25;451:13;447:2;440:25;483:13;479:2;472:25;515:13;511:2;504:25;547:13;543:2;536:25;579:14;575:2;568:26;23:575 diff --git a/test/solc/CommandLineInterface.cpp b/test/solc/CommandLineInterface.cpp index 7732faf38..08ec8947e 100644 --- a/test/solc/CommandLineInterface.cpp +++ b/test/solc/CommandLineInterface.cpp @@ -149,7 +149,7 @@ BOOST_AUTO_TEST_CASE(version) BOOST_AUTO_TEST_CASE(multiple_input_modes) { - array inputModeOptions = { + array inputModeOptions = { "--help", "--license", "--version", @@ -159,10 +159,11 @@ BOOST_AUTO_TEST_CASE(multiple_input_modes) "--strict-assembly", "--yul", "--import-ast", + "--import-asm-json", }; string expectedMessage = "The following options are mutually exclusive: " - "--help, --license, --version, --standard-json, --link, --assemble, --strict-assembly, --yul, --import-ast, --lsp. " + "--help, --license, --version, --standard-json, --link, --assemble, --strict-assembly, --yul, --import-ast, --lsp, --import-asm-json. " "Select at most one."; for (string const& mode1: inputModeOptions)