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
+12 -2
View File
@@ -33,9 +33,11 @@
#include <liblangutil/Exceptions.h>
#include <fstream>
#include <json/json.h>
#include <fstream>
#include <range/v3/algorithm/any_of.hpp>
using namespace std;
using namespace solidity;
using namespace solidity::evmasm;
@@ -317,6 +319,9 @@ Json::Value Assembly::assemblyJSON(map<string, unsigned> const& _sourceIndices)
case PushData:
collection.append(createJsonValue("PUSH data", sourceIndex, i.location().start, i.location().end, toStringInHex(i.data())));
break;
case VerbatimBytecode:
collection.append(createJsonValue("VERBATIM", sourceIndex, i.location().start, i.location().end, toHex(i.verbatimData())));
break;
default:
assertThrow(false, InvalidOpcode, "");
}
@@ -482,7 +487,9 @@ map<u256, u256> Assembly::optimiseInternal(
// function types that can be stored in storage.
AssemblyItems optimisedItems;
bool usesMSize = (find(m_items.begin(), m_items.end(), AssemblyItem{Instruction::MSIZE}) != m_items.end());
bool usesMSize = ranges::any_of(m_items, [](AssemblyItem const& _i) {
return _i == AssemblyItem{Instruction::MSIZE} || _i.type() == VerbatimBytecode;
});
auto iter = m_items.begin();
while (iter != m_items.end())
@@ -682,6 +689,9 @@ LinkerObject const& Assembly::assemble() const
ret.immutableReferences[i.data()].second.emplace_back(ret.bytecode.size());
ret.bytecode.resize(ret.bytecode.size() + 32);
break;
case VerbatimBytecode:
ret.bytecode += i.verbatimData();
break;
case AssignImmutable:
{
auto const& offsets = immutableReferencesBySub[i.data()].second;
+2
View File
@@ -73,6 +73,8 @@ public:
void appendImmutable(std::string const& _identifier) { append(newPushImmutable(_identifier)); }
void appendImmutableAssignment(std::string const& _identifier) { append(newImmutableAssignment(_identifier)); }
void appendVerbatim(bytes const& _data, int _stackDifference) { append(AssemblyItem(_data, _stackDifference)); }
AssemblyItem appendJump() { auto ret = append(newPushTag()); append(Instruction::JUMP); return ret; }
AssemblyItem appendJumpI() { auto ret = append(newPushTag()); append(Instruction::JUMPI); return ret; }
AssemblyItem appendJump(AssemblyItem const& _tag) { auto ret = append(_tag.pushTag()); append(Instruction::JUMP); return ret; }
+8
View File
@@ -91,6 +91,8 @@ size_t AssemblyItem::bytesRequired(size_t _addressLength) const
return 1 + (3 + 32) * *m_immutableOccurrences;
else
return 1 + (3 + 32) * 1024; // 1024 occurrences are beyond the maximum code size anyways.
case VerbatimBytecode:
return m_verbatimBytecode->second.size();
default:
break;
}
@@ -241,6 +243,9 @@ string AssemblyItem::toAssemblyText(Assembly const& _assembly) const
case UndefinedItem:
assertThrow(false, AssemblyException, "Invalid assembly item.");
break;
case VerbatimBytecode:
text = string("verbatimbytecode_") + util::toHex(m_verbatimBytecode->second);
break;
default:
assertThrow(false, InvalidOpcode, "");
}
@@ -309,6 +314,9 @@ ostream& solidity::evmasm::operator<<(ostream& _out, AssemblyItem const& _item)
case AssignImmutable:
_out << " AssignImmutable";
break;
case VerbatimBytecode:
_out << " Verbatim " << util::toHex(_item.verbatimData());
break;
case UndefinedItem:
_out << " ???";
break;
+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,
+3
View File
@@ -38,6 +38,7 @@ bool SemanticInformation::breaksCSEAnalysisBlock(AssemblyItem const& _item, bool
case Tag:
case PushDeployTimeAddress:
case AssignImmutable:
case VerbatimBytecode:
return true;
case Push:
case PushString:
@@ -164,6 +165,8 @@ bool SemanticInformation::reverts(Instruction _instruction)
bool SemanticInformation::isDeterministic(AssemblyItem const& _item)
{
assertThrow(_item.type() != VerbatimBytecode, AssemblyException, "");
if (_item.type() != Operation)
return true;