mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Add verbatim builtin.
This commit is contained in:
+12
-2
@@ -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;
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user