diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index 99f39aa1c..034b66bd5 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -75,19 +75,19 @@ unsigned Assembly::codeSize(unsigned subTagSize) const } } -void Assembly::importAssemblyItemsFromJSON(Json::Value const& _code) +void Assembly::importAssemblyItemsFromJSON(Json::Value const& _code, vector const& _sourceList) { solAssert(m_items.empty()); solRequire(_code.isArray(), AssemblyImportException, "Supplied JSON is not an array."); for (auto current = begin(_code); current != end(_code); ++current) { - auto const& item = m_items.emplace_back(createAssemblyItemFromJSON(*current, m_sourceList)); + 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 != end(_code) && createAssemblyItemFromJSON(*current, m_sourceList) != Instruction::JUMPDEST) + if (current != end(_code) && createAssemblyItemFromJSON(*current, _sourceList) != Instruction::JUMPDEST) solThrow(AssemblyImportException, "JUMPDEST expected after tag."); } } @@ -424,7 +424,7 @@ std::string Assembly::assemblyString( return tmp.str(); } -Json::Value Assembly::assemblyJSON(bool _includeSourceList) const +Json::Value Assembly::assemblyJSON(std::vector const& _sources, bool _includeSourceList) const { Json::Value root; root[".code"] = Json::arrayValue; @@ -433,11 +433,12 @@ Json::Value Assembly::assemblyJSON(bool _includeSourceList) const { int sourceIndex = -1; if (item.location().sourceName) - { - for (size_t index = 0; index < m_sourceList.size(); ++index) - if (m_sourceList[index] == *item.location().sourceName) + 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; @@ -470,12 +471,12 @@ Json::Value Assembly::assemblyJSON(bool _includeSourceList) const code.append(std::move(jumpdest)); } } - if (_includeSourceList) + if (!_sources.empty() && _includeSourceList) { root["sourceList"] = Json::arrayValue; Json::Value& jsonSourceList = root["sourceList"]; - for (int index = 0; index < static_cast(m_sourceList.size()); ++index) - jsonSourceList[index] = m_sourceList[static_cast(index)]; + for (int index = 0; index < static_cast(_sources.size()); ++index) + jsonSourceList[index] = _sources[static_cast(index)]; } if (!m_data.empty() || !m_subs.empty()) @@ -490,8 +491,7 @@ Json::Value Assembly::assemblyJSON(bool _includeSourceList) const { stringstream hexStr; hexStr << hex << i; - m_subs[i]->setSourceList(m_sourceList); - data[hexStr.str()] = m_subs[i]->assemblyJSON(false); + data[hexStr.str()] = m_subs[i]->assemblyJSON(_sources, false); } } @@ -501,7 +501,7 @@ Json::Value Assembly::assemblyJSON(bool _includeSourceList) const return root; } -shared_ptr Assembly::fromJSON(Json::Value const& _json, vector const& _sourceList, int _level) +std::pair, std::vector> Assembly::fromJSON(Json::Value const& _json, vector const& _sourceList, int _level) { solRequire(_json.isObject(), AssemblyImportException, "Supplied JSON is not an object."); static set const validMembers{".code", ".data", ".auxdata", "sourceList"}; @@ -528,15 +528,23 @@ shared_ptr Assembly::fromJSON(Json::Value const& _json, vector ); shared_ptr result = make_shared(langutil::EVMVersion(), _level == 0, ""); + vector sourceList; if (_json.isMember("sourceList")) { solAssert(_level == 0); for (auto const& it: _json["sourceList"]) - result->m_sourceList.emplace_back(it.asString()); + { + 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 - result->m_sourceList = _sourceList; + sourceList = _sourceList; - result->importAssemblyItemsFromJSON(_json[".code"]); + result->importAssemblyItemsFromJSON(_json[".code"], sourceList); if (_json[".auxdata"]) { solRequire(_json[".auxdata"].isString(), AssemblyImportException, "Optional member '.auxdata' is not of type string."); @@ -565,7 +573,7 @@ shared_ptr Assembly::fromJSON(Json::Value const& _json, vector } else if (code.isObject()) { - shared_ptr subassembly(Assembly::fromJSON(code, result->m_sourceList, _level + 1)); + shared_ptr subassembly(Assembly::fromJSON(code, sourceList, _level + 1).first); solAssert(subassembly); result->m_subs.emplace_back(make_shared(*subassembly)); // TODO: this shouldn't be enough for the general case. @@ -575,7 +583,7 @@ shared_ptr Assembly::fromJSON(Json::Value const& _json, vector solThrow(AssemblyImportException, "Key inside '.data' '" + dataItemID + "' can only be a valid hex-string or an object."); } } - return result; + return std::make_pair(result, sourceList); } AssemblyItem Assembly::namedTag(string const& _name, size_t _params, size_t _returns, optional _sourceID) diff --git a/libevmasm/Assembly.h b/libevmasm/Assembly.h index cec69d07e..9bbe7a7a3 100644 --- a/libevmasm/Assembly.h +++ b/libevmasm/Assembly.h @@ -150,31 +150,19 @@ public: ) const; /// Create a JSON representation of the assembly. - Json::Value assemblyJSON( - 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::shared_ptr fromJSON( + static std::pair, std::vector> fromJSON( Json::Value const& _json, std::vector const& _sourceList = {}, int _level = 0 ); - void setSourceList(std::vector const& _sourceList) - { - m_sourceList = _sourceList; - } - - std::vector const& sourceList() - { - return m_sourceList; - } - /// Mark this assembly as invalid. Calling ``assemble`` on it will throw. void markAsInvalid() { m_invalid = true; } @@ -195,7 +183,7 @@ protected: /// 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); + 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 @@ -249,7 +237,6 @@ protected: /// Internal name of the assembly object, only used with the Yul backend /// currently std::string m_name; - std::vector m_sourceList; langutil::SourceLocation m_currentSourceLocation; public: