Make verbatim compatible with KnownState.

This commit is contained in:
chriseth 2021-04-20 13:20:26 +02:00
parent e2d8005737
commit cb1af8b88a
11 changed files with 48 additions and 19 deletions

View File

@ -73,7 +73,10 @@ public:
void appendImmutable(std::string const& _identifier) { append(newPushImmutable(_identifier)); } void appendImmutable(std::string const& _identifier) { append(newPushImmutable(_identifier)); }
void appendImmutableAssignment(std::string const& _identifier) { append(newImmutableAssignment(_identifier)); } void appendImmutableAssignment(std::string const& _identifier) { append(newImmutableAssignment(_identifier)); }
void appendVerbatim(bytes const& _data, int _stackDifference) { append(AssemblyItem(_data, _stackDifference)); } void appendVerbatim(bytes _data, size_t _arguments, size_t _returnVariables)
{
append(AssemblyItem(std::move(_data), _arguments, _returnVariables));
}
AssemblyItem appendJump() { auto ret = append(newPushTag()); append(Instruction::JUMP); return ret; } AssemblyItem appendJump() { auto ret = append(newPushTag()); append(Instruction::JUMP); return ret; }
AssemblyItem appendJumpI() { auto ret = append(newPushTag()); append(Instruction::JUMPI); return ret; } AssemblyItem appendJumpI() { auto ret = append(newPushTag()); append(Instruction::JUMPI); return ret; }

View File

@ -92,7 +92,7 @@ size_t AssemblyItem::bytesRequired(size_t _addressLength) const
else else
return 1 + (3 + 32) * 1024; // 1024 occurrences are beyond the maximum code size anyways. return 1 + (3 + 32) * 1024; // 1024 occurrences are beyond the maximum code size anyways.
case VerbatimBytecode: case VerbatimBytecode:
return m_verbatimBytecode->second.size(); return std::get<2>(*m_verbatimBytecode).size();
default: default:
break; break;
} }
@ -103,6 +103,8 @@ size_t AssemblyItem::arguments() const
{ {
if (type() == Operation) if (type() == Operation)
return static_cast<size_t>(instructionInfo(instruction()).args); return static_cast<size_t>(instructionInfo(instruction()).args);
else if (type() == VerbatimBytecode)
return get<0>(*m_verbatimBytecode);
else if (type() == AssignImmutable) else if (type() == AssignImmutable)
return 2; return 2;
else else
@ -128,6 +130,8 @@ size_t AssemblyItem::returnValues() const
return 1; return 1;
case Tag: case Tag:
return 0; return 0;
case VerbatimBytecode:
return get<1>(*m_verbatimBytecode);
default: default:
break; break;
} }
@ -244,7 +248,7 @@ string AssemblyItem::toAssemblyText(Assembly const& _assembly) const
assertThrow(false, AssemblyException, "Invalid assembly item."); assertThrow(false, AssemblyException, "Invalid assembly item.");
break; break;
case VerbatimBytecode: case VerbatimBytecode:
text = string("verbatimbytecode_") + util::toHex(m_verbatimBytecode->second); text = string("verbatimbytecode_") + util::toHex(get<2>(*m_verbatimBytecode));
break; break;
default: default:
assertThrow(false, InvalidOpcode, ""); assertThrow(false, InvalidOpcode, "");

View File

