Add verbatim builtin.

This commit is contained in:
chriseth
2021-04-26 19:56:44 +02:00
parent 2969bc0f3e
commit e2d8005737
34 changed files with 371 additions and 13 deletions
+19 -3
View File
@@ -33,7 +33,8 @@
namespace solidity::evmasm
{
enum AssemblyItemType {
enum AssemblyItemType
{
UndefinedItem,
Operation,
Push,
@@ -47,7 +48,8 @@ enum AssemblyItemType {
PushLibraryAddress, ///< Push a currently unknown address of another (library) contract.
PushDeployTimeAddress, ///< Push an address to be filled at deploy time. Should not be touched by the optimizer.
PushImmutable, ///< Push the currently unknown value of an immutable variable. The actual value will be filled in by the constructor.
AssignImmutable ///< Assigns the current value on the stack to an immutable variable. Only valid during creation code.
AssignImmutable, ///< Assigns the current value on the stack to an immutable variable. Only valid during creation code.
VerbatimBytecode ///< Contains data that is inserted into the bytecode code section without modification.
};
class Assembly;
@@ -75,6 +77,12 @@ public:
else
m_data = std::make_shared<u256>(std::move(_data));
}
explicit AssemblyItem(bytes const& _verbatimData, int _deposit):
m_type(VerbatimBytecode),
m_instruction{},
m_verbatimBytecode{{_deposit, _verbatimData}}
{}
AssemblyItem(AssemblyItem const&) = default;
AssemblyItem(AssemblyItem&&) = default;
AssemblyItem& operator=(AssemblyItem const&) = default;
@@ -95,6 +103,8 @@ public:
u256 const& data() const { assertThrow(m_type != Operation, util::Exception, ""); return *m_data; }
void setData(u256 const& _data) { assertThrow(m_type != Operation, util::Exception, ""); m_data = std::make_shared<u256>(_data); }
bytes const& verbatimData() const { assertThrow(m_type == VerbatimBytecode, util::Exception, ""); return m_verbatimBytecode->second; }
/// @returns the instruction of this item (only valid if type() == Operation)
Instruction instruction() const { assertThrow(m_type == Operation, util::Exception, ""); return m_instruction; }
@@ -105,6 +115,8 @@ public:
return false;
if (type() == Operation)
return instruction() == _other.instruction();
else if (type() == VerbatimBytecode)
return *m_verbatimBytecode == *_other.m_verbatimBytecode;
else
return data() == _other.data();
}
@@ -116,6 +128,8 @@ public:
return type() < _other.type();
else if (type() == Operation)
return instruction() < _other.instruction();
else if (type() == VerbatimBytecode)
return *m_verbatimBytecode == *_other.m_verbatimBytecode;
else
return data() < _other.data();
}
@@ -137,7 +151,7 @@ public:
size_t bytesRequired(size_t _addressLength) const;
size_t arguments() const;
size_t returnValues() const;
size_t deposit() const { return returnValues() - arguments(); }
size_t deposit() const { return m_type == VerbatimBytecode ? static_cast<size_t>(m_verbatimBytecode->first) : returnValues() - arguments(); }
/// @returns true if the assembly item can be used in a functional context.
bool canBeFunctional() const;
@@ -162,6 +176,8 @@ private:
AssemblyItemType m_type;
Instruction m_instruction; ///< Only valid if m_type == Operation
std::shared_ptr<u256> m_data; ///< Only valid if m_type != Operation
/// If m_type == VerbatimBytecode, this holds stack difference and verbatim bytecode.
std::optional<std::pair<int, bytes>> m_verbatimBytecode;
langutil::SourceLocation m_location;
JumpType m_jumpType = JumpType::Ordinary;
/// Pushed value for operations with data to be determined during assembly stage,