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