@ -77,10 +77,10 @@ public:
else else
m_data = std::make_shared<u256>(std::move(_data)); m_data = std::make_shared<u256>(std::move(_data));
} }
explicit AssemblyItem(bytes const& _verbatimData, int _deposit): explicit AssemblyItem(bytes _verbatimData, size_t _arguments, size_t _returnVariables):
m_type(VerbatimBytecode), m_type(VerbatimBytecode),
m_instruction{}, m_instruction{},
m_verbatimBytecode{{_deposit, _verbatimData}} m_verbatimBytecode{{_arguments, _returnVariables, std::move(_verbatimData)}}
{} {}
AssemblyItem(AssemblyItem const&) = default; AssemblyItem(AssemblyItem const&) = default;
@ -103,7 +103,7 @@ public:
u256 const& data() const { assertThrow(m_type != Operation, util::Exception, ""); return *m_data; } 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); } 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; } bytes const& verbatimData() const { assertThrow(m_type == VerbatimBytecode, util::Exception, ""); return std::get<2>(*m_verbatimBytecode); }
/// @returns the instruction of this item (only valid if type() == Operation) /// @returns the instruction of this item (only valid if type() == Operation)
Instruction instruction() const { assertThrow(m_type == Operation, util::Exception, ""); return m_instruction; } Instruction instruction() const { assertThrow(m_type == Operation, util::Exception, ""); return m_instruction; }
@ -151,7 +151,7 @@ public:
size_t bytesRequired(size_t _addressLength) const; size_t bytesRequired(size_t _addressLength) const;
size_t arguments() const; size_t arguments() const;
size_t returnValues() const; size_t returnValues() const;
size_t deposit() const { return m_type == VerbatimBytecode ? static_cast<size_t>(m_verbatimBytecode->first) : returnValues() - arguments(); } size_t deposit() const { return returnValues() - arguments(); }
/// @returns true if the assembly item can be used in a functional context. /// @returns true if the assembly item can be used in a functional context.
bool canBeFunctional() const; bool canBeFunctional() const;
@ -176,8 +176,9 @@ private:
AssemblyItemType m_type; AssemblyItemType m_type;
Instruction m_instruction; ///< Only valid if m_type == Operation Instruction m_instruction; ///< Only valid if m_type == Operation
std::shared_ptr<u256> m_data; ///< 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. /// If m_type == VerbatimBytecode, this holds number of arguments, number of
std::optional<std::pair<int, bytes>> m_verbatimBytecode; /// return variables and verbatim bytecode.
std::optional<std::tuple<size_t, size_t, bytes>> m_verbatimBytecode;
langutil::SourceLocation m_location; langutil::SourceLocation m_location;
JumpType m_jumpType = JumpType::Ordinary; JumpType m_jumpType = JumpType::Ordinary;
/// Pushed value for operations with data to be determined during assembly stage, /// Pushed value for operations with data to be determined during assembly stage,

View File

@ -100,6 +100,24 @@ KnownState::StoreOperation KnownState::feedItem(AssemblyItem const& _item, bool
feedItem(AssemblyItem(Instruction::POP), _copyItem); feedItem(AssemblyItem(Instruction::POP), _copyItem);
return feedItem(AssemblyItem(Instruction::POP), _copyItem); return feedItem(AssemblyItem(Instruction::POP), _copyItem);
} }
else if (_item.type() == VerbatimBytecode)
{
m_sequenceNumber += 2;
resetMemory();
resetKnownKeccak256Hashes();
resetStorage();
// Consume all arguments and place unknown return values on the stack.
m_stackElements.erase(
m_stackElements.upper_bound(m_stackHeight - static_cast<int>(_item.arguments())),
m_stackElements.end()
);
m_stackHeight += static_cast<int>(_item.deposit());
for (size_t i = 0; i < _item.returnValues(); ++i)
setStackElement(
m_stackHeight - static_cast<int>(i),
m_expressionClasses->newClass(_item.location())
);
}
else if (_item.type() != Operation) else if (_item.type() != Operation)
{ {
assertThrow(_item.deposit() == 1, InvalidDeposit, ""); assertThrow(_item.deposit() == 1, InvalidDeposit, "");

View File

@ -78,7 +78,7 @@ public:
virtual void appendLinkerSymbol(std::string const& _name) = 0; virtual void appendLinkerSymbol(std::string const& _name) = 0;
/// Append raw bytes that stay untouched by the optimizer. /// Append raw bytes that stay untouched by the optimizer.
virtual void appendVerbatim(bytes const& _data, int _stackDifference) = 0; virtual void appendVerbatim(bytes _data, size_t _arguments, size_t _returnVariables) = 0;
/// Append a jump instruction. /// Append a jump instruction.
/// @param _stackDiffAfter the stack adjustment after this instruction. /// @param _stackDiffAfter the stack adjustment after this instruction.

View File

@ -99,9 +99,9 @@ void EthAssemblyAdapter::appendLinkerSymbol(std::string const& _linkerSymbol)
m_assembly.appendLibraryAddress(_linkerSymbol); m_assembly.appendLibraryAddress(_linkerSymbol);
} }
void EthAssemblyAdapter::appendVerbatim(bytes const& _data, int _stackDifference) void EthAssemblyAdapter::appendVerbatim(bytes _data, size_t _arguments, size_t _returnVariables)
{ {
m_assembly.appendVerbatim(_data, _stackDifference); m_assembly.appendVerbatim(move(_data), _arguments, _returnVariables);
} }
void EthAssemblyAdapter::appendJump(int _stackDiffAfter, JumpType _jumpType) void EthAssemblyAdapter::appendJump(int _stackDiffAfter, JumpType _jumpType)

View File

@ -50,7 +50,7 @@ public:
size_t newLabelId() override; size_t newLabelId() override;
size_t namedLabel(std::string const& _name) override; size_t namedLabel(std::string const& _name) override;
void appendLinkerSymbol(std::string const& _linkerSymbol) override; void appendLinkerSymbol(std::string const& _linkerSymbol) override;
void appendVerbatim(bytes const& _data, int _stackDifference) override; void appendVerbatim(bytes _data, size_t _arguments, size_t _returnVariables) override;
void appendJump(int _stackDiffAfter, JumpType _jumpType) override; void appendJump(int _stackDiffAfter, JumpType _jumpType) override;
void appendJumpTo(LabelID _labelId, int _stackDiffAfter, JumpType _jumpType) override; void appendJumpTo(LabelID _labelId, int _stackDiffAfter, JumpType _jumpType) override;
void appendJumpToIf(LabelID _labelId, JumpType _jumpType) override; void appendJumpToIf(LabelID _labelId, JumpType _jumpType) override;

View File

@ -382,8 +382,11 @@ BuiltinFunctionForEVM const* EVMDialect::verbatimFunction(size_t _arguments, siz
for (Expression const& arg: _call.arguments | ranges::views::tail | ranges::views::reverse) for (Expression const& arg: _call.arguments | ranges::views::tail | ranges::views::reverse)
_visitExpression(arg); _visitExpression(arg);
Expression const& bytecode = _call.arguments.front(); Expression const& bytecode = _call.arguments.front();
int diff = static_cast<int>(_returnVariables) - static_cast<int>(_arguments); _assembly.appendVerbatim(
_assembly.appendVerbatim(asBytes(std::get<Literal>(bytecode).value.str()), diff); asBytes(std::get<Literal>(bytecode).value.str()),
_arguments,
_returnVariables
);
} }
).second; ).second;
builtinFunction.isMSize = true; builtinFunction.isMSize = true;

View File

@ -69,9 +69,9 @@ void NoOutputAssembly::appendLinkerSymbol(string const&)
yulAssert(false, "Linker symbols not yet implemented."); yulAssert(false, "Linker symbols not yet implemented.");
} }
void NoOutputAssembly::appendVerbatim(bytes const&, int _stackDifference) void NoOutputAssembly::appendVerbatim(bytes, size_t _arguments, size_t _returnVariables)
{ {
m_stackHeight += _stackDifference; m_stackHeight += static_cast<int>(_returnVariables - _arguments);
} }
void NoOutputAssembly::appendJump(int _stackDiffAfter, JumpType) void NoOutputAssembly::appendJump(int _stackDiffAfter, JumpType)

View File

@ -58,7 +58,7 @@ public:
LabelID newLabelId() override; LabelID newLabelId() override;
LabelID namedLabel(std::string const& _name) override; LabelID namedLabel(std::string const& _name) override;
void appendLinkerSymbol(std::string const& _name) override; void appendLinkerSymbol(std::string const& _name) override;
void appendVerbatim(bytes const& _data, int _stackDifference) override; void appendVerbatim(bytes _data, size_t _arguments, size_t _returnVariables) override;
void appendJump(int _stackDiffAfter, JumpType _jumpType) override; void appendJump(int _stackDiffAfter, JumpType _jumpType) override;
void appendJumpTo(LabelID _labelId, int _stackDiffAfter, JumpType _jumpType) override; void appendJumpTo(LabelID _labelId, int _stackDiffAfter, JumpType _jumpType) override;

View File

@ -2,6 +2,6 @@
// The optimizer assumes verbatim could contain msize, // The optimizer assumes verbatim could contain msize,
// so it cannot optimize the mload away. // so it cannot optimize the mload away.
let x := mload(0x2000) let x := mload(0x2000)
verbatim_0i_0o("") verbatim_0i_0o("aa")
sstore(0, 2) sstore(0, 2)
} }