mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Search & Replace
This commit is contained in:
parent
b44b9285e4
commit
513d5a3265
@ -83,10 +83,10 @@ public:
|
||||
append(AssemblyItem(std::move(_data), _arguments, _returnVariables));
|
||||
}
|
||||
|
||||
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; }
|
||||
AssemblyItem appendJumpI(AssemblyItem const& _tag) { auto ret = append(_tag.pushTag()); append(Instruction::JUMPI); return ret; }
|
||||
AssemblyItem appendJump() { auto ret = append(newPushTag()); append(InternalInstruction::JUMP); return ret; }
|
||||
AssemblyItem appendJumpI() { auto ret = append(newPushTag()); append(InternalInstruction::JUMPI); return ret; }
|
||||
AssemblyItem appendJump(AssemblyItem const& _tag) { auto ret = append(_tag.pushTag()); append(InternalInstruction::JUMP); return ret; }
|
||||
AssemblyItem appendJumpI(AssemblyItem const& _tag) { auto ret = append(_tag.pushTag()); append(InternalInstruction::JUMPI); return ret; }
|
||||
|
||||
/// Adds a subroutine to the code (in the data section) and pushes its size (via a tag)
|
||||
/// on the stack. @returns the pushsub assembly item.
|
||||
|
@ -329,7 +329,7 @@ ostream& solidity::evmasm::operator<<(ostream& _out, AssemblyItem const& _item)
|
||||
{
|
||||
case Operation:
|
||||
_out << " " << instructionInfo(_item.instruction()).name;
|
||||
if (_item.instruction() == Instruction::JUMP || _item.instruction() == Instruction::JUMPI)
|
||||
if (_item.instruction() == InternalInstruction::JUMP || _item.instruction() == InternalInstruction::JUMPI)
|
||||
_out << "\t" << _item.getJumpTypeAsString();
|
||||
break;
|
||||
case Push:
|
||||
|
@ -66,7 +66,7 @@ public:
|
||||
|
||||
AssemblyItem(u256 _push, langutil::SourceLocation _location = langutil::SourceLocation()):
|
||||
AssemblyItem(Push, std::move(_push), std::move(_location)) { }
|
||||
AssemblyItem(Instruction _i, langutil::SourceLocation _location = langutil::SourceLocation()):
|
||||
AssemblyItem(InternalInstruction _i, langutil::SourceLocation _location = langutil::SourceLocation()):
|
||||
m_type(Operation),
|
||||
m_instruction(_i),
|
||||
m_location(std::move(_location))
|
||||
@ -76,7 +76,7 @@ public:
|
||||
m_location(std::move(_location))
|
||||
{
|
||||
if (m_type == Operation)
|
||||
m_instruction = Instruction(uint8_t(_data));
|
||||
m_instruction = InternalInstruction(uint8_t(_data));
|
||||
else
|
||||
m_data = std::make_shared<u256>(std::move(_data));
|
||||
}
|
||||
@ -116,7 +116,7 @@ public:
|
||||
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)
|
||||
Instruction instruction() const { assertThrow(m_type == Operation, util::Exception, ""); return m_instruction; }
|
||||
InternalInstruction instruction() const { assertThrow(m_type == Operation, util::Exception, ""); return m_instruction; }
|
||||
|
||||
/// @returns true if the type and data of the items are equal.
|
||||
bool operator==(AssemblyItem const& _other) const
|
||||
@ -145,11 +145,11 @@ public:
|
||||
}
|
||||
|
||||
/// Shortcut that avoids constructing an AssemblyItem just to perform the comparison.
|
||||
bool operator==(Instruction _instr) const
|
||||
bool operator==(InternalInstruction _instr) const
|
||||
{
|
||||
return type() == Operation && instruction() == _instr;
|
||||
}
|
||||
bool operator!=(Instruction _instr) const { return !operator==(_instr); }
|
||||
bool operator!=(InternalInstruction _instr) const { return !operator==(_instr); }
|
||||
|
||||
static std::string computeSourceMapping(
|
||||
AssemblyItems const& _items,
|
||||
@ -189,7 +189,7 @@ private:
|
||||
size_t opcodeCount() const noexcept;
|
||||
|
||||
AssemblyItemType m_type;
|
||||
Instruction m_instruction; ///< Only valid if m_type == Operation
|
||||
InternalInstruction 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 number of arguments, number of
|
||||
/// return variables and verbatim bytecode.
|
||||
|
@ -132,7 +132,7 @@ BlockDeduplicator::BlockIterator& BlockDeduplicator::BlockIterator::operator++()
|
||||
{
|
||||
if (it == end)
|
||||
return *this;
|
||||
if (SemanticInformation::altersControlFlow(*it) && *it != AssemblyItem{Instruction::JUMPI})
|
||||
if (SemanticInformation::altersControlFlow(*it) && *it != AssemblyItem{InternalInstruction::JUMPI})
|
||||
it = end;
|
||||
else
|
||||
{
|
||||
|
@ -88,36 +88,36 @@ void CommonSubexpressionEliminator::optimizeBreakingItem()
|
||||
|
||||
ExpressionClasses& classes = m_state.expressionClasses();
|
||||
SourceLocation const& itemLocation = m_breakingItem->location();
|
||||
if (*m_breakingItem == AssemblyItem(Instruction::JUMPI))
|
||||
if (*m_breakingItem == AssemblyItem(InternalInstruction::JUMPI))
|
||||
{
|
||||
AssemblyItem::JumpType jumpType = m_breakingItem->getJumpType();
|
||||
|
||||
Id condition = m_state.stackElement(m_state.stackHeight() - 1, itemLocation);
|
||||
if (classes.knownNonZero(condition))
|
||||
{
|
||||
feedItem(AssemblyItem(Instruction::SWAP1, itemLocation), true);
|
||||
feedItem(AssemblyItem(Instruction::POP, itemLocation), true);
|
||||
feedItem(AssemblyItem(InternalInstruction::SWAP1, itemLocation), true);
|
||||
feedItem(AssemblyItem(InternalInstruction::POP, itemLocation), true);
|
||||
|
||||
AssemblyItem item(Instruction::JUMP, itemLocation);
|
||||
AssemblyItem item(InternalInstruction::JUMP, itemLocation);
|
||||
item.setJumpType(jumpType);
|
||||
m_breakingItem = classes.storeItem(item);
|
||||
}
|
||||
else if (classes.knownZero(condition))
|
||||
{
|
||||
AssemblyItem it(Instruction::POP, itemLocation);
|
||||
AssemblyItem it(InternalInstruction::POP, itemLocation);
|
||||
feedItem(it, true);
|
||||
feedItem(it, true);
|
||||
m_breakingItem = nullptr;
|
||||
}
|
||||
}
|
||||
else if (*m_breakingItem == AssemblyItem(Instruction::RETURN))
|
||||
else if (*m_breakingItem == AssemblyItem(InternalInstruction::RETURN))
|
||||
{
|
||||
Id size = m_state.stackElement(m_state.stackHeight() - 1, itemLocation);
|
||||
if (classes.knownZero(size))
|
||||
{
|
||||
feedItem(AssemblyItem(Instruction::POP, itemLocation), true);
|
||||
feedItem(AssemblyItem(Instruction::POP, itemLocation), true);
|
||||
AssemblyItem item(Instruction::STOP, itemLocation);
|
||||
feedItem(AssemblyItem(InternalInstruction::POP, itemLocation), true);
|
||||
feedItem(AssemblyItem(InternalInstruction::POP, itemLocation), true);
|
||||
AssemblyItem item(InternalInstruction::STOP, itemLocation);
|
||||
m_breakingItem = classes.storeItem(item);
|
||||
}
|
||||
}
|
||||
@ -233,15 +233,15 @@ void CSECodeGenerator::addDependencies(Id _c)
|
||||
m_neededBy.insert(make_pair(argument, _c));
|
||||
}
|
||||
if (expr.item && expr.item->type() == Operation && (
|
||||
expr.item->instruction() == Instruction::SLOAD ||
|
||||
expr.item->instruction() == Instruction::MLOAD ||
|
||||
expr.item->instruction() == Instruction::KECCAK256
|
||||
expr.item->instruction() == InternalInstruction::SLOAD ||
|
||||
expr.item->instruction() == InternalInstruction::MLOAD ||
|
||||
expr.item->instruction() == InternalInstruction::KECCAK256
|
||||
))
|
||||
{
|
||||
// this loads an unknown value from storage or memory and thus, in addition to its
|
||||
// arguments, depends on all store operations to addresses where we do not know that
|
||||
// they are different that occur before this load
|
||||
StoreOperation::Target target = expr.item->instruction() == Instruction::SLOAD ?
|
||||
StoreOperation::Target target = expr.item->instruction() == InternalInstruction::SLOAD ?
|
||||
StoreOperation::Storage : StoreOperation::Memory;
|
||||
Id slotToLoadFrom = expr.arguments.at(0);
|
||||
for (auto const& p: m_storeOperations)
|
||||
@ -255,16 +255,16 @@ void CSECodeGenerator::addDependencies(Id _c)
|
||||
bool knownToBeIndependent = false;
|
||||
switch (expr.item->instruction())
|
||||
{
|
||||
case Instruction::SLOAD:
|
||||
case InternalInstruction::SLOAD:
|
||||
knownToBeIndependent = m_expressionClasses.knownToBeDifferent(slot, slotToLoadFrom);
|
||||
break;
|
||||
case Instruction::MLOAD:
|
||||
case InternalInstruction::MLOAD:
|
||||
knownToBeIndependent = m_expressionClasses.knownToBeDifferentBy32(slot, slotToLoadFrom);
|
||||
break;
|
||||
case Instruction::KECCAK256:
|
||||
case InternalInstruction::KECCAK256:
|
||||
{
|
||||
Id length = expr.arguments.at(1);
|
||||
AssemblyItem offsetInstr(Instruction::SUB, expr.item->location());
|
||||
AssemblyItem offsetInstr(InternalInstruction::SUB, expr.item->location());
|
||||
Id offsetToStart = m_expressionClasses.find(offsetInstr, {slot, slotToLoadFrom});
|
||||
u256 const* o = m_expressionClasses.knownConstant(offsetToStart);
|
||||
u256 const* l = m_expressionClasses.knownConstant(length);
|
||||
@ -397,7 +397,7 @@ void CSECodeGenerator::generateClassElement(Id _c, bool _allowSequenced)
|
||||
|
||||
while (SemanticInformation::isCommutativeOperation(*expr.item) &&
|
||||
!m_generatedItems.empty() &&
|
||||
m_generatedItems.back() == AssemblyItem(Instruction::SWAP1))
|
||||
m_generatedItems.back() == AssemblyItem(InternalInstruction::SWAP1))
|
||||
// this will not append a swap but remove the one that is already there
|
||||
appendOrRemoveSwap(m_stackHeight - 1, itemLocation);
|
||||
for (size_t i = 0; i < arguments.size(); ++i)
|
||||
@ -464,7 +464,7 @@ bool CSECodeGenerator::removeStackTopIfPossible()
|
||||
return false;
|
||||
m_classPositions[m_stack[m_stackHeight]].erase(m_stackHeight);
|
||||
m_stack.erase(m_stackHeight);
|
||||
appendItem(AssemblyItem(Instruction::POP));
|
||||
appendItem(AssemblyItem(InternalInstruction::POP));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -84,10 +84,10 @@ bigint ConstantOptimisationMethod::simpleRunGas(AssemblyItems const& _items)
|
||||
bigint gas = 0;
|
||||
for (AssemblyItem const& item: _items)
|
||||
if (item.type() == Push)
|
||||
gas += GasMeter::runGas(Instruction::PUSH1);
|
||||
gas += GasMeter::runGas(InternalInstruction::PUSH1);
|
||||
else if (item.type() == Operation)
|
||||
{
|
||||
if (item.instruction() == Instruction::EXP)
|
||||
if (item.instruction() == InternalInstruction::EXP)
|
||||
gas += GasCosts::expGas;
|
||||
else
|
||||
gas += GasMeter::runGas(item.instruction());
|
||||
@ -131,7 +131,7 @@ void ConstantOptimisationMethod::replaceConstants(
|
||||
bigint LiteralMethod::gasNeeded() const
|
||||
{
|
||||
return combineGas(
|
||||
simpleRunGas({Instruction::PUSH1}),
|
||||
simpleRunGas({InternalInstruction::PUSH1}),
|
||||
// PUSHX plus data
|
||||
(m_params.isCreation ? GasCosts::txDataNonZeroGas(m_params.evmVersion) : GasCosts::createDataGas) + dataGas(toCompactBigEndian(m_value, 1)),
|
||||
0
|
||||
@ -167,22 +167,22 @@ AssemblyItems const& CodeCopyMethod::copyRoutine()
|
||||
|
||||
// back up memory
|
||||
// mload(0)
|
||||
Instruction::DUP1,
|
||||
Instruction::MLOAD,
|
||||
InternalInstruction::DUP1,
|
||||
InternalInstruction::MLOAD,
|
||||
|
||||
// codecopy(0, <offset>, 32)
|
||||
u256(32),
|
||||
AssemblyItem(PushData, u256(1) << 16), // replaced above in actualCopyRoutine[4]
|
||||
Instruction::DUP4,
|
||||
Instruction::CODECOPY,
|
||||
InternalInstruction::DUP4,
|
||||
InternalInstruction::CODECOPY,
|
||||
|
||||
// mload(0)
|
||||
Instruction::DUP2,
|
||||
Instruction::MLOAD,
|
||||
InternalInstruction::DUP2,
|
||||
InternalInstruction::MLOAD,
|
||||
|
||||
// restore original memory
|
||||
Instruction::SWAP2,
|
||||
Instruction::MSTORE
|
||||
InternalInstruction::SWAP2,
|
||||
InternalInstruction::MSTORE
|
||||
};
|
||||
return copyRoutine;
|
||||
}
|
||||
@ -194,7 +194,7 @@ AssemblyItems ComputeMethod::findRepresentation(u256 const& _value)
|
||||
return AssemblyItems{_value};
|
||||
else if (numberEncodingSize(~_value) < numberEncodingSize(_value))
|
||||
// Negated is shorter to represent
|
||||
return findRepresentation(~_value) + AssemblyItems{Instruction::NOT};
|
||||
return findRepresentation(~_value) + AssemblyItems{InternalInstruction::NOT};
|
||||
else
|
||||
{
|
||||
// Decompose value into a * 2**k + b where abs(b) << 2**k
|
||||
@ -226,18 +226,18 @@ AssemblyItems ComputeMethod::findRepresentation(u256 const& _value)
|
||||
if (m_params.evmVersion.hasBitwiseShifting())
|
||||
{
|
||||
newRoutine += findRepresentation(upperPart);
|
||||
newRoutine += AssemblyItems{u256(bits), Instruction::SHL};
|
||||
newRoutine += AssemblyItems{u256(bits), InternalInstruction::SHL};
|
||||
}
|
||||
else
|
||||
{
|
||||
newRoutine += AssemblyItems{u256(bits), u256(2), Instruction::EXP};
|
||||
newRoutine += AssemblyItems{u256(bits), u256(2), InternalInstruction::EXP};
|
||||
if (upperPart != 1)
|
||||
newRoutine += findRepresentation(upperPart) + AssemblyItems{Instruction::MUL};
|
||||
newRoutine += findRepresentation(upperPart) + AssemblyItems{InternalInstruction::MUL};
|
||||
}
|
||||
if (lowerPart > 0)
|
||||
newRoutine += AssemblyItems{Instruction::ADD};
|
||||
newRoutine += AssemblyItems{InternalInstruction::ADD};
|
||||
else if (lowerPart < 0)
|
||||
newRoutine.push_back(Instruction::SUB);
|
||||
newRoutine.push_back(InternalInstruction::SUB);
|
||||
|
||||
if (m_maxSteps > 0)
|
||||
m_maxSteps--;
|
||||
@ -267,24 +267,24 @@ bool ComputeMethod::checkRepresentation(u256 const& _value, AssemblyItems const&
|
||||
u256* sp = &stack.back();
|
||||
switch (item.instruction())
|
||||
{
|
||||
case Instruction::MUL:
|
||||
case InternalInstruction::MUL:
|
||||
sp[-1] = sp[0] * sp[-1];
|
||||
break;
|
||||
case Instruction::EXP:
|
||||
case InternalInstruction::EXP:
|
||||
if (sp[-1] > 0xff)
|
||||
return false;
|
||||
sp[-1] = boost::multiprecision::pow(sp[0], unsigned(sp[-1]));
|
||||
break;
|
||||
case Instruction::ADD:
|
||||
case InternalInstruction::ADD:
|
||||
sp[-1] = sp[0] + sp[-1];
|
||||
break;
|
||||
case Instruction::SUB:
|
||||
case InternalInstruction::SUB:
|
||||
sp[-1] = sp[0] - sp[-1];
|
||||
break;
|
||||
case Instruction::NOT:
|
||||
case InternalInstruction::NOT:
|
||||
sp[0] = ~sp[0];
|
||||
break;
|
||||
case Instruction::SHL:
|
||||
case InternalInstruction::SHL:
|
||||
assertThrow(
|
||||
m_params.evmVersion.hasBitwiseShifting(),
|
||||
OptimizerException,
|
||||
@ -293,7 +293,7 @@ bool ComputeMethod::checkRepresentation(u256 const& _value, AssemblyItems const&
|
||||
assertThrow(sp[0] <= u256(255), OptimizerException, "Invalid shift generated.");
|
||||
sp[-1] = u256(bigint(sp[-1]) << unsigned(sp[0]));
|
||||
break;
|
||||
case Instruction::SHR:
|
||||
case InternalInstruction::SHR:
|
||||
assertThrow(
|
||||
m_params.evmVersion.hasBitwiseShifting(),
|
||||
OptimizerException,
|
||||
@ -320,7 +320,7 @@ bool ComputeMethod::checkRepresentation(u256 const& _value, AssemblyItems const&
|
||||
|
||||
bigint ComputeMethod::gasNeeded(AssemblyItems const& _routine) const
|
||||
{
|
||||
auto numExps = static_cast<size_t>(count(_routine.begin(), _routine.end(), Instruction::EXP));
|
||||
auto numExps = static_cast<size_t>(count(_routine.begin(), _routine.end(), InternalInstruction::EXP));
|
||||
return combineGas(
|
||||
simpleRunGas(_routine) + numExps * (GasCosts::expGas + GasCosts::expByteGas(m_params.evmVersion)),
|
||||
// Data gas for routine: Some bytes are zero, but we ignore them.
|
||||
|
@ -92,9 +92,9 @@ void ControlFlowGraph::splitBlocks()
|
||||
if (SemanticInformation::altersControlFlow(item))
|
||||
{
|
||||
m_blocks[id].end = static_cast<unsigned>(index + 1);
|
||||
if (item == Instruction::JUMP)
|
||||
if (item == InternalInstruction::JUMP)
|
||||
m_blocks[id].endType = BasicBlock::EndType::JUMP;
|
||||
else if (item == Instruction::JUMPI)
|
||||
else if (item == InternalInstruction::JUMPI)
|
||||
m_blocks[id].endType = BasicBlock::EndType::JUMPI;
|
||||
else
|
||||
m_blocks[id].endType = BasicBlock::EndType::STOP;
|
||||
|
@ -148,13 +148,13 @@ ExpressionClasses::Id ExpressionClasses::newClass(SourceLocation const& _locatio
|
||||
bool ExpressionClasses::knownToBeDifferent(ExpressionClasses::Id _a, ExpressionClasses::Id _b)
|
||||
{
|
||||
// Try to simplify "_a - _b" and return true iff the value is a non-zero constant.
|
||||
return knownNonZero(find(Instruction::SUB, {_a, _b}));
|
||||
return knownNonZero(find(InternalInstruction::SUB, {_a, _b}));
|
||||
}
|
||||
|
||||
bool ExpressionClasses::knownToBeDifferentBy32(ExpressionClasses::Id _a, ExpressionClasses::Id _b)
|
||||
{
|
||||
// Try to simplify "_a - _b" and return true iff the value is at least 32 away from zero.
|
||||
u256 const* v = knownConstant(find(Instruction::SUB, {_a, _b}));
|
||||
u256 const* v = knownConstant(find(InternalInstruction::SUB, {_a, _b}));
|
||||
// forbidden interval is ["-31", 31]
|
||||
return v && *v + 31 > u256(62);
|
||||
}
|
||||
@ -166,7 +166,7 @@ bool ExpressionClasses::knownZero(Id _c)
|
||||
|
||||
bool ExpressionClasses::knownNonZero(Id _c)
|
||||
{
|
||||
return Pattern(u256(0)).matches(representative(find(Instruction::ISZERO, {_c})), *this);
|
||||
return Pattern(u256(0)).matches(representative(find(InternalInstruction::ISZERO, {_c})), *this);
|
||||
}
|
||||
|
||||
u256 const* ExpressionClasses::knownConstant(Id _c)
|
||||
|
@ -52,17 +52,17 @@ GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item, bool _
|
||||
case PushProgramSize:
|
||||
case PushLibraryAddress:
|
||||
case PushDeployTimeAddress:
|
||||
gas = runGas(Instruction::PUSH1);
|
||||
gas = runGas(InternalInstruction::PUSH1);
|
||||
break;
|
||||
case Tag:
|
||||
gas = runGas(Instruction::JUMPDEST);
|
||||
gas = runGas(InternalInstruction::JUMPDEST);
|
||||
break;
|
||||
case Operation:
|
||||
{
|
||||
ExpressionClasses& classes = m_state->expressionClasses();
|
||||
switch (_item.instruction())
|
||||
{
|
||||
case Instruction::SSTORE:
|
||||
case InternalInstruction::SSTORE:
|
||||
{
|
||||
ExpressionClasses::Id slot = m_state->relativeStackElement(0);
|
||||
ExpressionClasses::Id value = m_state->relativeStackElement(-1);
|
||||
@ -75,57 +75,57 @@ GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item, bool _
|
||||
gas = GasCosts::totalSstoreSetGas(m_evmVersion);
|
||||
break;
|
||||
}
|
||||
case Instruction::SLOAD:
|
||||
case InternalInstruction::SLOAD:
|
||||
gas = GasCosts::sloadGas(m_evmVersion);
|
||||
break;
|
||||
case Instruction::RETURN:
|
||||
case Instruction::REVERT:
|
||||
case InternalInstruction::RETURN:
|
||||
case InternalInstruction::REVERT:
|
||||
gas = runGas(_item.instruction());
|
||||
gas += memoryGas(0, -1);
|
||||
break;
|
||||
case Instruction::MLOAD:
|
||||
case Instruction::MSTORE:
|
||||
case InternalInstruction::MLOAD:
|
||||
case InternalInstruction::MSTORE:
|
||||
gas = runGas(_item.instruction());
|
||||
gas += memoryGas(classes.find(Instruction::ADD, {
|
||||
gas += memoryGas(classes.find(InternalInstruction::ADD, {
|
||||
m_state->relativeStackElement(0),
|
||||
classes.find(AssemblyItem(32))
|
||||
}));
|
||||
break;
|
||||
case Instruction::MSTORE8:
|
||||
case InternalInstruction::MSTORE8:
|
||||
gas = runGas(_item.instruction());
|
||||
gas += memoryGas(classes.find(Instruction::ADD, {
|
||||
gas += memoryGas(classes.find(InternalInstruction::ADD, {
|
||||
m_state->relativeStackElement(0),
|
||||
classes.find(AssemblyItem(1))
|
||||
}));
|
||||
break;
|
||||
case Instruction::KECCAK256:
|
||||
case InternalInstruction::KECCAK256:
|
||||
gas = GasCosts::keccak256Gas;
|
||||
gas += memoryGas(0, -1);
|
||||
gas += wordGas(GasCosts::keccak256WordGas, m_state->relativeStackElement(-1));
|
||||
break;
|
||||
case Instruction::CALLDATACOPY:
|
||||
case Instruction::CODECOPY:
|
||||
case Instruction::RETURNDATACOPY:
|
||||
case InternalInstruction::CALLDATACOPY:
|
||||
case InternalInstruction::CODECOPY:
|
||||
case InternalInstruction::RETURNDATACOPY:
|
||||
gas = runGas(_item.instruction());
|
||||
gas += memoryGas(0, -2);
|
||||
gas += wordGas(GasCosts::copyGas, m_state->relativeStackElement(-2));
|
||||
break;
|
||||
case Instruction::EXTCODESIZE:
|
||||
case InternalInstruction::EXTCODESIZE:
|
||||
gas = GasCosts::extCodeGas(m_evmVersion);
|
||||
break;
|
||||
case Instruction::EXTCODEHASH:
|
||||
case InternalInstruction::EXTCODEHASH:
|
||||
gas = GasCosts::balanceGas(m_evmVersion);
|
||||
break;
|
||||
case Instruction::EXTCODECOPY:
|
||||
case InternalInstruction::EXTCODECOPY:
|
||||
gas = GasCosts::extCodeGas(m_evmVersion);
|
||||
gas += memoryGas(-1, -3);
|
||||
gas += wordGas(GasCosts::copyGas, m_state->relativeStackElement(-3));
|
||||
break;
|
||||
case Instruction::LOG0:
|
||||
case Instruction::LOG1:
|
||||
case Instruction::LOG2:
|
||||
case Instruction::LOG3:
|
||||
case Instruction::LOG4:
|
||||
case InternalInstruction::LOG0:
|
||||
case InternalInstruction::LOG1:
|
||||
case InternalInstruction::LOG2:
|
||||
case InternalInstruction::LOG3:
|
||||
case InternalInstruction::LOG4:
|
||||
{
|
||||
gas = GasCosts::logGas + GasCosts::logTopicGas * getLogNumber(_item.instruction());
|
||||
gas += memoryGas(0, -1);
|
||||
@ -135,10 +135,10 @@ GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item, bool _
|
||||
gas = GasConsumption::infinite();
|
||||
break;
|
||||
}
|
||||
case Instruction::CALL:
|
||||
case Instruction::CALLCODE:
|
||||
case Instruction::DELEGATECALL:
|
||||
case Instruction::STATICCALL:
|
||||
case InternalInstruction::CALL:
|
||||
case InternalInstruction::CALLCODE:
|
||||
case InternalInstruction::DELEGATECALL:
|
||||
case InternalInstruction::STATICCALL:
|
||||
{
|
||||
if (_includeExternalCosts)
|
||||
// We assume that we do not know the target contract and thus, the consumption is infinite.
|
||||
@ -150,10 +150,10 @@ GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item, bool _
|
||||
gas += (*value);
|
||||
else
|
||||
gas = GasConsumption::infinite();
|
||||
if (_item.instruction() == Instruction::CALL)
|
||||
if (_item.instruction() == InternalInstruction::CALL)
|
||||
gas += GasCosts::callNewAccountGas; // We very rarely know whether the address exists.
|
||||
int valueSize = 1;
|
||||
if (_item.instruction() == Instruction::DELEGATECALL || _item.instruction() == Instruction::STATICCALL)
|
||||
if (_item.instruction() == InternalInstruction::DELEGATECALL || _item.instruction() == InternalInstruction::STATICCALL)
|
||||
valueSize = 0;
|
||||
else if (!classes.knownZero(m_state->relativeStackElement(-1 - valueSize)))
|
||||
gas += GasCosts::callValueTransferGas;
|
||||
@ -162,12 +162,12 @@ GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item, bool _
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Instruction::SELFDESTRUCT:
|
||||
case InternalInstruction::SELFDESTRUCT:
|
||||
gas = GasCosts::selfdestructGas(m_evmVersion);
|
||||
gas += GasCosts::callNewAccountGas; // We very rarely know whether the address exists.
|
||||
break;
|
||||
case Instruction::CREATE:
|
||||
case Instruction::CREATE2:
|
||||
case InternalInstruction::CREATE:
|
||||
case InternalInstruction::CREATE2:
|
||||
if (_includeExternalCosts)
|
||||
// We assume that we do not know the target contract and thus, the consumption is infinite.
|
||||
gas = GasConsumption::infinite();
|
||||
@ -177,7 +177,7 @@ GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item, bool _
|
||||
gas += memoryGas(-1, -2);
|
||||
}
|
||||
break;
|
||||
case Instruction::EXP:
|
||||
case InternalInstruction::EXP:
|
||||
gas = GasCosts::expGas;
|
||||
if (u256 const* value = classes.knownConstant(m_state->relativeStackElement(-1)))
|
||||
{
|
||||
@ -191,14 +191,14 @@ GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item, bool _
|
||||
else
|
||||
gas += GasCosts::expByteGas(m_evmVersion) * 32;
|
||||
break;
|
||||
case Instruction::BALANCE:
|
||||
case InternalInstruction::BALANCE:
|
||||
gas = GasCosts::balanceGas(m_evmVersion);
|
||||
break;
|
||||
case Instruction::CHAINID:
|
||||
gas = runGas(Instruction::CHAINID);
|
||||
case InternalInstruction::CHAINID:
|
||||
gas = runGas(InternalInstruction::CHAINID);
|
||||
break;
|
||||
case Instruction::SELFBALANCE:
|
||||
gas = runGas(Instruction::SELFBALANCE);
|
||||
case InternalInstruction::SELFBALANCE:
|
||||
gas = runGas(InternalInstruction::SELFBALANCE);
|
||||
break;
|
||||
default:
|
||||
gas = runGas(_item.instruction());
|
||||
@ -246,15 +246,15 @@ GasMeter::GasConsumption GasMeter::memoryGas(int _stackPosOffset, int _stackPosS
|
||||
if (classes.knownZero(m_state->relativeStackElement(_stackPosSize)))
|
||||
return GasConsumption(0);
|
||||
else
|
||||
return memoryGas(classes.find(Instruction::ADD, {
|
||||
return memoryGas(classes.find(InternalInstruction::ADD, {
|
||||
m_state->relativeStackElement(_stackPosOffset),
|
||||
m_state->relativeStackElement(_stackPosSize)
|
||||
}));
|
||||
}
|
||||
|
||||
unsigned GasMeter::runGas(Instruction _instruction)
|
||||
unsigned GasMeter::runGas(InternalInstruction _instruction)
|
||||
{
|
||||
if (_instruction == Instruction::JUMPDEST)
|
||||
if (_instruction == InternalInstruction::JUMPDEST)
|
||||
return 1;
|
||||
|
||||
switch (instructionInfo(_instruction).gasPriceTier)
|
||||
|
@ -221,7 +221,7 @@ public:
|
||||
|
||||
/// @returns gas costs for simple instructions with constant gas costs (that do not
|
||||
/// change with EVM versions)
|
||||
static unsigned runGas(Instruction _instruction);
|
||||
static unsigned runGas(InternalInstruction _instruction);
|
||||
|
||||
/// @returns the gas cost of the supplied data, depending whether it is in creation code, or not.
|
||||
/// In case of @a _inCreation, the data is only sent as a transaction and is not stored, whereas
|
||||
|
@ -85,7 +85,7 @@ bool Inliner::isInlineCandidate(size_t _tag, ranges::span<AssemblyItem const> _i
|
||||
if (_items.back().type() != Operation)
|
||||
return false;
|
||||
if (
|
||||
_items.back() != Instruction::JUMP &&
|
||||
_items.back() != InternalInstruction::JUMP &&
|
||||
!SemanticInformation::terminatesControlFlow(_items.back().instruction())
|
||||
)
|
||||
return false;
|
||||
@ -150,13 +150,13 @@ bool Inliner::shouldInlineFullFunctionBody(size_t _tag, ranges::span<AssemblyIte
|
||||
static AssemblyItems const uninlinedCallSitePattern = {
|
||||
AssemblyItem{PushTag},
|
||||
AssemblyItem{PushTag},
|
||||
AssemblyItem{Instruction::JUMP},
|
||||
AssemblyItem{InternalInstruction::JUMP},
|
||||
AssemblyItem{Tag}
|
||||
};
|
||||
static AssemblyItems const uninlinedFunctionPattern = {
|
||||
AssemblyItem{Tag},
|
||||
// Actual function body of size functionBodySize. Handled separately below.
|
||||
AssemblyItem{Instruction::JUMP}
|
||||
AssemblyItem{InternalInstruction::JUMP}
|
||||
};
|
||||
|
||||
// Both the call site and jump site pattern is executed for each call.
|
||||
@ -201,12 +201,12 @@ bool Inliner::shouldInlineFullFunctionBody(size_t _tag, ranges::span<AssemblyIte
|
||||
|
||||
optional<AssemblyItem> Inliner::shouldInline(size_t _tag, AssemblyItem const& _jump, InlinableBlock const& _block) const
|
||||
{
|
||||
assertThrow(_jump == Instruction::JUMP, OptimizerException, "");
|
||||
assertThrow(_jump == InternalInstruction::JUMP, OptimizerException, "");
|
||||
AssemblyItem blockExit = _block.items.back();
|
||||
|
||||
if (
|
||||
_jump.getJumpType() == AssemblyItem::JumpType::IntoFunction &&
|
||||
blockExit == Instruction::JUMP &&
|
||||
blockExit == InternalInstruction::JUMP &&
|
||||
blockExit.getJumpType() == AssemblyItem::JumpType::OutOfFunction &&
|
||||
shouldInlineFullFunctionBody(_tag, _block.items, _block.pushTagCount)
|
||||
)
|
||||
@ -223,7 +223,7 @@ optional<AssemblyItem> Inliner::shouldInline(size_t _tag, AssemblyItem const& _j
|
||||
{
|
||||
static AssemblyItems const jumpPattern = {
|
||||
AssemblyItem{PushTag},
|
||||
AssemblyItem{Instruction::JUMP},
|
||||
AssemblyItem{InternalInstruction::JUMP},
|
||||
};
|
||||
if (
|
||||
GasMeter::dataGas(codeSize(_block.items), m_isCreation, m_evmVersion) <=
|
||||
@ -250,7 +250,7 @@ void Inliner::optimise()
|
||||
if (next(it) != m_items.end())
|
||||
{
|
||||
AssemblyItem const& nextItem = *next(it);
|
||||
if (item.type() == PushTag && nextItem == Instruction::JUMP)
|
||||
if (item.type() == PushTag && nextItem == InternalInstruction::JUMP)
|
||||
{
|
||||
if (optional<size_t> tag = getLocalTag(item))
|
||||
if (auto* inlinableBlock = util::valueOrNullptr(inlinableBlocks, *tag))
|
||||
|
@ -97,8 +97,8 @@ KnownState::StoreOperation KnownState::feedItem(AssemblyItem const& _item, bool
|
||||
// Since AssignImmutable breaks blocks, it should be fine to only consider its changes to the stack, which
|
||||
// is the same as two POPs.
|
||||
// Note that the StoreOperation for POP is generic and _copyItem is ignored.
|
||||
feedItem(AssemblyItem(Instruction::POP), _copyItem);
|
||||
return feedItem(AssemblyItem(Instruction::POP), _copyItem);
|
||||
feedItem(AssemblyItem(InternalInstruction::POP), _copyItem);
|
||||
return feedItem(AssemblyItem(InternalInstruction::POP), _copyItem);
|
||||
}
|
||||
else if (_item.type() == VerbatimBytecode)
|
||||
{
|
||||
@ -129,48 +129,48 @@ KnownState::StoreOperation KnownState::feedItem(AssemblyItem const& _item, bool
|
||||
}
|
||||
else
|
||||
{
|
||||
Instruction instruction = _item.instruction();
|
||||
InternalInstruction instruction = _item.instruction();
|
||||
InstructionInfo info = instructionInfo(instruction);
|
||||
if (SemanticInformation::isDupInstruction(_item))
|
||||
setStackElement(
|
||||
m_stackHeight + 1,
|
||||
stackElement(
|
||||
m_stackHeight - static_cast<int>(instruction) + static_cast<int>(Instruction::DUP1),
|
||||
m_stackHeight - static_cast<int>(instruction) + static_cast<int>(InternalInstruction::DUP1),
|
||||
_item.location()
|
||||
)
|
||||
);
|
||||
else if (SemanticInformation::isSwapInstruction(_item))
|
||||
swapStackElements(
|
||||
m_stackHeight,
|
||||
m_stackHeight - 1 - static_cast<int>(instruction) + static_cast<int>(Instruction::SWAP1),
|
||||
m_stackHeight - 1 - static_cast<int>(instruction) + static_cast<int>(InternalInstruction::SWAP1),
|
||||
_item.location()
|
||||
);
|
||||
else if (instruction != Instruction::POP)
|
||||
else if (instruction != InternalInstruction::POP)
|
||||
{
|
||||
vector<Id> arguments(static_cast<size_t>(info.args));
|
||||
for (size_t i = 0; i < static_cast<size_t>(info.args); ++i)
|
||||
arguments[i] = stackElement(m_stackHeight - static_cast<int>(i), _item.location());
|
||||
switch (_item.instruction())
|
||||
{
|
||||
case Instruction::SSTORE:
|
||||
case InternalInstruction::SSTORE:
|
||||
op = storeInStorage(arguments[0], arguments[1], _item.location());
|
||||
break;
|
||||
case Instruction::SLOAD:
|
||||
case InternalInstruction::SLOAD:
|
||||
setStackElement(
|
||||
m_stackHeight + static_cast<int>(_item.deposit()),
|
||||
loadFromStorage(arguments[0], _item.location())
|
||||
);
|
||||
break;
|
||||
case Instruction::MSTORE:
|
||||
case InternalInstruction::MSTORE:
|
||||
op = storeInMemory(arguments[0], arguments[1], _item.location());
|
||||
break;
|
||||
case Instruction::MLOAD:
|
||||
case InternalInstruction::MLOAD:
|
||||
setStackElement(
|
||||
m_stackHeight + static_cast<int>(_item.deposit()),
|
||||
loadFromMemory(arguments[0], _item.location())
|
||||
);
|
||||
break;
|
||||
case Instruction::KECCAK256:
|
||||
case InternalInstruction::KECCAK256:
|
||||
setStackElement(
|
||||
m_stackHeight + static_cast<int>(_item.deposit()),
|
||||
applyKeccak256(arguments.at(0), arguments.at(1), _item.location())
|
||||
@ -335,7 +335,7 @@ KnownState::StoreOperation KnownState::storeInStorage(
|
||||
storageContents.insert(storageItem);
|
||||
m_storageContent = std::move(storageContents);
|
||||
|
||||
AssemblyItem item(Instruction::SSTORE, _location);
|
||||
AssemblyItem item(InternalInstruction::SSTORE, _location);
|
||||
Id id = m_expressionClasses->find(item, {_slot, _value}, true, m_sequenceNumber);
|
||||
StoreOperation operation{StoreOperation::Storage, _slot, m_sequenceNumber, id};
|
||||
m_storageContent[_slot] = _value;
|
||||
@ -350,7 +350,7 @@ ExpressionClasses::Id KnownState::loadFromStorage(Id _slot, SourceLocation const
|
||||
if (m_storageContent.count(_slot))
|
||||
return m_storageContent.at(_slot);
|
||||
|
||||
AssemblyItem item(Instruction::SLOAD, _location);
|
||||
AssemblyItem item(InternalInstruction::SLOAD, _location);
|
||||
return m_storageContent[_slot] = m_expressionClasses->find(item, {_slot}, true, m_sequenceNumber);
|
||||
}
|
||||
|
||||
@ -367,7 +367,7 @@ KnownState::StoreOperation KnownState::storeInMemory(Id _slot, Id _value, Source
|
||||
memoryContents.insert(memoryItem);
|
||||
m_memoryContent = std::move(memoryContents);
|
||||
|
||||
AssemblyItem item(Instruction::MSTORE, _location);
|
||||
AssemblyItem item(InternalInstruction::MSTORE, _location);
|
||||
Id id = m_expressionClasses->find(item, {_slot, _value}, true, m_sequenceNumber);
|
||||
StoreOperation operation{StoreOperation::Memory, _slot, m_sequenceNumber, id};
|
||||
m_memoryContent[_slot] = _value;
|
||||
@ -381,7 +381,7 @@ ExpressionClasses::Id KnownState::loadFromMemory(Id _slot, SourceLocation const&
|
||||
if (m_memoryContent.count(_slot))
|
||||
return m_memoryContent.at(_slot);
|
||||
|
||||
AssemblyItem item(Instruction::MLOAD, _location);
|
||||
AssemblyItem item(InternalInstruction::MLOAD, _location);
|
||||
return m_memoryContent[_slot] = m_expressionClasses->find(item, {_slot}, true, m_sequenceNumber);
|
||||
}
|
||||
|
||||
@ -391,7 +391,7 @@ KnownState::Id KnownState::applyKeccak256(
|
||||
SourceLocation const& _location
|
||||
)
|
||||
{
|
||||
AssemblyItem keccak256Item(Instruction::KECCAK256, _location);
|
||||
AssemblyItem keccak256Item(InternalInstruction::KECCAK256, _location);
|
||||
// Special logic if length is a short constant, otherwise we cannot tell.
|
||||
u256 const* l = m_expressionClasses->knownConstant(_length);
|
||||
// unknown or too large length
|
||||
@ -402,7 +402,7 @@ KnownState::Id KnownState::applyKeccak256(
|
||||
for (unsigned i = 0; i < length; i += 32)
|
||||
{
|
||||
Id slot = m_expressionClasses->find(
|
||||
AssemblyItem(Instruction::ADD, _location),
|
||||
AssemblyItem(InternalInstruction::ADD, _location),
|
||||
{_start, m_expressionClasses->find(u256(i))}
|
||||
);
|
||||
arguments.push_back(loadFromMemory(slot, _location));
|
||||
|
@ -88,7 +88,7 @@ GasMeter::GasConsumption PathGasMeter::handleQueueItem()
|
||||
bool branchStops = false;
|
||||
jumpTags.clear();
|
||||
AssemblyItem const& item = m_items.at(index);
|
||||
if (item.type() == Tag || item == AssemblyItem(Instruction::JUMPDEST))
|
||||
if (item.type() == Tag || item == AssemblyItem(InternalInstruction::JUMPDEST))
|
||||
{
|
||||
// Do not allow any backwards jump. This is quite restrictive but should work for
|
||||
// the simplest things.
|
||||
@ -96,14 +96,14 @@ GasMeter::GasConsumption PathGasMeter::handleQueueItem()
|
||||
return GasMeter::GasConsumption::infinite();
|
||||
path->visitedJumpdests.insert(index);
|
||||
}
|
||||
else if (item == AssemblyItem(Instruction::JUMP))
|
||||
else if (item == AssemblyItem(InternalInstruction::JUMP))
|
||||
{
|
||||
branchStops = true;
|
||||
jumpTags = state->tagsInExpression(state->relativeStackElement(0));
|
||||
if (jumpTags.empty()) // unknown jump destination
|
||||
return GasMeter::GasConsumption::infinite();
|
||||
}
|
||||
else if (item == AssemblyItem(Instruction::JUMPI))
|
||||
else if (item == AssemblyItem(InternalInstruction::JUMPI))
|
||||
{
|
||||
ExpressionClasses::Id condition = state->relativeStackElement(-1);
|
||||
if (classes.knownNonZero(condition) || !classes.knownZero(condition))
|
||||
|
@ -87,7 +87,7 @@ struct PushPop: SimplePeepholeOptimizerMethod<PushPop>
|
||||
static bool applySimple(AssemblyItem const& _push, AssemblyItem const& _pop, std::back_insert_iterator<AssemblyItems>)
|
||||
{
|
||||
auto t = _push.type();
|
||||
return _pop == Instruction::POP && (
|
||||
return _pop == InternalInstruction::POP && (
|
||||
SemanticInformation::isDupInstruction(_push) ||
|
||||
t == Push || t == PushTag || t == PushSub ||
|
||||
t == PushSubSize || t == PushProgramSize || t == PushData || t == PushLibraryAddress
|
||||
@ -103,13 +103,13 @@ struct OpPop: SimplePeepholeOptimizerMethod<OpPop>
|
||||
std::back_insert_iterator<AssemblyItems> _out
|
||||
)
|
||||
{
|
||||
if (_pop == Instruction::POP && _op.type() == Operation)
|
||||
if (_pop == InternalInstruction::POP && _op.type() == Operation)
|
||||
{
|
||||
Instruction instr = _op.instruction();
|
||||
InternalInstruction instr = _op.instruction();
|
||||
if (instructionInfo(instr).ret == 1 && !instructionInfo(instr).sideEffects)
|
||||
{
|
||||
for (int j = 0; j < instructionInfo(instr).args; j++)
|
||||
*_out = {Instruction::POP, _op.location()};
|
||||
*_out = {InternalInstruction::POP, _op.location()};
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -125,20 +125,20 @@ struct OpStop: SimplePeepholeOptimizerMethod<OpStop>
|
||||
std::back_insert_iterator<AssemblyItems> _out
|
||||
)
|
||||
{
|
||||
if (_stop == Instruction::STOP)
|
||||
if (_stop == InternalInstruction::STOP)
|
||||
{
|
||||
if (_op.type() == Operation)
|
||||
{
|
||||
Instruction instr = _op.instruction();
|
||||
InternalInstruction instr = _op.instruction();
|
||||
if (!instructionInfo(instr).sideEffects)
|
||||
{
|
||||
*_out = {Instruction::STOP, _op.location()};
|
||||
*_out = {InternalInstruction::STOP, _op.location()};
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (_op.type() == Push)
|
||||
{
|
||||
*_out = {Instruction::STOP, _op.location()};
|
||||
*_out = {InternalInstruction::STOP, _op.location()};
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -157,7 +157,7 @@ struct OpReturnRevert: SimplePeepholeOptimizerMethod<OpReturnRevert>
|
||||
)
|
||||
{
|
||||
if (
|
||||
(_returnRevert == Instruction::RETURN || _returnRevert == Instruction::REVERT) &&
|
||||
(_returnRevert == InternalInstruction::RETURN || _returnRevert == InternalInstruction::REVERT) &&
|
||||
_push.type() == Push &&
|
||||
(_pushOrDup.type() == Push || _pushOrDup == dupInstruction(1))
|
||||
)
|
||||
@ -190,7 +190,7 @@ struct DoublePush: SimplePeepholeOptimizerMethod<DoublePush>
|
||||
if (_push1.type() == Push && _push2.type() == Push && _push1.data() == _push2.data())
|
||||
{
|
||||
*_out = _push1;
|
||||
*_out = {Instruction::DUP1, _push2.location()};
|
||||
*_out = {InternalInstruction::DUP1, _push2.location()};
|
||||
return true;
|
||||
}
|
||||
else
|
||||
@ -204,7 +204,7 @@ struct CommutativeSwap: SimplePeepholeOptimizerMethod<CommutativeSwap>
|
||||
{
|
||||
// Remove SWAP1 if following instruction is commutative
|
||||
if (
|
||||
_swap == Instruction::SWAP1 &&
|
||||
_swap == InternalInstruction::SWAP1 &&
|
||||
SemanticInformation::isCommutativeOperation(_op)
|
||||
)
|
||||
{
|
||||
@ -220,15 +220,15 @@ struct SwapComparison: SimplePeepholeOptimizerMethod<SwapComparison>
|
||||
{
|
||||
static bool applySimple(AssemblyItem const& _swap, AssemblyItem const& _op, std::back_insert_iterator<AssemblyItems> _out)
|
||||
{
|
||||
static map<Instruction, Instruction> const swappableOps{
|
||||
{ Instruction::LT, Instruction::GT },
|
||||
{ Instruction::GT, Instruction::LT },
|
||||
{ Instruction::SLT, Instruction::SGT },
|
||||
{ Instruction::SGT, Instruction::SLT }
|
||||
static map<InternalInstruction, InternalInstruction> const swappableOps{
|
||||
{ InternalInstruction::LT, InternalInstruction::GT },
|
||||
{ InternalInstruction::GT, InternalInstruction::LT },
|
||||
{ InternalInstruction::SLT, InternalInstruction::SGT },
|
||||
{ InternalInstruction::SGT, InternalInstruction::SLT }
|
||||
};
|
||||
|
||||
if (
|
||||
_swap == Instruction::SWAP1 &&
|
||||
_swap == InternalInstruction::SWAP1 &&
|
||||
_op.type() == Operation &&
|
||||
swappableOps.count(_op.instruction())
|
||||
)
|
||||
@ -276,10 +276,10 @@ struct IsZeroIsZeroJumpI: SimplePeepholeOptimizerMethod<IsZeroIsZeroJumpI>
|
||||
)
|
||||
{
|
||||
if (
|
||||
_iszero1 == Instruction::ISZERO &&
|
||||
_iszero2 == Instruction::ISZERO &&
|
||||
_iszero1 == InternalInstruction::ISZERO &&
|
||||
_iszero2 == InternalInstruction::ISZERO &&
|
||||
_pushTag.type() == PushTag &&
|
||||
_jumpi == Instruction::JUMPI
|
||||
_jumpi == InternalInstruction::JUMPI
|
||||
)
|
||||
{
|
||||
*_out = _pushTag;
|
||||
@ -302,13 +302,13 @@ struct EqIsZeroJumpI: SimplePeepholeOptimizerMethod<EqIsZeroJumpI>
|
||||
)
|
||||
{
|
||||
if (
|
||||
_eq == Instruction::EQ &&
|
||||
_iszero == Instruction::ISZERO &&
|
||||
_eq == InternalInstruction::EQ &&
|
||||
_iszero == InternalInstruction::ISZERO &&
|
||||
_pushTag.type() == PushTag &&
|
||||
_jumpi == Instruction::JUMPI
|
||||
_jumpi == InternalInstruction::JUMPI
|
||||
)
|
||||
{
|
||||
*_out = AssemblyItem(Instruction::SUB, _eq.location());
|
||||
*_out = AssemblyItem(InternalInstruction::SUB, _eq.location());
|
||||
*_out = _pushTag;
|
||||
*_out = _jumpi;
|
||||
return true;
|
||||
@ -332,14 +332,14 @@ struct DoubleJump: SimplePeepholeOptimizerMethod<DoubleJump>
|
||||
{
|
||||
if (
|
||||
_pushTag1.type() == PushTag &&
|
||||
_jumpi == Instruction::JUMPI &&
|
||||
_jumpi == InternalInstruction::JUMPI &&
|
||||
_pushTag2.type() == PushTag &&
|
||||
_jump == Instruction::JUMP &&
|
||||
_jump == InternalInstruction::JUMP &&
|
||||
_tag1.type() == Tag &&
|
||||
_pushTag1.data() == _tag1.data()
|
||||
)
|
||||
{
|
||||
*_out = AssemblyItem(Instruction::ISZERO, _jumpi.location());
|
||||
*_out = AssemblyItem(InternalInstruction::ISZERO, _jumpi.location());
|
||||
*_out = _pushTag2;
|
||||
*_out = _jumpi;
|
||||
*_out = _tag1;
|
||||
@ -361,13 +361,13 @@ struct JumpToNext: SimplePeepholeOptimizerMethod<JumpToNext>
|
||||
{
|
||||
if (
|
||||
_pushTag.type() == PushTag &&
|
||||
(_jump == Instruction::JUMP || _jump == Instruction::JUMPI) &&
|
||||
(_jump == InternalInstruction::JUMP || _jump == InternalInstruction::JUMPI) &&
|
||||
_tag.type() == Tag &&
|
||||
_pushTag.data() == _tag.data()
|
||||
)
|
||||
{
|
||||
if (_jump == Instruction::JUMPI)
|
||||
*_out = AssemblyItem(Instruction::POP, _jump.location());
|
||||
if (_jump == InternalInstruction::JUMPI)
|
||||
*_out = AssemblyItem(InternalInstruction::POP, _jump.location());
|
||||
*_out = _tag;
|
||||
return true;
|
||||
}
|
||||
@ -385,7 +385,7 @@ struct TagConjunctions: SimplePeepholeOptimizerMethod<TagConjunctions>
|
||||
std::back_insert_iterator<AssemblyItems> _out
|
||||
)
|
||||
{
|
||||
if (_and != Instruction::AND)
|
||||
if (_and != InternalInstruction::AND)
|
||||
return false;
|
||||
if (
|
||||
_pushTag.type() == PushTag &&
|
||||
@ -422,8 +422,8 @@ struct TruthyAnd: SimplePeepholeOptimizerMethod<TruthyAnd>
|
||||
{
|
||||
return (
|
||||
_push.type() == Push && _push.data() == 0 &&
|
||||
_not == Instruction::NOT &&
|
||||
_and == Instruction::AND
|
||||
_not == InternalInstruction::NOT &&
|
||||
_and == InternalInstruction::AND
|
||||
);
|
||||
}
|
||||
};
|
||||
@ -438,12 +438,12 @@ struct UnreachableCode
|
||||
if (it == end)
|
||||
return false;
|
||||
if (
|
||||
it[0] != Instruction::JUMP &&
|
||||
it[0] != Instruction::RETURN &&
|
||||
it[0] != Instruction::STOP &&
|
||||
it[0] != Instruction::INVALID &&
|
||||
it[0] != Instruction::SELFDESTRUCT &&
|
||||
it[0] != Instruction::REVERT
|
||||
it[0] != InternalInstruction::JUMP &&
|
||||
it[0] != InternalInstruction::RETURN &&
|
||||
it[0] != InternalInstruction::STOP &&
|
||||
it[0] != InternalInstruction::INVALID &&
|
||||
it[0] != InternalInstruction::SELFDESTRUCT &&
|
||||
it[0] != InternalInstruction::REVERT
|
||||
)
|
||||
return false;
|
||||
|
||||
@ -475,7 +475,7 @@ void applyMethods(OptimiserState& _state, Method, OtherMethods... _other)
|
||||
|
||||
size_t numberOfPops(AssemblyItems const& _items)
|
||||
{
|
||||
return static_cast<size_t>(std::count(_items.begin(), _items.end(), Instruction::POP));
|
||||
return static_cast<size_t>(std::count(_items.begin(), _items.end(), InternalInstruction::POP));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -367,10 +367,10 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart5(
|
||||
});
|
||||
|
||||
for (auto instr: {
|
||||
Instruction::ADDRESS,
|
||||
Instruction::CALLER,
|
||||
Instruction::ORIGIN,
|
||||
Instruction::COINBASE
|
||||
InternalInstruction::ADDRESS,
|
||||
InternalInstruction::CALLER,
|
||||
InternalInstruction::ORIGIN,
|
||||
InternalInstruction::COINBASE
|
||||
})
|
||||
{
|
||||
assertThrow(Pattern::WordSize > 160, OptimizerException, "");
|
||||
@ -402,11 +402,11 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart6(
|
||||
std::vector<SimplificationRule<Pattern>> rules;
|
||||
// Double negation of opcodes with boolean result
|
||||
for (auto instr: {
|
||||
Instruction::EQ,
|
||||
Instruction::LT,
|
||||
Instruction::SLT,
|
||||
Instruction::GT,
|
||||
Instruction::SGT
|
||||
InternalInstruction::EQ,
|
||||
InternalInstruction::LT,
|
||||
InternalInstruction::SLT,
|
||||
InternalInstruction::GT,
|
||||
InternalInstruction::SGT
|
||||
})
|
||||
{
|
||||
typename Builtins::PatternGeneratorInstance op{instr};
|
||||
@ -448,12 +448,12 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart7(
|
||||
|
||||
std::vector<SimplificationRule<Pattern>> rules;
|
||||
// Associative operations
|
||||
for (auto&& instrAndFunc: std::vector<std::pair<Instruction, std::function<Word(Word, Word)>>>{
|
||||
{Instruction::ADD, std::plus<Word>()},
|
||||
{Instruction::MUL, std::multiplies<Word>()},
|
||||
{Instruction::AND, std::bit_and<Word>()},
|
||||
{Instruction::OR, std::bit_or<Word>()},
|
||||
{Instruction::XOR, std::bit_xor<Word>()}
|
||||
for (auto&& instrAndFunc: std::vector<std::pair<InternalInstruction, std::function<Word(Word, Word)>>>{
|
||||
{InternalInstruction::ADD, std::plus<Word>()},
|
||||
{InternalInstruction::MUL, std::multiplies<Word>()},
|
||||
{InternalInstruction::AND, std::bit_and<Word>()},
|
||||
{InternalInstruction::OR, std::bit_or<Word>()},
|
||||
{InternalInstruction::XOR, std::bit_xor<Word>()}
|
||||
})
|
||||
{
|
||||
typename Builtins::PatternGeneratorInstance op{instrAndFunc.first};
|
||||
@ -544,12 +544,12 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart7(
|
||||
});
|
||||
|
||||
// Move AND with constant across SHL and SHR by constant
|
||||
for (auto instr: {Instruction::SHL, Instruction::SHR})
|
||||
for (auto instr: {InternalInstruction::SHL, InternalInstruction::SHR})
|
||||
{
|
||||
typename Builtins::PatternGeneratorInstance shiftOp{instr};
|
||||
auto replacement = [=]() -> Pattern {
|
||||
Word mask =
|
||||
instr == Instruction::SHL ?
|
||||
instr == InternalInstruction::SHL ?
|
||||
shlWorkaround(A.d(), unsigned(B.d())) :
|
||||
A.d() >> unsigned(B.d());
|
||||
return Builtins::AND(shiftOp(B.d(), X), std::move(mask));
|
||||
@ -743,8 +743,8 @@ std::vector<SimplificationRule<Pattern>> evmRuleList(
|
||||
|
||||
if (_evmVersion.hasSelfBalance())
|
||||
rules.push_back({
|
||||
Builtins::BALANCE(Instruction::ADDRESS),
|
||||
[]() -> Pattern { return Instruction::SELFBALANCE; }
|
||||
Builtins::BALANCE(InternalInstruction::ADDRESS),
|
||||
[]() -> Pattern { return InternalInstruction::SELFBALANCE; }
|
||||
});
|
||||
|
||||
rules.emplace_back(
|
||||
|
@ -29,12 +29,12 @@ using namespace std;
|
||||
using namespace solidity;
|
||||
using namespace solidity::evmasm;
|
||||
|
||||
vector<SemanticInformation::Operation> SemanticInformation::readWriteOperations(Instruction _instruction)
|
||||
vector<SemanticInformation::Operation> SemanticInformation::readWriteOperations(InternalInstruction _instruction)
|
||||
{
|
||||
switch (_instruction)
|
||||
{
|
||||
case Instruction::SSTORE:
|
||||
case Instruction::SLOAD:
|
||||
case InternalInstruction::SSTORE:
|
||||
case InternalInstruction::SLOAD:
|
||||
{
|
||||
assertThrow(memory(_instruction) == Effect::None, OptimizerException, "");
|
||||
assertThrow(storage(_instruction) != Effect::None, OptimizerException, "");
|
||||
@ -46,9 +46,9 @@ vector<SemanticInformation::Operation> SemanticInformation::readWriteOperations(
|
||||
op.lengthConstant = 1;
|
||||
return {op};
|
||||
}
|
||||
case Instruction::MSTORE:
|
||||
case Instruction::MSTORE8:
|
||||
case Instruction::MLOAD:
|
||||
case InternalInstruction::MSTORE:
|
||||
case InternalInstruction::MSTORE8:
|
||||
case InternalInstruction::MLOAD:
|
||||
{
|
||||
assertThrow(memory(_instruction) != Effect::None, OptimizerException, "");
|
||||
assertThrow(storage(_instruction) == Effect::None, OptimizerException, "");
|
||||
@ -56,21 +56,21 @@ vector<SemanticInformation::Operation> SemanticInformation::readWriteOperations(
|
||||
op.effect = memory(_instruction);
|
||||
op.location = Location::Memory;
|
||||
op.startParameter = 0;
|
||||
if (_instruction == Instruction::MSTORE || _instruction == Instruction::MLOAD)
|
||||
if (_instruction == InternalInstruction::MSTORE || _instruction == InternalInstruction::MLOAD)
|
||||
op.lengthConstant = 32;
|
||||
else if (_instruction == Instruction::MSTORE8)
|
||||
else if (_instruction == InternalInstruction::MSTORE8)
|
||||
op.lengthConstant = 1;
|
||||
|
||||
return {op};
|
||||
}
|
||||
case Instruction::REVERT:
|
||||
case Instruction::RETURN:
|
||||
case Instruction::KECCAK256:
|
||||
case Instruction::LOG0:
|
||||
case Instruction::LOG1:
|
||||
case Instruction::LOG2:
|
||||
case Instruction::LOG3:
|
||||
case Instruction::LOG4:
|
||||
case InternalInstruction::REVERT:
|
||||
case InternalInstruction::RETURN:
|
||||
case InternalInstruction::KECCAK256:
|
||||
case InternalInstruction::LOG0:
|
||||
case InternalInstruction::LOG1:
|
||||
case InternalInstruction::LOG2:
|
||||
case InternalInstruction::LOG3:
|
||||
case InternalInstruction::LOG4:
|
||||
{
|
||||
assertThrow(storage(_instruction) == Effect::None, OptimizerException, "");
|
||||
assertThrow(memory(_instruction) == Effect::Read, OptimizerException, "");
|
||||
@ -81,7 +81,7 @@ vector<SemanticInformation::Operation> SemanticInformation::readWriteOperations(
|
||||
op.lengthParameter = 1;
|
||||
return {op};
|
||||
}
|
||||
case Instruction::EXTCODECOPY:
|
||||
case InternalInstruction::EXTCODECOPY:
|
||||
{
|
||||
assertThrow(memory(_instruction) == Effect::Write, OptimizerException, "");
|
||||
assertThrow(storage(_instruction) == Effect::None, OptimizerException, "");
|
||||
@ -92,9 +92,9 @@ vector<SemanticInformation::Operation> SemanticInformation::readWriteOperations(
|
||||
op.lengthParameter = 3;
|
||||
return {op};
|
||||
}
|
||||
case Instruction::CODECOPY:
|
||||
case Instruction::CALLDATACOPY:
|
||||
case Instruction::RETURNDATACOPY:
|
||||
case InternalInstruction::CODECOPY:
|
||||
case InternalInstruction::CALLDATACOPY:
|
||||
case InternalInstruction::RETURNDATACOPY:
|
||||
{
|
||||
assertThrow(memory(_instruction) == Effect::Write, OptimizerException, "");
|
||||
assertThrow(storage(_instruction) == Effect::None, OptimizerException, "");
|
||||
@ -105,17 +105,17 @@ vector<SemanticInformation::Operation> SemanticInformation::readWriteOperations(
|
||||
op.lengthParameter = 2;
|
||||
return {op};
|
||||
}
|
||||
case Instruction::STATICCALL:
|
||||
case Instruction::CALL:
|
||||
case Instruction::CALLCODE:
|
||||
case Instruction::DELEGATECALL:
|
||||
case InternalInstruction::STATICCALL:
|
||||
case InternalInstruction::CALL:
|
||||
case InternalInstruction::CALLCODE:
|
||||
case InternalInstruction::DELEGATECALL:
|
||||
{
|
||||
size_t paramCount = static_cast<size_t>(instructionInfo(_instruction).args);
|
||||
vector<Operation> operations{
|
||||
Operation{Location::Memory, Effect::Read, paramCount - 4, paramCount - 3, {}},
|
||||
Operation{Location::Storage, Effect::Read, {}, {}, {}}
|
||||
};
|
||||
if (_instruction != Instruction::STATICCALL)
|
||||
if (_instruction != InternalInstruction::STATICCALL)
|
||||
operations.emplace_back(Operation{Location::Storage, Effect::Write, {}, {}, {}});
|
||||
operations.emplace_back(Operation{
|
||||
Location::Memory,
|
||||
@ -128,8 +128,8 @@ vector<SemanticInformation::Operation> SemanticInformation::readWriteOperations(
|
||||
});
|
||||
return operations;
|
||||
}
|
||||
case Instruction::CREATE:
|
||||
case Instruction::CREATE2:
|
||||
case InternalInstruction::CREATE:
|
||||
case InternalInstruction::CREATE2:
|
||||
return vector<Operation>{
|
||||
Operation{
|
||||
Location::Memory,
|
||||
@ -141,7 +141,7 @@ vector<SemanticInformation::Operation> SemanticInformation::readWriteOperations(
|
||||
Operation{Location::Storage, Effect::Read, {}, {}, {}},
|
||||
Operation{Location::Storage, Effect::Write, {}, {}, {}}
|
||||
};
|
||||
case Instruction::MSIZE:
|
||||
case InternalInstruction::MSIZE:
|
||||
// This is just to satisfy the assert below.
|
||||
return vector<Operation>{};
|
||||
default:
|
||||
@ -174,18 +174,18 @@ bool SemanticInformation::breaksCSEAnalysisBlock(AssemblyItem const& _item, bool
|
||||
{
|
||||
if (isSwapInstruction(_item) || isDupInstruction(_item))
|
||||
return false;
|
||||
if (_item.instruction() == Instruction::GAS || _item.instruction() == Instruction::PC)
|
||||
if (_item.instruction() == InternalInstruction::GAS || _item.instruction() == InternalInstruction::PC)
|
||||
return true; // GAS and PC assume a specific order of opcodes
|
||||
if (_item.instruction() == Instruction::MSIZE)
|
||||
if (_item.instruction() == InternalInstruction::MSIZE)
|
||||
return true; // msize is modified already by memory access, avoid that for now
|
||||
InstructionInfo info = instructionInfo(_item.instruction());
|
||||
if (_item.instruction() == Instruction::SSTORE)
|
||||
if (_item.instruction() == InternalInstruction::SSTORE)
|
||||
return false;
|
||||
if (_item.instruction() == Instruction::MSTORE)
|
||||
if (_item.instruction() == InternalInstruction::MSTORE)
|
||||
return false;
|
||||
if (!_msizeImportant && (
|
||||
_item.instruction() == Instruction::MLOAD ||
|
||||
_item.instruction() == Instruction::KECCAK256
|
||||
_item.instruction() == InternalInstruction::MLOAD ||
|
||||
_item.instruction() == InternalInstruction::KECCAK256
|
||||
))
|
||||
return false;
|
||||
//@todo: We do not handle the following memory instructions for now:
|
||||
@ -204,12 +204,12 @@ bool SemanticInformation::isCommutativeOperation(AssemblyItem const& _item)
|
||||
return false;
|
||||
switch (_item.instruction())
|
||||
{
|
||||
case Instruction::ADD:
|
||||
case Instruction::MUL:
|
||||
case Instruction::EQ:
|
||||
case Instruction::AND:
|
||||
case Instruction::OR:
|
||||
case Instruction::XOR:
|
||||
case InternalInstruction::ADD:
|
||||
case InternalInstruction::MUL:
|
||||
case InternalInstruction::EQ:
|
||||
case InternalInstruction::AND:
|
||||
case InternalInstruction::OR:
|
||||
case InternalInstruction::XOR:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@ -232,7 +232,7 @@ bool SemanticInformation::isSwapInstruction(AssemblyItem const& _item)
|
||||
|
||||
bool SemanticInformation::isJumpInstruction(AssemblyItem const& _item)
|
||||
{
|
||||
return _item == Instruction::JUMP || _item == Instruction::JUMPI;
|
||||
return _item == InternalInstruction::JUMP || _item == InternalInstruction::JUMPI;
|
||||
}
|
||||
|
||||
bool SemanticInformation::altersControlFlow(AssemblyItem const& _item)
|
||||
@ -243,40 +243,40 @@ bool SemanticInformation::altersControlFlow(AssemblyItem const& _item)
|
||||
{
|
||||
// note that CALL, CALLCODE and CREATE do not really alter the control flow, because we
|
||||
// continue on the next instruction
|
||||
case Instruction::JUMP:
|
||||
case Instruction::JUMPI:
|
||||
case Instruction::RETURN:
|
||||
case Instruction::SELFDESTRUCT:
|
||||
case Instruction::STOP:
|
||||
case Instruction::INVALID:
|
||||
case Instruction::REVERT:
|
||||
case InternalInstruction::JUMP:
|
||||
case InternalInstruction::JUMPI:
|
||||
case InternalInstruction::RETURN:
|
||||
case InternalInstruction::SELFDESTRUCT:
|
||||
case InternalInstruction::STOP:
|
||||
case InternalInstruction::INVALID:
|
||||
case InternalInstruction::REVERT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool SemanticInformation::terminatesControlFlow(Instruction _instruction)
|
||||
bool SemanticInformation::terminatesControlFlow(InternalInstruction _instruction)
|
||||
{
|
||||
switch (_instruction)
|
||||
{
|
||||
case Instruction::RETURN:
|
||||
case Instruction::SELFDESTRUCT:
|
||||
case Instruction::STOP:
|
||||
case Instruction::INVALID:
|
||||
case Instruction::REVERT:
|
||||
case InternalInstruction::RETURN:
|
||||
case InternalInstruction::SELFDESTRUCT:
|
||||
case InternalInstruction::STOP:
|
||||
case InternalInstruction::INVALID:
|
||||
case InternalInstruction::REVERT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool SemanticInformation::reverts(Instruction _instruction)
|
||||
bool SemanticInformation::reverts(InternalInstruction _instruction)
|
||||
{
|
||||
switch (_instruction)
|
||||
{
|
||||
case Instruction::INVALID:
|
||||
case Instruction::REVERT:
|
||||
case InternalInstruction::INVALID:
|
||||
case InternalInstruction::REVERT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@ -292,28 +292,28 @@ bool SemanticInformation::isDeterministic(AssemblyItem const& _item)
|
||||
|
||||
switch (_item.instruction())
|
||||
{
|
||||
case Instruction::CALL:
|
||||
case Instruction::CALLCODE:
|
||||
case Instruction::DELEGATECALL:
|
||||
case Instruction::STATICCALL:
|
||||
case Instruction::CREATE:
|
||||
case Instruction::CREATE2:
|
||||
case Instruction::GAS:
|
||||
case Instruction::PC:
|
||||
case Instruction::MSIZE: // depends on previous writes and reads, not only on content
|
||||
case Instruction::BALANCE: // depends on previous calls
|
||||
case Instruction::SELFBALANCE: // depends on previous calls
|
||||
case Instruction::EXTCODESIZE:
|
||||
case Instruction::EXTCODEHASH:
|
||||
case Instruction::RETURNDATACOPY: // depends on previous calls
|
||||
case Instruction::RETURNDATASIZE:
|
||||
case InternalInstruction::CALL:
|
||||
case InternalInstruction::CALLCODE:
|
||||
case InternalInstruction::DELEGATECALL:
|
||||
case InternalInstruction::STATICCALL:
|
||||
case InternalInstruction::CREATE:
|
||||
case InternalInstruction::CREATE2:
|
||||
case InternalInstruction::GAS:
|
||||
case InternalInstruction::PC:
|
||||
case InternalInstruction::MSIZE: // depends on previous writes and reads, not only on content
|
||||
case InternalInstruction::BALANCE: // depends on previous calls
|
||||
case InternalInstruction::SELFBALANCE: // depends on previous calls
|
||||
case InternalInstruction::EXTCODESIZE:
|
||||
case InternalInstruction::EXTCODEHASH:
|
||||
case InternalInstruction::RETURNDATACOPY: // depends on previous calls
|
||||
case InternalInstruction::RETURNDATASIZE:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool SemanticInformation::movable(Instruction _instruction)
|
||||
bool SemanticInformation::movable(InternalInstruction _instruction)
|
||||
{
|
||||
// These are not really functional.
|
||||
if (isDupInstruction(_instruction) || isSwapInstruction(_instruction))
|
||||
@ -323,16 +323,16 @@ bool SemanticInformation::movable(Instruction _instruction)
|
||||
return false;
|
||||
switch (_instruction)
|
||||
{
|
||||
case Instruction::KECCAK256:
|
||||
case Instruction::BALANCE:
|
||||
case Instruction::SELFBALANCE:
|
||||
case Instruction::EXTCODESIZE:
|
||||
case Instruction::EXTCODEHASH:
|
||||
case Instruction::RETURNDATASIZE:
|
||||
case Instruction::SLOAD:
|
||||
case Instruction::PC:
|
||||
case Instruction::MSIZE:
|
||||
case Instruction::GAS:
|
||||
case InternalInstruction::KECCAK256:
|
||||
case InternalInstruction::BALANCE:
|
||||
case InternalInstruction::SELFBALANCE:
|
||||
case InternalInstruction::EXTCODESIZE:
|
||||
case InternalInstruction::EXTCODEHASH:
|
||||
case InternalInstruction::RETURNDATASIZE:
|
||||
case InternalInstruction::SLOAD:
|
||||
case InternalInstruction::PC:
|
||||
case InternalInstruction::MSIZE:
|
||||
case InternalInstruction::GAS:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
@ -340,7 +340,7 @@ bool SemanticInformation::movable(Instruction _instruction)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SemanticInformation::canBeRemoved(Instruction _instruction)
|
||||
bool SemanticInformation::canBeRemoved(InternalInstruction _instruction)
|
||||
{
|
||||
// These are not really functional.
|
||||
assertThrow(!isDupInstruction(_instruction) && !isSwapInstruction(_instruction), AssemblyException, "");
|
||||
@ -348,42 +348,42 @@ bool SemanticInformation::canBeRemoved(Instruction _instruction)
|
||||
return !instructionInfo(_instruction).sideEffects;
|
||||
}
|
||||
|
||||
bool SemanticInformation::canBeRemovedIfNoMSize(Instruction _instruction)
|
||||
bool SemanticInformation::canBeRemovedIfNoMSize(InternalInstruction _instruction)
|
||||
{
|
||||
if (_instruction == Instruction::KECCAK256 || _instruction == Instruction::MLOAD)
|
||||
if (_instruction == InternalInstruction::KECCAK256 || _instruction == InternalInstruction::MLOAD)
|
||||
return true;
|
||||
else
|
||||
return canBeRemoved(_instruction);
|
||||
}
|
||||
|
||||
SemanticInformation::Effect SemanticInformation::memory(Instruction _instruction)
|
||||
SemanticInformation::Effect SemanticInformation::memory(InternalInstruction _instruction)
|
||||
{
|
||||
switch (_instruction)
|
||||
{
|
||||
case Instruction::CALLDATACOPY:
|
||||
case Instruction::CODECOPY:
|
||||
case Instruction::EXTCODECOPY:
|
||||
case Instruction::RETURNDATACOPY:
|
||||
case Instruction::MSTORE:
|
||||
case Instruction::MSTORE8:
|
||||
case Instruction::CALL:
|
||||
case Instruction::CALLCODE:
|
||||
case Instruction::DELEGATECALL:
|
||||
case Instruction::STATICCALL:
|
||||
case InternalInstruction::CALLDATACOPY:
|
||||
case InternalInstruction::CODECOPY:
|
||||
case InternalInstruction::EXTCODECOPY:
|
||||
case InternalInstruction::RETURNDATACOPY:
|
||||
case InternalInstruction::MSTORE:
|
||||
case InternalInstruction::MSTORE8:
|
||||
case InternalInstruction::CALL:
|
||||
case InternalInstruction::CALLCODE:
|
||||
case InternalInstruction::DELEGATECALL:
|
||||
case InternalInstruction::STATICCALL:
|
||||
return SemanticInformation::Write;
|
||||
|
||||
case Instruction::CREATE:
|
||||
case Instruction::CREATE2:
|
||||
case Instruction::KECCAK256:
|
||||
case Instruction::MLOAD:
|
||||
case Instruction::MSIZE:
|
||||
case Instruction::RETURN:
|
||||
case Instruction::REVERT:
|
||||
case Instruction::LOG0:
|
||||
case Instruction::LOG1:
|
||||
case Instruction::LOG2:
|
||||
case Instruction::LOG3:
|
||||
case Instruction::LOG4:
|
||||
case InternalInstruction::CREATE:
|
||||
case InternalInstruction::CREATE2:
|
||||
case InternalInstruction::KECCAK256:
|
||||
case InternalInstruction::MLOAD:
|
||||
case InternalInstruction::MSIZE:
|
||||
case InternalInstruction::RETURN:
|
||||
case InternalInstruction::REVERT:
|
||||
case InternalInstruction::LOG0:
|
||||
case InternalInstruction::LOG1:
|
||||
case InternalInstruction::LOG2:
|
||||
case InternalInstruction::LOG3:
|
||||
case InternalInstruction::LOG4:
|
||||
return SemanticInformation::Read;
|
||||
|
||||
default:
|
||||
@ -391,18 +391,18 @@ SemanticInformation::Effect SemanticInformation::memory(Instruction _instruction
|
||||
}
|
||||
}
|
||||
|
||||
bool SemanticInformation::movableApartFromEffects(Instruction _instruction)
|
||||
bool SemanticInformation::movableApartFromEffects(InternalInstruction _instruction)
|
||||
{
|
||||
switch (_instruction)
|
||||
{
|
||||
case Instruction::EXTCODEHASH:
|
||||
case Instruction::EXTCODESIZE:
|
||||
case Instruction::RETURNDATASIZE:
|
||||
case Instruction::BALANCE:
|
||||
case Instruction::SELFBALANCE:
|
||||
case Instruction::SLOAD:
|
||||
case Instruction::KECCAK256:
|
||||
case Instruction::MLOAD:
|
||||
case InternalInstruction::EXTCODEHASH:
|
||||
case InternalInstruction::EXTCODESIZE:
|
||||
case InternalInstruction::RETURNDATASIZE:
|
||||
case InternalInstruction::BALANCE:
|
||||
case InternalInstruction::SELFBALANCE:
|
||||
case InternalInstruction::SLOAD:
|
||||
case InternalInstruction::KECCAK256:
|
||||
case InternalInstruction::MLOAD:
|
||||
return true;
|
||||
|
||||
default:
|
||||
@ -410,20 +410,20 @@ bool SemanticInformation::movableApartFromEffects(Instruction _instruction)
|
||||
}
|
||||
}
|
||||
|
||||
SemanticInformation::Effect SemanticInformation::storage(Instruction _instruction)
|
||||
SemanticInformation::Effect SemanticInformation::storage(InternalInstruction _instruction)
|
||||
{
|
||||
switch (_instruction)
|
||||
{
|
||||
case Instruction::CALL:
|
||||
case Instruction::CALLCODE:
|
||||
case Instruction::DELEGATECALL:
|
||||
case Instruction::CREATE:
|
||||
case Instruction::CREATE2:
|
||||
case Instruction::SSTORE:
|
||||
case InternalInstruction::CALL:
|
||||
case InternalInstruction::CALLCODE:
|
||||
case InternalInstruction::DELEGATECALL:
|
||||
case InternalInstruction::CREATE:
|
||||
case InternalInstruction::CREATE2:
|
||||
case InternalInstruction::SSTORE:
|
||||
return SemanticInformation::Write;
|
||||
|
||||
case Instruction::SLOAD:
|
||||
case Instruction::STATICCALL:
|
||||
case InternalInstruction::SLOAD:
|
||||
case InternalInstruction::STATICCALL:
|
||||
return SemanticInformation::Read;
|
||||
|
||||
default:
|
||||
@ -431,28 +431,28 @@ SemanticInformation::Effect SemanticInformation::storage(Instruction _instructio
|
||||
}
|
||||
}
|
||||
|
||||
SemanticInformation::Effect SemanticInformation::otherState(Instruction _instruction)
|
||||
SemanticInformation::Effect SemanticInformation::otherState(InternalInstruction _instruction)
|
||||
{
|
||||
switch (_instruction)
|
||||
{
|
||||
case Instruction::CALL:
|
||||
case Instruction::CALLCODE:
|
||||
case Instruction::DELEGATECALL:
|
||||
case Instruction::CREATE:
|
||||
case Instruction::CREATE2:
|
||||
case Instruction::SELFDESTRUCT:
|
||||
case Instruction::STATICCALL: // because it can affect returndatasize
|
||||
case InternalInstruction::CALL:
|
||||
case InternalInstruction::CALLCODE:
|
||||
case InternalInstruction::DELEGATECALL:
|
||||
case InternalInstruction::CREATE:
|
||||
case InternalInstruction::CREATE2:
|
||||
case InternalInstruction::SELFDESTRUCT:
|
||||
case InternalInstruction::STATICCALL: // because it can affect returndatasize
|
||||
// Strictly speaking, log0, .., log4 writes to the state, but the EVM cannot read it, so they
|
||||
// are just marked as having 'other side effects.'
|
||||
return SemanticInformation::Write;
|
||||
|
||||
case Instruction::EXTCODESIZE:
|
||||
case Instruction::EXTCODEHASH:
|
||||
case Instruction::RETURNDATASIZE:
|
||||
case Instruction::BALANCE:
|
||||
case Instruction::SELFBALANCE:
|
||||
case Instruction::RETURNDATACOPY:
|
||||
case Instruction::EXTCODECOPY:
|
||||
case InternalInstruction::EXTCODESIZE:
|
||||
case InternalInstruction::EXTCODEHASH:
|
||||
case InternalInstruction::RETURNDATASIZE:
|
||||
case InternalInstruction::BALANCE:
|
||||
case InternalInstruction::SELFBALANCE:
|
||||
case InternalInstruction::RETURNDATACOPY:
|
||||
case InternalInstruction::EXTCODECOPY:
|
||||
// PC and GAS are specifically excluded here. Instructions such as CALLER, CALLVALUE,
|
||||
// ADDRESS are excluded because they cannot change during execution.
|
||||
return SemanticInformation::Read;
|
||||
@ -462,31 +462,31 @@ SemanticInformation::Effect SemanticInformation::otherState(Instruction _instruc
|
||||
}
|
||||
}
|
||||
|
||||
bool SemanticInformation::invalidInPureFunctions(Instruction _instruction)
|
||||
bool SemanticInformation::invalidInPureFunctions(InternalInstruction _instruction)
|
||||
{
|
||||
switch (_instruction)
|
||||
{
|
||||
case Instruction::ADDRESS:
|
||||
case Instruction::SELFBALANCE:
|
||||
case Instruction::BALANCE:
|
||||
case Instruction::ORIGIN:
|
||||
case Instruction::CALLER:
|
||||
case Instruction::CALLVALUE:
|
||||
case Instruction::CHAINID:
|
||||
case Instruction::BASEFEE:
|
||||
case Instruction::GAS:
|
||||
case Instruction::GASPRICE:
|
||||
case Instruction::EXTCODESIZE:
|
||||
case Instruction::EXTCODECOPY:
|
||||
case Instruction::EXTCODEHASH:
|
||||
case Instruction::BLOCKHASH:
|
||||
case Instruction::COINBASE:
|
||||
case Instruction::TIMESTAMP:
|
||||
case Instruction::NUMBER:
|
||||
case Instruction::DIFFICULTY:
|
||||
case Instruction::GASLIMIT:
|
||||
case Instruction::STATICCALL:
|
||||
case Instruction::SLOAD:
|
||||
case InternalInstruction::ADDRESS:
|
||||
case InternalInstruction::SELFBALANCE:
|
||||
case InternalInstruction::BALANCE:
|
||||
case InternalInstruction::ORIGIN:
|
||||
case InternalInstruction::CALLER:
|
||||
case InternalInstruction::CALLVALUE:
|
||||
case InternalInstruction::CHAINID:
|
||||
case InternalInstruction::BASEFEE:
|
||||
case InternalInstruction::GAS:
|
||||
case InternalInstruction::GASPRICE:
|
||||
case InternalInstruction::EXTCODESIZE:
|
||||
case InternalInstruction::EXTCODECOPY:
|
||||
case InternalInstruction::EXTCODEHASH:
|
||||
case InternalInstruction::BLOCKHASH:
|
||||
case InternalInstruction::COINBASE:
|
||||
case InternalInstruction::TIMESTAMP:
|
||||
case InternalInstruction::NUMBER:
|
||||
case InternalInstruction::DIFFICULTY:
|
||||
case InternalInstruction::GASLIMIT:
|
||||
case InternalInstruction::STATICCALL:
|
||||
case InternalInstruction::SLOAD:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
@ -494,24 +494,24 @@ bool SemanticInformation::invalidInPureFunctions(Instruction _instruction)
|
||||
return invalidInViewFunctions(_instruction);
|
||||
}
|
||||
|
||||
bool SemanticInformation::invalidInViewFunctions(Instruction _instruction)
|
||||
bool SemanticInformation::invalidInViewFunctions(InternalInstruction _instruction)
|
||||
{
|
||||
switch (_instruction)
|
||||
{
|
||||
case Instruction::SSTORE:
|
||||
case Instruction::JUMP:
|
||||
case Instruction::JUMPI:
|
||||
case Instruction::LOG0:
|
||||
case Instruction::LOG1:
|
||||
case Instruction::LOG2:
|
||||
case Instruction::LOG3:
|
||||
case Instruction::LOG4:
|
||||
case Instruction::CREATE:
|
||||
case Instruction::CALL:
|
||||
case Instruction::CALLCODE:
|
||||
case Instruction::DELEGATECALL:
|
||||
case Instruction::CREATE2:
|
||||
case Instruction::SELFDESTRUCT:
|
||||
case InternalInstruction::SSTORE:
|
||||
case InternalInstruction::JUMP:
|
||||
case InternalInstruction::JUMPI:
|
||||
case InternalInstruction::LOG0:
|
||||
case InternalInstruction::LOG1:
|
||||
case InternalInstruction::LOG2:
|
||||
case InternalInstruction::LOG3:
|
||||
case InternalInstruction::LOG4:
|
||||
case InternalInstruction::CREATE:
|
||||
case InternalInstruction::CALL:
|
||||
case InternalInstruction::CALLCODE:
|
||||
case InternalInstruction::DELEGATECALL:
|
||||
case InternalInstruction::CREATE2:
|
||||
case InternalInstruction::SELFDESTRUCT:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
|
@ -72,7 +72,7 @@ struct SemanticInformation
|
||||
/// Order matters.
|
||||
/// For external calls, there is just one unknown read and one unknown write operation,
|
||||
/// event though there might be multiple.
|
||||
static std::vector<Operation> readWriteOperations(Instruction _instruction);
|
||||
static std::vector<Operation> readWriteOperations(InternalInstruction _instruction);
|
||||
|
||||
/// @returns true if the given items starts a new block for common subexpression analysis.
|
||||
/// @param _msizeImportant if false, consider an operation non-breaking if its only side-effect is that it modifies msize.
|
||||
@ -84,34 +84,34 @@ struct SemanticInformation
|
||||
static bool isSwapInstruction(AssemblyItem const& _item);
|
||||
static bool isJumpInstruction(AssemblyItem const& _item);
|
||||
static bool altersControlFlow(AssemblyItem const& _item);
|
||||
static bool terminatesControlFlow(Instruction _instruction);
|
||||
static bool reverts(Instruction _instruction);
|
||||
static bool terminatesControlFlow(InternalInstruction _instruction);
|
||||
static bool reverts(InternalInstruction _instruction);
|
||||
/// @returns false if the value put on the stack by _item depends on anything else than
|
||||
/// the information in the current block header, memory, storage or stack.
|
||||
static bool isDeterministic(AssemblyItem const& _item);
|
||||
/// @returns true if the instruction can be moved or copied (together with its arguments)
|
||||
/// without altering the semantics. This means it cannot depend on storage or memory,
|
||||
/// cannot have any side-effects, but it can depend on a call-constant state of the blockchain.
|
||||
static bool movable(Instruction _instruction);
|
||||
static bool movable(InternalInstruction _instruction);
|
||||
/// If true, the expressions in this code can be moved or copied (together with their arguments)
|
||||
/// across control flow branches and instructions as long as these instructions' 'effects' do
|
||||
/// not influence the 'effects' of the aforementioned expressions.
|
||||
static bool movableApartFromEffects(Instruction _instruction);
|
||||
static bool movableApartFromEffects(InternalInstruction _instruction);
|
||||
/// @returns true if the instruction can be removed without changing the semantics.
|
||||
/// This does not mean that it has to be deterministic or retrieve information from
|
||||
/// somewhere else than purely the values of its arguments.
|
||||
static bool canBeRemoved(Instruction _instruction);
|
||||
static bool canBeRemoved(InternalInstruction _instruction);
|
||||
/// @returns true if the instruction can be removed without changing the semantics.
|
||||
/// This does not mean that it has to be deterministic or retrieve information from
|
||||
/// somewhere else than purely the values of its arguments.
|
||||
/// If true, the instruction is still allowed to influence the value returned by the
|
||||
/// msize instruction.
|
||||
static bool canBeRemovedIfNoMSize(Instruction _instruction);
|
||||
static Effect memory(Instruction _instruction);
|
||||
static Effect storage(Instruction _instruction);
|
||||
static Effect otherState(Instruction _instruction);
|
||||
static bool invalidInPureFunctions(Instruction _instruction);
|
||||
static bool invalidInViewFunctions(Instruction _instruction);
|
||||
static bool canBeRemovedIfNoMSize(InternalInstruction _instruction);
|
||||
static Effect memory(InternalInstruction _instruction);
|
||||
static Effect storage(InternalInstruction _instruction);
|
||||
static Effect otherState(InternalInstruction _instruction);
|
||||
static bool invalidInPureFunctions(InternalInstruction _instruction);
|
||||
static bool invalidInViewFunctions(InternalInstruction _instruction);
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -54,9 +54,9 @@ struct SimplificationRule
|
||||
template <typename Pattern>
|
||||
struct EVMBuiltins
|
||||
{
|
||||
using InstrType = Instruction;
|
||||
using InstrType = InternalInstruction;
|
||||
|
||||
template<Instruction inst>
|
||||
template<InternalInstruction inst>
|
||||
struct PatternGenerator
|
||||
{
|
||||
template<typename... Args> constexpr Pattern operator()(Args&&... _args) const
|
||||
@ -67,7 +67,7 @@ struct EVMBuiltins
|
||||
|
||||
struct PatternGeneratorInstance
|
||||
{
|
||||
Instruction instruction;
|
||||
InternalInstruction instruction;
|
||||
template<typename... Args> constexpr Pattern operator()(Args&&... _args) const
|
||||
{
|
||||
return {instruction, {std::forward<Args>(_args)...}};
|
||||
@ -75,83 +75,83 @@ struct EVMBuiltins
|
||||
};
|
||||
|
||||
|
||||
static auto constexpr STOP = PatternGenerator<Instruction::STOP>{};
|
||||
static auto constexpr ADD = PatternGenerator<Instruction::ADD>{};
|
||||
static auto constexpr SUB = PatternGenerator<Instruction::SUB>{};
|
||||
static auto constexpr MUL = PatternGenerator<Instruction::MUL>{};
|
||||
static auto constexpr DIV = PatternGenerator<Instruction::DIV>{};
|
||||
static auto constexpr SDIV = PatternGenerator<Instruction::SDIV>{};
|
||||
static auto constexpr MOD = PatternGenerator<Instruction::MOD>{};
|
||||
static auto constexpr SMOD = PatternGenerator<Instruction::SMOD>{};
|
||||
static auto constexpr EXP = PatternGenerator<Instruction::EXP>{};
|
||||
static auto constexpr NOT = PatternGenerator<Instruction::NOT>{};
|
||||
static auto constexpr LT = PatternGenerator<Instruction::LT>{};
|
||||
static auto constexpr GT = PatternGenerator<Instruction::GT>{};
|
||||
static auto constexpr SLT = PatternGenerator<Instruction::SLT>{};
|
||||
static auto constexpr SGT = PatternGenerator<Instruction::SGT>{};
|
||||
static auto constexpr EQ = PatternGenerator<Instruction::EQ>{};
|
||||
static auto constexpr ISZERO = PatternGenerator<Instruction::ISZERO>{};
|
||||
static auto constexpr AND = PatternGenerator<Instruction::AND>{};
|
||||
static auto constexpr OR = PatternGenerator<Instruction::OR>{};
|
||||
static auto constexpr XOR = PatternGenerator<Instruction::XOR>{};
|
||||
static auto constexpr BYTE = PatternGenerator<Instruction::BYTE>{};
|
||||
static auto constexpr SHL = PatternGenerator<Instruction::SHL>{};
|
||||
static auto constexpr SHR = PatternGenerator<Instruction::SHR>{};
|
||||
static auto constexpr SAR = PatternGenerator<Instruction::SAR>{};
|
||||
static auto constexpr ADDMOD = PatternGenerator<Instruction::ADDMOD>{};
|
||||
static auto constexpr MULMOD = PatternGenerator<Instruction::MULMOD>{};
|
||||
static auto constexpr SIGNEXTEND = PatternGenerator<Instruction::SIGNEXTEND>{};
|
||||
static auto constexpr KECCAK256 = PatternGenerator<Instruction::KECCAK256>{};
|
||||
static auto constexpr ADDRESS = PatternGenerator<Instruction::ADDRESS>{};
|
||||
static auto constexpr BALANCE = PatternGenerator<Instruction::BALANCE>{};
|
||||
static auto constexpr ORIGIN = PatternGenerator<Instruction::ORIGIN>{};
|
||||
static auto constexpr CALLER = PatternGenerator<Instruction::CALLER>{};
|
||||
static auto constexpr CALLVALUE = PatternGenerator<Instruction::CALLVALUE>{};
|
||||
static auto constexpr CALLDATALOAD = PatternGenerator<Instruction::CALLDATALOAD>{};
|
||||
static auto constexpr CALLDATASIZE = PatternGenerator<Instruction::CALLDATASIZE>{};
|
||||
static auto constexpr CALLDATACOPY = PatternGenerator<Instruction::CALLDATACOPY>{};
|
||||
static auto constexpr CODESIZE = PatternGenerator<Instruction::CODESIZE>{};
|
||||
static auto constexpr CODECOPY = PatternGenerator<Instruction::CODECOPY>{};
|
||||
static auto constexpr GASPRICE = PatternGenerator<Instruction::GASPRICE>{};
|
||||
static auto constexpr EXTCODESIZE = PatternGenerator<Instruction::EXTCODESIZE>{};
|
||||
static auto constexpr EXTCODECOPY = PatternGenerator<Instruction::EXTCODECOPY>{};
|
||||
static auto constexpr RETURNDATASIZE = PatternGenerator<Instruction::RETURNDATASIZE>{};
|
||||
static auto constexpr RETURNDATACOPY = PatternGenerator<Instruction::RETURNDATACOPY>{};
|
||||
static auto constexpr EXTCODEHASH = PatternGenerator<Instruction::EXTCODEHASH>{};
|
||||
static auto constexpr BLOCKHASH = PatternGenerator<Instruction::BLOCKHASH>{};
|
||||
static auto constexpr COINBASE = PatternGenerator<Instruction::COINBASE>{};
|
||||
static auto constexpr TIMESTAMP = PatternGenerator<Instruction::TIMESTAMP>{};
|
||||
static auto constexpr NUMBER = PatternGenerator<Instruction::NUMBER>{};
|
||||
static auto constexpr DIFFICULTY = PatternGenerator<Instruction::DIFFICULTY>{};
|
||||
static auto constexpr PREVRANDAO = PatternGenerator<Instruction::PREVRANDAO>{};
|
||||
static auto constexpr GASLIMIT = PatternGenerator<Instruction::GASLIMIT>{};
|
||||
static auto constexpr CHAINID = PatternGenerator<Instruction::CHAINID>{};
|
||||
static auto constexpr SELFBALANCE = PatternGenerator<Instruction::SELFBALANCE>{};
|
||||
static auto constexpr BASEFEE = PatternGenerator<Instruction::BASEFEE>{};
|
||||
static auto constexpr POP = PatternGenerator<Instruction::POP>{};
|
||||
static auto constexpr MLOAD = PatternGenerator<Instruction::MLOAD>{};
|
||||
static auto constexpr MSTORE = PatternGenerator<Instruction::MSTORE>{};
|
||||
static auto constexpr MSTORE8 = PatternGenerator<Instruction::MSTORE8>{};
|
||||
static auto constexpr SLOAD = PatternGenerator<Instruction::SLOAD>{};
|
||||
static auto constexpr SSTORE = PatternGenerator<Instruction::SSTORE>{};
|
||||
static auto constexpr PC = PatternGenerator<Instruction::PC>{};
|
||||
static auto constexpr MSIZE = PatternGenerator<Instruction::MSIZE>{};
|
||||
static auto constexpr GAS = PatternGenerator<Instruction::GAS>{};
|
||||
static auto constexpr LOG0 = PatternGenerator<Instruction::LOG0>{};
|
||||
static auto constexpr LOG1 = PatternGenerator<Instruction::LOG1>{};
|
||||
static auto constexpr LOG2 = PatternGenerator<Instruction::LOG2>{};
|
||||
static auto constexpr LOG3 = PatternGenerator<Instruction::LOG3>{};
|
||||
static auto constexpr LOG4 = PatternGenerator<Instruction::LOG4>{};
|
||||
static auto constexpr CREATE = PatternGenerator<Instruction::CREATE>{};
|
||||
static auto constexpr CALL = PatternGenerator<Instruction::CALL>{};
|
||||
static auto constexpr CALLCODE = PatternGenerator<Instruction::CALLCODE>{};
|
||||
static auto constexpr STATICCALL = PatternGenerator<Instruction::STATICCALL>{};
|
||||
static auto constexpr RETURN = PatternGenerator<Instruction::RETURN>{};
|
||||
static auto constexpr DELEGATECALL = PatternGenerator<Instruction::DELEGATECALL>{};
|
||||
static auto constexpr CREATE2 = PatternGenerator<Instruction::CREATE2>{};
|
||||
static auto constexpr REVERT = PatternGenerator<Instruction::REVERT>{};
|
||||
static auto constexpr INVALID = PatternGenerator<Instruction::INVALID>{};
|
||||
static auto constexpr SELFDESTRUCT = PatternGenerator<Instruction::SELFDESTRUCT>{};
|
||||
static auto constexpr STOP = PatternGenerator<InternalInstruction::STOP>{};
|
||||
static auto constexpr ADD = PatternGenerator<InternalInstruction::ADD>{};
|
||||
static auto constexpr SUB = PatternGenerator<InternalInstruction::SUB>{};
|
||||
static auto constexpr MUL = PatternGenerator<InternalInstruction::MUL>{};
|
||||
static auto constexpr DIV = PatternGenerator<InternalInstruction::DIV>{};
|
||||
static auto constexpr SDIV = PatternGenerator<InternalInstruction::SDIV>{};
|
||||
static auto constexpr MOD = PatternGenerator<InternalInstruction::MOD>{};
|
||||
static auto constexpr SMOD = PatternGenerator<InternalInstruction::SMOD>{};
|
||||
static auto constexpr EXP = PatternGenerator<InternalInstruction::EXP>{};
|
||||
static auto constexpr NOT = PatternGenerator<InternalInstruction::NOT>{};
|
||||
static auto constexpr LT = PatternGenerator<InternalInstruction::LT>{};
|
||||
static auto constexpr GT = PatternGenerator<InternalInstruction::GT>{};
|
||||
static auto constexpr SLT = PatternGenerator<InternalInstruction::SLT>{};
|
||||
static auto constexpr SGT = PatternGenerator<InternalInstruction::SGT>{};
|
||||
static auto constexpr EQ = PatternGenerator<InternalInstruction::EQ>{};
|
||||
static auto constexpr ISZERO = PatternGenerator<InternalInstruction::ISZERO>{};
|
||||
static auto constexpr AND = PatternGenerator<InternalInstruction::AND>{};
|
||||
static auto constexpr OR = PatternGenerator<InternalInstruction::OR>{};
|
||||
static auto constexpr XOR = PatternGenerator<InternalInstruction::XOR>{};
|
||||
static auto constexpr BYTE = PatternGenerator<InternalInstruction::BYTE>{};
|
||||
static auto constexpr SHL = PatternGenerator<InternalInstruction::SHL>{};
|
||||
static auto constexpr SHR = PatternGenerator<InternalInstruction::SHR>{};
|
||||
static auto constexpr SAR = PatternGenerator<InternalInstruction::SAR>{};
|
||||
static auto constexpr ADDMOD = PatternGenerator<InternalInstruction::ADDMOD>{};
|
||||
static auto constexpr MULMOD = PatternGenerator<InternalInstruction::MULMOD>{};
|
||||
static auto constexpr SIGNEXTEND = PatternGenerator<InternalInstruction::SIGNEXTEND>{};
|
||||
static auto constexpr KECCAK256 = PatternGenerator<InternalInstruction::KECCAK256>{};
|
||||
static auto constexpr ADDRESS = PatternGenerator<InternalInstruction::ADDRESS>{};
|
||||
static auto constexpr BALANCE = PatternGenerator<InternalInstruction::BALANCE>{};
|
||||
static auto constexpr ORIGIN = PatternGenerator<InternalInstruction::ORIGIN>{};
|
||||
static auto constexpr CALLER = PatternGenerator<InternalInstruction::CALLER>{};
|
||||
static auto constexpr CALLVALUE = PatternGenerator<InternalInstruction::CALLVALUE>{};
|
||||
static auto constexpr CALLDATALOAD = PatternGenerator<InternalInstruction::CALLDATALOAD>{};
|
||||
static auto constexpr CALLDATASIZE = PatternGenerator<InternalInstruction::CALLDATASIZE>{};
|
||||
static auto constexpr CALLDATACOPY = PatternGenerator<InternalInstruction::CALLDATACOPY>{};
|
||||
static auto constexpr CODESIZE = PatternGenerator<InternalInstruction::CODESIZE>{};
|
||||
static auto constexpr CODECOPY = PatternGenerator<InternalInstruction::CODECOPY>{};
|
||||
static auto constexpr GASPRICE = PatternGenerator<InternalInstruction::GASPRICE>{};
|
||||
static auto constexpr EXTCODESIZE = PatternGenerator<InternalInstruction::EXTCODESIZE>{};
|
||||
static auto constexpr EXTCODECOPY = PatternGenerator<InternalInstruction::EXTCODECOPY>{};
|
||||
static auto constexpr RETURNDATASIZE = PatternGenerator<InternalInstruction::RETURNDATASIZE>{};
|
||||
static auto constexpr RETURNDATACOPY = PatternGenerator<InternalInstruction::RETURNDATACOPY>{};
|
||||
static auto constexpr EXTCODEHASH = PatternGenerator<InternalInstruction::EXTCODEHASH>{};
|
||||
static auto constexpr BLOCKHASH = PatternGenerator<InternalInstruction::BLOCKHASH>{};
|
||||
static auto constexpr COINBASE = PatternGenerator<InternalInstruction::COINBASE>{};
|
||||
static auto constexpr TIMESTAMP = PatternGenerator<InternalInstruction::TIMESTAMP>{};
|
||||
static auto constexpr NUMBER = PatternGenerator<InternalInstruction::NUMBER>{};
|
||||
static auto constexpr DIFFICULTY = PatternGenerator<InternalInstruction::DIFFICULTY>{};
|
||||
static auto constexpr PREVRANDAO = PatternGenerator<InternalInstruction::PREVRANDAO>{};
|
||||
static auto constexpr GASLIMIT = PatternGenerator<InternalInstruction::GASLIMIT>{};
|
||||
static auto constexpr CHAINID = PatternGenerator<InternalInstruction::CHAINID>{};
|
||||
static auto constexpr SELFBALANCE = PatternGenerator<InternalInstruction::SELFBALANCE>{};
|
||||
static auto constexpr BASEFEE = PatternGenerator<InternalInstruction::BASEFEE>{};
|
||||
static auto constexpr POP = PatternGenerator<InternalInstruction::POP>{};
|
||||
static auto constexpr MLOAD = PatternGenerator<InternalInstruction::MLOAD>{};
|
||||
static auto constexpr MSTORE = PatternGenerator<InternalInstruction::MSTORE>{};
|
||||
static auto constexpr MSTORE8 = PatternGenerator<InternalInstruction::MSTORE8>{};
|
||||
static auto constexpr SLOAD = PatternGenerator<InternalInstruction::SLOAD>{};
|
||||
static auto constexpr SSTORE = PatternGenerator<InternalInstruction::SSTORE>{};
|
||||
static auto constexpr PC = PatternGenerator<InternalInstruction::PC>{};
|
||||
static auto constexpr MSIZE = PatternGenerator<InternalInstruction::MSIZE>{};
|
||||
static auto constexpr GAS = PatternGenerator<InternalInstruction::GAS>{};
|
||||
static auto constexpr LOG0 = PatternGenerator<InternalInstruction::LOG0>{};
|
||||
static auto constexpr LOG1 = PatternGenerator<InternalInstruction::LOG1>{};
|
||||
static auto constexpr LOG2 = PatternGenerator<InternalInstruction::LOG2>{};
|
||||
static auto constexpr LOG3 = PatternGenerator<InternalInstruction::LOG3>{};
|
||||
static auto constexpr LOG4 = PatternGenerator<InternalInstruction::LOG4>{};
|
||||
static auto constexpr CREATE = PatternGenerator<InternalInstruction::CREATE>{};
|
||||
static auto constexpr CALL = PatternGenerator<InternalInstruction::CALL>{};
|
||||
static auto constexpr CALLCODE = PatternGenerator<InternalInstruction::CALLCODE>{};
|
||||
static auto constexpr STATICCALL = PatternGenerator<InternalInstruction::STATICCALL>{};
|
||||
static auto constexpr RETURN = PatternGenerator<InternalInstruction::RETURN>{};
|
||||
static auto constexpr DELEGATECALL = PatternGenerator<InternalInstruction::DELEGATECALL>{};
|
||||
static auto constexpr CREATE2 = PatternGenerator<InternalInstruction::CREATE2>{};
|
||||
static auto constexpr REVERT = PatternGenerator<InternalInstruction::REVERT>{};
|
||||
static auto constexpr INVALID = PatternGenerator<InternalInstruction::INVALID>{};
|
||||
static auto constexpr SELFDESTRUCT = PatternGenerator<InternalInstruction::SELFDESTRUCT>{};
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ SimplificationRule<Pattern> const* Rules::findFirstMatch(
|
||||
|
||||
bool Rules::isInitialized() const
|
||||
{
|
||||
return !m_rules[uint8_t(Instruction::ADD)].empty();
|
||||
return !m_rules[uint8_t(InternalInstruction::ADD)].empty();
|
||||
}
|
||||
|
||||
void Rules::addRules(std::vector<SimplificationRule<Pattern>> const& _rules)
|
||||
@ -96,7 +96,7 @@ Rules::Rules()
|
||||
assertThrow(isInitialized(), OptimizerException, "Rule list not properly initialized.");
|
||||
}
|
||||
|
||||
Pattern::Pattern(Instruction _instruction, std::initializer_list<Pattern> _arguments):
|
||||
Pattern::Pattern(InternalInstruction _instruction, std::initializer_list<Pattern> _arguments):
|
||||
m_type(Operation),
|
||||
m_instruction(_instruction),
|
||||
m_arguments(_arguments)
|
||||
|
@ -103,7 +103,7 @@ public:
|
||||
// Matches a specific assembly item type or anything if not given.
|
||||
Pattern(AssemblyItemType _type = UndefinedItem): m_type(_type) {}
|
||||
// Matches a given instruction with given arguments
|
||||
Pattern(Instruction _instruction, std::initializer_list<Pattern> _arguments = {});
|
||||
Pattern(InternalInstruction _instruction, std::initializer_list<Pattern> _arguments = {});
|
||||
/// Sets this pattern to be part of the match group with the identifier @a _group.
|
||||
/// Inside one rule, all patterns in the same match group have to match expressions from the
|
||||
/// same expression equivalence class.
|
||||
@ -122,7 +122,7 @@ public:
|
||||
std::string toString() const;
|
||||
|
||||
AssemblyItemType type() const { return m_type; }
|
||||
Instruction instruction() const
|
||||
InternalInstruction instruction() const
|
||||
{
|
||||
assertThrow(type() == Operation, OptimizerException, "");
|
||||
return m_instruction;
|
||||
@ -135,7 +135,7 @@ private:
|
||||
|
||||
AssemblyItemType m_type;
|
||||
bool m_requireDataMatch = false;
|
||||
Instruction m_instruction; ///< Only valid if m_type is Operation
|
||||
InternalInstruction m_instruction; ///< Only valid if m_type is Operation
|
||||
std::shared_ptr<u256> m_data; ///< Only valid if m_type is not Operation
|
||||
std::vector<Pattern> m_arguments;
|
||||
unsigned m_matchGroup = 0;
|
||||
|
@ -25,28 +25,28 @@ using namespace solidity;
|
||||
using namespace solidity::evmasm;
|
||||
using namespace solidity::langutil;
|
||||
|
||||
bool EVMVersion::hasOpcode(Instruction _opcode) const
|
||||
bool EVMVersion::hasInstruction(InternalInstruction _instruction) const
|
||||
{
|
||||
switch (_opcode)
|
||||
switch (_instruction)
|
||||
{
|
||||
case Instruction::RETURNDATACOPY:
|
||||
case Instruction::RETURNDATASIZE:
|
||||
case InternalInstruction::RETURNDATACOPY:
|
||||
case InternalInstruction::RETURNDATASIZE:
|
||||
return supportsReturndata();
|
||||
case Instruction::STATICCALL:
|
||||
case InternalInstruction::STATICCALL:
|
||||
return hasStaticCall();
|
||||
case Instruction::SHL:
|
||||
case Instruction::SHR:
|
||||
case Instruction::SAR:
|
||||
case InternalInstruction::SHL:
|
||||
case InternalInstruction::SHR:
|
||||
case InternalInstruction::SAR:
|
||||
return hasBitwiseShifting();
|
||||
case Instruction::CREATE2:
|
||||
case InternalInstruction::CREATE2:
|
||||
return hasCreate2();
|
||||
case Instruction::EXTCODEHASH:
|
||||
case InternalInstruction::EXTCODEHASH:
|
||||
return hasExtCodeHash();
|
||||
case Instruction::CHAINID:
|
||||
case InternalInstruction::CHAINID:
|
||||
return hasChainID();
|
||||
case Instruction::SELFBALANCE:
|
||||
case InternalInstruction::SELFBALANCE:
|
||||
return hasSelfBalance();
|
||||
case Instruction::BASEFEE:
|
||||
case InternalInstruction::BASEFEE:
|
||||
return hasBaseFee();
|
||||
case InternalInstruction::DIFFICULTY:
|
||||
return hasDifficulty();
|
||||
|
@ -112,7 +112,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
void checkInstruction(SourceLocation _location, evmasm::Instruction _instruction)
|
||||
void checkInstruction(SourceLocation _location, evmasm::InternalInstruction _instruction)
|
||||
{
|
||||
if (evmasm::SemanticInformation::invalidInViewFunctions(_instruction))
|
||||
m_reportMutability(StateMutability::NonPayable, _location);
|
||||
|
@ -74,9 +74,9 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
|
||||
if (fromCalldata && _sourceType.isDynamicallySized())
|
||||
{
|
||||
// stack: target_ref source_ref source_length
|
||||
m_context << Instruction::SWAP1;
|
||||
m_context << InternalInstruction::SWAP1;
|
||||
// stack: target_ref source_length source_ref
|
||||
m_context << Instruction::DUP3;
|
||||
m_context << InternalInstruction::DUP3;
|
||||
// stack: target_ref source_length source_ref target_ref
|
||||
m_context.callYulFunction(
|
||||
m_context.utilFunctions().copyByteArrayToStorageFunction(_sourceType, _targetType),
|
||||
@ -87,7 +87,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
|
||||
else
|
||||
{
|
||||
// stack: target_ref source_ref
|
||||
m_context << Instruction::DUP2;
|
||||
m_context << InternalInstruction::DUP2;
|
||||
// stack: target_ref source_ref target_ref
|
||||
m_context.callYulFunction(
|
||||
m_context.utilFunctions().copyByteArrayToStorageFunction(_sourceType, _targetType),
|
||||
@ -105,8 +105,8 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
|
||||
if (_sourceType.location() == DataLocation::Memory && _sourceType.isDynamicallySized())
|
||||
{
|
||||
// increment source pointer to point to data
|
||||
m_context << Instruction::SWAP1 << u256(0x20);
|
||||
m_context << Instruction::ADD << Instruction::SWAP1;
|
||||
m_context << InternalInstruction::SWAP1 << u256(0x20);
|
||||
m_context << InternalInstruction::ADD << InternalInstruction::SWAP1;
|
||||
}
|
||||
|
||||
// stack: target_ref source_ref source_length
|
||||
@ -122,7 +122,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
|
||||
ArrayType const& _sourceType = dynamic_cast<ArrayType const&>(*sourceType);
|
||||
ArrayType const& _targetType = dynamic_cast<ArrayType const&>(*targetType);
|
||||
// stack: target_ref source_ref source_length
|
||||
_context << Instruction::DUP3;
|
||||
_context << InternalInstruction::DUP3;
|
||||
// stack: target_ref source_ref source_length target_ref
|
||||
utils.retrieveLength(_targetType);
|
||||
// stack: target_ref source_ref source_length target_ref target_length
|
||||
@ -130,7 +130,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
|
||||
{
|
||||
// store new target length
|
||||
solAssert(!_targetType.isByteArrayOrString());
|
||||
_context << Instruction::DUP3 << Instruction::DUP3 << Instruction::SSTORE;
|
||||
_context << InternalInstruction::DUP3 << InternalInstruction::DUP3 << InternalInstruction::SSTORE;
|
||||
}
|
||||
if (sourceBaseType->category() == Type::Category::Mapping)
|
||||
{
|
||||
@ -138,35 +138,35 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
|
||||
solAssert(_sourceType.location() == DataLocation::Storage, "");
|
||||
// nothing to copy
|
||||
_context
|
||||
<< Instruction::POP << Instruction::POP
|
||||
<< Instruction::POP << Instruction::POP;
|
||||
<< InternalInstruction::POP << InternalInstruction::POP
|
||||
<< InternalInstruction::POP << InternalInstruction::POP;
|
||||
return;
|
||||
}
|
||||
// stack: target_ref source_ref source_length target_ref target_length
|
||||
// compute hashes (data positions)
|
||||
_context << Instruction::SWAP1;
|
||||
_context << InternalInstruction::SWAP1;
|
||||
if (_targetType.isDynamicallySized())
|
||||
CompilerUtils(_context).computeHashStatic();
|
||||
// stack: target_ref source_ref source_length target_length target_data_pos
|
||||
_context << Instruction::SWAP1;
|
||||
_context << InternalInstruction::SWAP1;
|
||||
utils.convertLengthToSize(_targetType);
|
||||
_context << Instruction::DUP2 << Instruction::ADD;
|
||||
_context << InternalInstruction::DUP2 << InternalInstruction::ADD;
|
||||
// stack: target_ref source_ref source_length target_data_pos target_data_end
|
||||
_context << Instruction::SWAP3;
|
||||
_context << InternalInstruction::SWAP3;
|
||||
// stack: target_ref target_data_end source_length target_data_pos source_ref
|
||||
|
||||
evmasm::AssemblyItem copyLoopEndWithoutByteOffset = _context.newTag();
|
||||
solAssert(!_targetType.isByteArrayOrString());
|
||||
// skip copying if source length is zero
|
||||
_context << Instruction::DUP3 << Instruction::ISZERO;
|
||||
_context << InternalInstruction::DUP3 << InternalInstruction::ISZERO;
|
||||
_context.appendConditionalJumpTo(copyLoopEndWithoutByteOffset);
|
||||
|
||||
if (_sourceType.location() == DataLocation::Storage && _sourceType.isDynamicallySized())
|
||||
CompilerUtils(_context).computeHashStatic();
|
||||
// stack: target_ref target_data_end source_length target_data_pos source_data_pos
|
||||
_context << Instruction::SWAP2;
|
||||
_context << InternalInstruction::SWAP2;
|
||||
utils.convertLengthToSize(_sourceType);
|
||||
_context << Instruction::DUP3 << Instruction::ADD;
|
||||
_context << InternalInstruction::DUP3 << InternalInstruction::ADD;
|
||||
// stack: target_ref target_data_end source_data_pos target_data_pos source_data_end
|
||||
if (haveByteOffsetTarget)
|
||||
_context << u256(0);
|
||||
@ -178,7 +178,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
|
||||
// check for loop condition
|
||||
_context
|
||||
<< dupInstruction(3 + byteOffsetSize) << dupInstruction(2 + byteOffsetSize)
|
||||
<< Instruction::GT << Instruction::ISZERO;
|
||||
<< InternalInstruction::GT << InternalInstruction::ISZERO;
|
||||
evmasm::AssemblyItem copyLoopEnd = _context.appendConditionalJump();
|
||||
// stack: target_ref target_data_end source_data_pos target_data_pos source_data_end [target_byte_offset] [source_byte_offset]
|
||||
// copy
|
||||
@ -193,19 +193,19 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
|
||||
!sourceBaseArrayType.isDynamicallySized(),
|
||||
"Copying nested calldata dynamic arrays to storage is not implemented in the old code generator."
|
||||
);
|
||||
_context << Instruction::DUP3;
|
||||
_context << InternalInstruction::DUP3;
|
||||
if (sourceBaseArrayType.location() == DataLocation::Memory)
|
||||
_context << Instruction::MLOAD;
|
||||
_context << Instruction::DUP3;
|
||||
_context << InternalInstruction::MLOAD;
|
||||
_context << InternalInstruction::DUP3;
|
||||
utils.copyArrayToStorage(dynamic_cast<ArrayType const&>(*targetBaseType), sourceBaseArrayType);
|
||||
_context << Instruction::POP;
|
||||
_context << InternalInstruction::POP;
|
||||
}
|
||||
else if (directCopy)
|
||||
{
|
||||
solAssert(byteOffsetSize == 0, "Byte offset for direct copy.");
|
||||
_context
|
||||
<< Instruction::DUP3 << Instruction::SLOAD
|
||||
<< Instruction::DUP3 << Instruction::SSTORE;
|
||||
<< InternalInstruction::DUP3 << InternalInstruction::SLOAD
|
||||
<< InternalInstruction::DUP3 << InternalInstruction::SSTORE;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -217,7 +217,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
|
||||
if (_sourceType.location() == DataLocation::Storage)
|
||||
{
|
||||
if (haveByteOffsetSource)
|
||||
_context << Instruction::DUP2;
|
||||
_context << InternalInstruction::DUP2;
|
||||
else
|
||||
_context << u256(0);
|
||||
StorageItem(_context, *sourceBaseType).retrieveValue(SourceLocation(), true);
|
||||
@ -254,7 +254,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
|
||||
else
|
||||
_context << sourceBaseType->calldataHeadSize();
|
||||
_context
|
||||
<< Instruction::ADD
|
||||
<< InternalInstruction::ADD
|
||||
<< swapInstruction(2 + byteOffsetSize);
|
||||
}
|
||||
// increment target
|
||||
@ -264,7 +264,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
|
||||
_context
|
||||
<< swapInstruction(1 + byteOffsetSize)
|
||||
<< targetBaseType->storageSize()
|
||||
<< Instruction::ADD
|
||||
<< InternalInstruction::ADD
|
||||
<< swapInstruction(1 + byteOffsetSize);
|
||||
_context.appendJumpTo(copyLoopStart);
|
||||
_context << copyLoopEnd;
|
||||
@ -272,7 +272,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
|
||||
{
|
||||
// clear elements that might be left over in the current slot in target
|
||||
// stack: target_ref target_data_end source_data_pos target_data_pos source_data_end target_byte_offset [source_byte_offset]
|
||||
_context << dupInstruction(byteOffsetSize) << Instruction::ISZERO;
|
||||
_context << dupInstruction(byteOffsetSize) << InternalInstruction::ISZERO;
|
||||
evmasm::AssemblyItem copyCleanupLoopEnd = _context.appendConditionalJump();
|
||||
_context << dupInstruction(2 + byteOffsetSize) << dupInstruction(1 + byteOffsetSize);
|
||||
StorageItem(_context, *targetBaseType).setToZero(SourceLocation(), true);
|
||||
@ -280,21 +280,21 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
|
||||
_context.appendJumpTo(copyLoopEnd);
|
||||
|
||||
_context << copyCleanupLoopEnd;
|
||||
_context << Instruction::POP; // might pop the source, but then target is popped next
|
||||
_context << InternalInstruction::POP; // might pop the source, but then target is popped next
|
||||
}
|
||||
if (haveByteOffsetSource)
|
||||
_context << Instruction::POP;
|
||||
_context << InternalInstruction::POP;
|
||||
_context << copyLoopEndWithoutByteOffset;
|
||||
|
||||
// zero-out leftovers in target
|
||||
// stack: target_ref target_data_end source_data_pos target_data_pos_updated source_data_end
|
||||
_context << Instruction::POP << Instruction::SWAP1 << Instruction::POP;
|
||||
_context << InternalInstruction::POP << InternalInstruction::SWAP1 << InternalInstruction::POP;
|
||||
// stack: target_ref target_data_end target_data_pos_updated
|
||||
if (targetBaseType->storageBytes() < 32)
|
||||
utils.clearStorageLoop(TypeProvider::uint256());
|
||||
else
|
||||
utils.clearStorageLoop(targetBaseType);
|
||||
_context << Instruction::POP;
|
||||
_context << InternalInstruction::POP;
|
||||
}
|
||||
);
|
||||
}
|
||||
@ -323,7 +323,7 @@ void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWord
|
||||
)";
|
||||
routine += "target := add(target, len)\n";
|
||||
m_context.appendInlineAssembly("{" + routine + "}", {"target", "source", "len"});
|
||||
m_context << Instruction::POP << Instruction::POP;
|
||||
m_context << InternalInstruction::POP << InternalInstruction::POP;
|
||||
}
|
||||
else if (_sourceType.location() == DataLocation::Memory)
|
||||
{
|
||||
@ -332,25 +332,25 @@ void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWord
|
||||
if (!_sourceType.baseType()->isValueType())
|
||||
{
|
||||
// copy using a loop
|
||||
m_context << u256(0) << Instruction::SWAP3;
|
||||
m_context << u256(0) << InternalInstruction::SWAP3;
|
||||
// stack: counter source length target
|
||||
auto repeat = m_context.newTag();
|
||||
m_context << repeat;
|
||||
m_context << Instruction::DUP2 << Instruction::DUP5;
|
||||
m_context << Instruction::LT << Instruction::ISZERO;
|
||||
m_context << InternalInstruction::DUP2 << InternalInstruction::DUP5;
|
||||
m_context << InternalInstruction::LT << InternalInstruction::ISZERO;
|
||||
auto loopEnd = m_context.appendConditionalJump();
|
||||
m_context << Instruction::DUP3 << Instruction::DUP5;
|
||||
m_context << InternalInstruction::DUP3 << InternalInstruction::DUP5;
|
||||
accessIndex(_sourceType, false);
|
||||
MemoryItem(m_context, *_sourceType.baseType(), true).retrieveValue(SourceLocation(), true);
|
||||
if (auto baseArray = dynamic_cast<ArrayType const*>(_sourceType.baseType()))
|
||||
copyArrayToMemory(*baseArray, _padToWordBoundaries);
|
||||
else
|
||||
utils.storeInMemoryDynamic(*_sourceType.baseType());
|
||||
m_context << Instruction::SWAP3 << u256(1) << Instruction::ADD;
|
||||
m_context << Instruction::SWAP3;
|
||||
m_context << InternalInstruction::SWAP3 << u256(1) << InternalInstruction::ADD;
|
||||
m_context << InternalInstruction::SWAP3;
|
||||
m_context.appendJumpTo(repeat);
|
||||
m_context << loopEnd;
|
||||
m_context << Instruction::SWAP3;
|
||||
m_context << InternalInstruction::SWAP3;
|
||||
utils.popStackSlots(3);
|
||||
// stack: updated_target_pos
|
||||
return;
|
||||
@ -360,13 +360,13 @@ void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWord
|
||||
if (_sourceType.isDynamicallySized())
|
||||
{
|
||||
// change pointer to data part
|
||||
m_context << Instruction::SWAP1 << u256(32) << Instruction::ADD;
|
||||
m_context << Instruction::SWAP1;
|
||||
m_context << InternalInstruction::SWAP1 << u256(32) << InternalInstruction::ADD;
|
||||
m_context << InternalInstruction::SWAP1;
|
||||
}
|
||||
if (!_sourceType.isByteArrayOrString())
|
||||
convertLengthToSize(_sourceType);
|
||||
// stack: <target> <source> <size>
|
||||
m_context << Instruction::DUP1 << Instruction::DUP4 << Instruction::DUP4;
|
||||
m_context << InternalInstruction::DUP1 << InternalInstruction::DUP4 << InternalInstruction::DUP4;
|
||||
// We can resort to copying full 32 bytes only if
|
||||
// - the length is known to be a multiple of 32 or
|
||||
// - we will pad to full 32 bytes later anyway.
|
||||
@ -375,7 +375,7 @@ void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWord
|
||||
else
|
||||
utils.memoryCopy();
|
||||
|
||||
m_context << Instruction::SWAP1 << Instruction::POP;
|
||||
m_context << InternalInstruction::SWAP1 << InternalInstruction::POP;
|
||||
// stack: <target> <size>
|
||||
|
||||
bool paddingNeeded = _padToWordBoundaries && _sourceType.isByteArrayOrString();
|
||||
@ -383,43 +383,43 @@ void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWord
|
||||
if (paddingNeeded)
|
||||
{
|
||||
// stack: <target> <size>
|
||||
m_context << Instruction::SWAP1 << Instruction::DUP2 << Instruction::ADD;
|
||||
m_context << InternalInstruction::SWAP1 << InternalInstruction::DUP2 << InternalInstruction::ADD;
|
||||
// stack: <length> <target + size>
|
||||
m_context << Instruction::SWAP1 << u256(31) << Instruction::AND;
|
||||
m_context << InternalInstruction::SWAP1 << u256(31) << InternalInstruction::AND;
|
||||
// stack: <target + size> <remainder = size % 32>
|
||||
evmasm::AssemblyItem skip = m_context.newTag();
|
||||
if (_sourceType.isDynamicallySized())
|
||||
{
|
||||
m_context << Instruction::DUP1 << Instruction::ISZERO;
|
||||
m_context << InternalInstruction::DUP1 << InternalInstruction::ISZERO;
|
||||
m_context.appendConditionalJumpTo(skip);
|
||||
}
|
||||
// round off, load from there.
|
||||
// stack <target + size> <remainder = size % 32>
|
||||
m_context << Instruction::DUP1 << Instruction::DUP3;
|
||||
m_context << Instruction::SUB;
|
||||
m_context << InternalInstruction::DUP1 << InternalInstruction::DUP3;
|
||||
m_context << InternalInstruction::SUB;
|
||||
// stack: target+size remainder <target + size - remainder>
|
||||
m_context << Instruction::DUP1 << Instruction::MLOAD;
|
||||
m_context << InternalInstruction::DUP1 << InternalInstruction::MLOAD;
|
||||
// Now we AND it with ~(2**(8 * (32 - remainder)) - 1)
|
||||
m_context << u256(1);
|
||||
m_context << Instruction::DUP4 << u256(32) << Instruction::SUB;
|
||||
m_context << InternalInstruction::DUP4 << u256(32) << InternalInstruction::SUB;
|
||||
// stack: ...<v> 1 <32 - remainder>
|
||||
m_context << u256(0x100) << Instruction::EXP << Instruction::SUB;
|
||||
m_context << Instruction::NOT << Instruction::AND;
|
||||
m_context << u256(0x100) << InternalInstruction::EXP << InternalInstruction::SUB;
|
||||
m_context << InternalInstruction::NOT << InternalInstruction::AND;
|
||||
// stack: target+size remainder target+size-remainder <v & ...>
|
||||
m_context << Instruction::DUP2 << Instruction::MSTORE;
|
||||
m_context << InternalInstruction::DUP2 << InternalInstruction::MSTORE;
|
||||
// stack: target+size remainder target+size-remainder
|
||||
m_context << u256(32) << Instruction::ADD;
|
||||
m_context << u256(32) << InternalInstruction::ADD;
|
||||
// stack: target+size remainder <new_padded_end>
|
||||
m_context << Instruction::SWAP2 << Instruction::POP;
|
||||
m_context << InternalInstruction::SWAP2 << InternalInstruction::POP;
|
||||
|
||||
if (_sourceType.isDynamicallySized())
|
||||
m_context << skip.tag();
|
||||
// stack <target + "size"> <remainder = size % 32>
|
||||
m_context << Instruction::POP;
|
||||
m_context << InternalInstruction::POP;
|
||||
}
|
||||
else
|
||||
// stack: <target> <size>
|
||||
m_context << Instruction::ADD;
|
||||
m_context << InternalInstruction::ADD;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -431,48 +431,48 @@ void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWord
|
||||
retrieveLength(_sourceType);
|
||||
// stack here: memory_offset storage_offset length
|
||||
// jump to end if length is zero
|
||||
m_context << Instruction::DUP1 << Instruction::ISZERO;
|
||||
m_context << InternalInstruction::DUP1 << InternalInstruction::ISZERO;
|
||||
evmasm::AssemblyItem loopEnd = m_context.appendConditionalJump();
|
||||
// Special case for tightly-stored byte arrays
|
||||
if (_sourceType.isByteArrayOrString())
|
||||
{
|
||||
// stack here: memory_offset storage_offset length
|
||||
m_context << Instruction::DUP1 << u256(31) << Instruction::LT;
|
||||
m_context << InternalInstruction::DUP1 << u256(31) << InternalInstruction::LT;
|
||||
evmasm::AssemblyItem longByteArray = m_context.appendConditionalJump();
|
||||
// store the short byte array (discard lower-order byte)
|
||||
m_context << u256(0x100) << Instruction::DUP1;
|
||||
m_context << Instruction::DUP4 << Instruction::SLOAD;
|
||||
m_context << Instruction::DIV << Instruction::MUL;
|
||||
m_context << Instruction::DUP4 << Instruction::MSTORE;
|
||||
m_context << u256(0x100) << InternalInstruction::DUP1;
|
||||
m_context << InternalInstruction::DUP4 << InternalInstruction::SLOAD;
|
||||
m_context << InternalInstruction::DIV << InternalInstruction::MUL;
|
||||
m_context << InternalInstruction::DUP4 << InternalInstruction::MSTORE;
|
||||
// stack here: memory_offset storage_offset length
|
||||
// add 32 or length to memory offset
|
||||
m_context << Instruction::SWAP2;
|
||||
m_context << InternalInstruction::SWAP2;
|
||||
if (_padToWordBoundaries)
|
||||
m_context << u256(32);
|
||||
else
|
||||
m_context << Instruction::DUP3;
|
||||
m_context << Instruction::ADD;
|
||||
m_context << Instruction::SWAP2;
|
||||
m_context << InternalInstruction::DUP3;
|
||||
m_context << InternalInstruction::ADD;
|
||||
m_context << InternalInstruction::SWAP2;
|
||||
m_context.appendJumpTo(loopEnd);
|
||||
m_context << longByteArray;
|
||||
}
|
||||
else
|
||||
// convert length to memory size
|
||||
m_context << _sourceType.baseType()->memoryHeadSize() << Instruction::MUL;
|
||||
m_context << _sourceType.baseType()->memoryHeadSize() << InternalInstruction::MUL;
|
||||
|
||||
m_context << Instruction::DUP3 << Instruction::ADD << Instruction::SWAP2;
|
||||
m_context << InternalInstruction::DUP3 << InternalInstruction::ADD << InternalInstruction::SWAP2;
|
||||
if (_sourceType.isDynamicallySized())
|
||||
{
|
||||
// actual array data is stored at KECCAK256(storage_offset)
|
||||
m_context << Instruction::SWAP1;
|
||||
m_context << InternalInstruction::SWAP1;
|
||||
utils.computeHashStatic();
|
||||
m_context << Instruction::SWAP1;
|
||||
m_context << InternalInstruction::SWAP1;
|
||||
}
|
||||
|
||||
// stack here: memory_end_offset storage_data_offset memory_offset
|
||||
bool haveByteOffset = !_sourceType.isByteArrayOrString() && storageBytes <= 16;
|
||||
if (haveByteOffset)
|
||||
m_context << u256(0) << Instruction::SWAP1;
|
||||
m_context << u256(0) << InternalInstruction::SWAP1;
|
||||
// stack here: memory_end_offset storage_data_offset [storage_byte_offset] memory_offset
|
||||
evmasm::AssemblyItem loopStart = m_context.newTag();
|
||||
m_context << loopStart;
|
||||
@ -480,20 +480,20 @@ void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWord
|
||||
if (_sourceType.isByteArrayOrString())
|
||||
{
|
||||
// Packed both in storage and memory.
|
||||
m_context << Instruction::DUP2 << Instruction::SLOAD;
|
||||
m_context << Instruction::DUP2 << Instruction::MSTORE;
|
||||
m_context << InternalInstruction::DUP2 << InternalInstruction::SLOAD;
|
||||
m_context << InternalInstruction::DUP2 << InternalInstruction::MSTORE;
|
||||
// increment storage_data_offset by 1
|
||||
m_context << Instruction::SWAP1 << u256(1) << Instruction::ADD;
|
||||
m_context << InternalInstruction::SWAP1 << u256(1) << InternalInstruction::ADD;
|
||||
// increment memory offset by 32
|
||||
m_context << Instruction::SWAP1 << u256(32) << Instruction::ADD;
|
||||
m_context << InternalInstruction::SWAP1 << u256(32) << InternalInstruction::ADD;
|
||||
}
|
||||
else
|
||||
{
|
||||
// stack here: memory_end_offset storage_data_offset [storage_byte_offset] memory_offset
|
||||
if (haveByteOffset)
|
||||
m_context << Instruction::DUP3 << Instruction::DUP3;
|
||||
m_context << InternalInstruction::DUP3 << InternalInstruction::DUP3;
|
||||
else
|
||||
m_context << Instruction::DUP2 << u256(0);
|
||||
m_context << InternalInstruction::DUP2 << u256(0);
|
||||
StorageItem(m_context, *_sourceType.baseType()).retrieveValue(SourceLocation(), true);
|
||||
if (auto baseArray = dynamic_cast<ArrayType const*>(_sourceType.baseType()))
|
||||
copyArrayToMemory(*baseArray, _padToWordBoundaries);
|
||||
@ -504,18 +504,18 @@ void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWord
|
||||
incrementByteOffset(storageBytes, 2, 3);
|
||||
else
|
||||
{
|
||||
m_context << Instruction::SWAP1;
|
||||
m_context << storageSize << Instruction::ADD;
|
||||
m_context << Instruction::SWAP1;
|
||||
m_context << InternalInstruction::SWAP1;
|
||||
m_context << storageSize << InternalInstruction::ADD;
|
||||
m_context << InternalInstruction::SWAP1;
|
||||
}
|
||||
}
|
||||
// check for loop condition
|
||||
m_context << Instruction::DUP1 << dupInstruction(haveByteOffset ? 5 : 4);
|
||||
m_context << Instruction::GT;
|
||||
m_context << InternalInstruction::DUP1 << dupInstruction(haveByteOffset ? 5 : 4);
|
||||
m_context << InternalInstruction::GT;
|
||||
m_context.appendConditionalJumpTo(loopStart);
|
||||
// stack here: memory_end_offset storage_data_offset [storage_byte_offset] memory_offset
|
||||
if (haveByteOffset)
|
||||
m_context << Instruction::SWAP1 << Instruction::POP;
|
||||
m_context << InternalInstruction::SWAP1 << InternalInstruction::POP;
|
||||
if (!_sourceType.isByteArrayOrString())
|
||||
{
|
||||
solAssert(_sourceType.calldataStride() % 32 == 0, "");
|
||||
@ -526,12 +526,12 @@ void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWord
|
||||
// memory_end_offset - start is the actual length (we want to compute the ceil of).
|
||||
// memory_offset - start is its next multiple of 32, but it might be off by 32.
|
||||
// so we compute: memory_end_offset += (memory_offset - memory_end_offest) & 31
|
||||
m_context << Instruction::DUP3 << Instruction::SWAP1 << Instruction::SUB;
|
||||
m_context << u256(31) << Instruction::AND;
|
||||
m_context << Instruction::DUP3 << Instruction::ADD;
|
||||
m_context << Instruction::SWAP2;
|
||||
m_context << InternalInstruction::DUP3 << InternalInstruction::SWAP1 << InternalInstruction::SUB;
|
||||
m_context << u256(31) << InternalInstruction::AND;
|
||||
m_context << InternalInstruction::DUP3 << InternalInstruction::ADD;
|
||||
m_context << InternalInstruction::SWAP2;
|
||||
}
|
||||
m_context << loopEnd << Instruction::POP << Instruction::POP;
|
||||
m_context << loopEnd << InternalInstruction::POP << InternalInstruction::POP;
|
||||
}
|
||||
}
|
||||
|
||||
@ -555,20 +555,20 @@ void ArrayUtils::clearArray(ArrayType const& _typeIn) const
|
||||
if (_type.baseType()->isValueType())
|
||||
solAssert(_type.baseType()->storageSize() <= 1, "Invalid size for value type.");
|
||||
|
||||
_context << Instruction::POP; // remove byte offset
|
||||
_context << InternalInstruction::POP; // remove byte offset
|
||||
if (_type.isDynamicallySized())
|
||||
ArrayUtils(_context).clearDynamicArray(_type);
|
||||
else if (_type.length() == 0 || _type.baseType()->category() == Type::Category::Mapping)
|
||||
_context << Instruction::POP;
|
||||
_context << InternalInstruction::POP;
|
||||
else if (_type.baseType()->isValueType() && _type.storageSize() <= 5)
|
||||
{
|
||||
// unroll loop for small arrays @todo choose a good value
|
||||
// Note that we loop over storage slots here, not elements.
|
||||
for (unsigned i = 1; i < _type.storageSize(); ++i)
|
||||
_context
|
||||
<< u256(0) << Instruction::DUP2 << Instruction::SSTORE
|
||||
<< u256(1) << Instruction::ADD;
|
||||
_context << u256(0) << Instruction::SWAP1 << Instruction::SSTORE;
|
||||
<< u256(0) << InternalInstruction::DUP2 << InternalInstruction::SSTORE
|
||||
<< u256(1) << InternalInstruction::ADD;
|
||||
_context << u256(0) << InternalInstruction::SWAP1 << InternalInstruction::SSTORE;
|
||||
}
|
||||
else if (!_type.baseType()->isValueType() && _type.length() <= 4)
|
||||
{
|
||||
@ -579,22 +579,22 @@ void ArrayUtils::clearArray(ArrayType const& _typeIn) const
|
||||
_context << u256(0);
|
||||
StorageItem(_context, *_type.baseType()).setToZero(SourceLocation(), false);
|
||||
_context
|
||||
<< Instruction::POP
|
||||
<< u256(_type.baseType()->storageSize()) << Instruction::ADD;
|
||||
<< InternalInstruction::POP
|
||||
<< u256(_type.baseType()->storageSize()) << InternalInstruction::ADD;
|
||||
}
|
||||
_context << u256(0);
|
||||
StorageItem(_context, *_type.baseType()).setToZero(SourceLocation(), true);
|
||||
}
|
||||
else
|
||||
{
|
||||
_context << Instruction::DUP1 << _type.length();
|
||||
_context << InternalInstruction::DUP1 << _type.length();
|
||||
ArrayUtils(_context).convertLengthToSize(_type);
|
||||
_context << Instruction::ADD << Instruction::SWAP1;
|
||||
_context << InternalInstruction::ADD << InternalInstruction::SWAP1;
|
||||
if (_type.baseType()->storageBytes() < 32)
|
||||
ArrayUtils(_context).clearStorageLoop(TypeProvider::uint256());
|
||||
else
|
||||
ArrayUtils(_context).clearStorageLoop(_type.baseType());
|
||||
_context << Instruction::POP;
|
||||
_context << InternalInstruction::POP;
|
||||
}
|
||||
solAssert(_context.stackHeight() == stackHeightStart - 2, "");
|
||||
}
|
||||
@ -609,15 +609,15 @@ void ArrayUtils::clearDynamicArray(ArrayType const& _type) const
|
||||
// fetch length
|
||||
retrieveLength(_type);
|
||||
// set length to zero
|
||||
m_context << u256(0) << Instruction::DUP3 << Instruction::SSTORE;
|
||||
m_context << u256(0) << InternalInstruction::DUP3 << InternalInstruction::SSTORE;
|
||||
// Special case: short byte arrays are stored togeher with their length
|
||||
evmasm::AssemblyItem endTag = m_context.newTag();
|
||||
if (_type.isByteArrayOrString())
|
||||
{
|
||||
// stack: ref old_length
|
||||
m_context << Instruction::DUP1 << u256(31) << Instruction::LT;
|
||||
m_context << InternalInstruction::DUP1 << u256(31) << InternalInstruction::LT;
|
||||
evmasm::AssemblyItem longByteArray = m_context.appendConditionalJump();
|
||||
m_context << Instruction::POP;
|
||||
m_context << InternalInstruction::POP;
|
||||
m_context.appendJumpTo(endTag);
|
||||
m_context.adjustStackOffset(1); // needed because of jump
|
||||
m_context << longByteArray;
|
||||
@ -625,11 +625,11 @@ void ArrayUtils::clearDynamicArray(ArrayType const& _type) const
|
||||
// stack: ref old_length
|
||||
convertLengthToSize(_type);
|
||||
// compute data positions
|
||||
m_context << Instruction::SWAP1;
|
||||
m_context << InternalInstruction::SWAP1;
|
||||
CompilerUtils(m_context).computeHashStatic();
|
||||
// stack: len data_pos
|
||||
m_context << Instruction::SWAP1 << Instruction::DUP2 << Instruction::ADD
|
||||
<< Instruction::SWAP1;
|
||||
m_context << InternalInstruction::SWAP1 << InternalInstruction::DUP2 << InternalInstruction::ADD
|
||||
<< InternalInstruction::SWAP1;
|
||||
// stack: data_pos_end data_pos
|
||||
if (_type.storageStride() < 32)
|
||||
clearStorageLoop(TypeProvider::uint256());
|
||||
@ -637,7 +637,7 @@ void ArrayUtils::clearDynamicArray(ArrayType const& _type) const
|
||||
clearStorageLoop(_type.baseType());
|
||||
// cleanup
|
||||
m_context << endTag;
|
||||
m_context << Instruction::POP;
|
||||
m_context << InternalInstruction::POP;
|
||||
}
|
||||
|
||||
void ArrayUtils::resizeDynamicArray(ArrayType const& _typeIn) const
|
||||
@ -670,13 +670,13 @@ void ArrayUtils::resizeDynamicArray(ArrayType const& _typeIn) const
|
||||
evmasm::AssemblyItem regularPath = _context.newTag();
|
||||
// We start by a large case-distinction about the old and new length of the byte array.
|
||||
|
||||
_context << Instruction::DUP3 << Instruction::SLOAD;
|
||||
_context << InternalInstruction::DUP3 << InternalInstruction::SLOAD;
|
||||
// stack: ref new_length current_length ref_value
|
||||
|
||||
solAssert(_context.stackHeight() - stackHeightStart == 4 - 2, "3");
|
||||
_context << Instruction::DUP2 << u256(31) << Instruction::LT;
|
||||
_context << InternalInstruction::DUP2 << u256(31) << InternalInstruction::LT;
|
||||
evmasm::AssemblyItem currentIsLong = _context.appendConditionalJump();
|
||||
_context << Instruction::DUP3 << u256(31) << Instruction::LT;
|
||||
_context << InternalInstruction::DUP3 << u256(31) << InternalInstruction::LT;
|
||||
evmasm::AssemblyItem newIsLong = _context.appendConditionalJump();
|
||||
|
||||
// Here: short -> short
|
||||
@ -684,17 +684,17 @@ void ArrayUtils::resizeDynamicArray(ArrayType const& _typeIn) const
|
||||
// Compute 1 << (256 - 8 * new_size)
|
||||
evmasm::AssemblyItem shortToShort = _context.newTag();
|
||||
_context << shortToShort;
|
||||
_context << Instruction::DUP3 << u256(8) << Instruction::MUL;
|
||||
_context << u256(0x100) << Instruction::SUB;
|
||||
_context << u256(2) << Instruction::EXP;
|
||||
_context << InternalInstruction::DUP3 << u256(8) << InternalInstruction::MUL;
|
||||
_context << u256(0x100) << InternalInstruction::SUB;
|
||||
_context << u256(2) << InternalInstruction::EXP;
|
||||
// Divide and multiply by that value, clearing bits.
|
||||
_context << Instruction::DUP1 << Instruction::SWAP2;
|
||||
_context << Instruction::DIV << Instruction::MUL;
|
||||
_context << InternalInstruction::DUP1 << InternalInstruction::SWAP2;
|
||||
_context << InternalInstruction::DIV << InternalInstruction::MUL;
|
||||
// Insert 2*length.
|
||||
_context << Instruction::DUP3 << Instruction::DUP1 << Instruction::ADD;
|
||||
_context << Instruction::OR;
|
||||
_context << InternalInstruction::DUP3 << InternalInstruction::DUP1 << InternalInstruction::ADD;
|
||||
_context << InternalInstruction::OR;
|
||||
// Store.
|
||||
_context << Instruction::DUP4 << Instruction::SSTORE;
|
||||
_context << InternalInstruction::DUP4 << InternalInstruction::SSTORE;
|
||||
solAssert(_context.stackHeight() - stackHeightStart == 3 - 2, "3");
|
||||
_context.appendJumpTo(resizeEnd);
|
||||
|
||||
@ -705,24 +705,24 @@ void ArrayUtils::resizeDynamicArray(ArrayType const& _typeIn) const
|
||||
// stack: ref new_length current_length ref_value
|
||||
solAssert(_context.stackHeight() - stackHeightStart == 4 - 2, "3");
|
||||
// Zero out lower-order byte.
|
||||
_context << u256(0xff) << Instruction::NOT << Instruction::AND;
|
||||
_context << u256(0xff) << InternalInstruction::NOT << InternalInstruction::AND;
|
||||
// Store at data location.
|
||||
_context << Instruction::DUP4;
|
||||
_context << InternalInstruction::DUP4;
|
||||
CompilerUtils(_context).computeHashStatic();
|
||||
_context << Instruction::SSTORE;
|
||||
_context << InternalInstruction::SSTORE;
|
||||
// stack: ref new_length current_length
|
||||
// Store new length: Compule 2*length + 1 and store it.
|
||||
_context << Instruction::DUP2 << Instruction::DUP1 << Instruction::ADD;
|
||||
_context << u256(1) << Instruction::ADD;
|
||||
_context << InternalInstruction::DUP2 << InternalInstruction::DUP1 << InternalInstruction::ADD;
|
||||
_context << u256(1) << InternalInstruction::ADD;
|
||||
// stack: ref new_length current_length 2*new_length+1
|
||||
_context << Instruction::DUP4 << Instruction::SSTORE;
|
||||
_context << InternalInstruction::DUP4 << InternalInstruction::SSTORE;
|
||||
solAssert(_context.stackHeight() - stackHeightStart == 3 - 2, "3");
|
||||
_context.appendJumpTo(resizeEnd);
|
||||
|
||||
_context.adjustStackOffset(1); // we have to do that because of the jumps
|
||||
|
||||
_context << currentIsLong;
|
||||
_context << Instruction::DUP3 << u256(31) << Instruction::LT;
|
||||
_context << InternalInstruction::DUP3 << u256(31) << InternalInstruction::LT;
|
||||
_context.appendConditionalJumpTo(regularPath);
|
||||
|
||||
// Here: long -> short
|
||||
@ -731,51 +731,51 @@ void ArrayUtils::resizeDynamicArray(ArrayType const& _typeIn) const
|
||||
|
||||
// stack: ref new_length current_length ref_value
|
||||
solAssert(_context.stackHeight() - stackHeightStart == 4 - 2, "3");
|
||||
_context << Instruction::POP << Instruction::DUP3;
|
||||
_context << InternalInstruction::POP << InternalInstruction::DUP3;
|
||||
CompilerUtils(_context).computeHashStatic();
|
||||
_context << Instruction::DUP1 << Instruction::SLOAD << Instruction::SWAP1;
|
||||
_context << InternalInstruction::DUP1 << InternalInstruction::SLOAD << InternalInstruction::SWAP1;
|
||||
// stack: ref new_length current_length first_word data_location
|
||||
_context << Instruction::DUP3;
|
||||
_context << InternalInstruction::DUP3;
|
||||
ArrayUtils(_context).convertLengthToSize(_type);
|
||||
_context << Instruction::DUP2 << Instruction::ADD << Instruction::SWAP1;
|
||||
_context << InternalInstruction::DUP2 << InternalInstruction::ADD << InternalInstruction::SWAP1;
|
||||
// stack: ref new_length current_length first_word data_location_end data_location
|
||||
ArrayUtils(_context).clearStorageLoop(TypeProvider::uint256());
|
||||
_context << Instruction::POP;
|
||||
_context << InternalInstruction::POP;
|
||||
// stack: ref new_length current_length first_word
|
||||
solAssert(_context.stackHeight() - stackHeightStart == 4 - 2, "3");
|
||||
_context.appendJumpTo(shortToShort);
|
||||
|
||||
_context << regularPath;
|
||||
// stack: ref new_length current_length ref_value
|
||||
_context << Instruction::POP;
|
||||
_context << InternalInstruction::POP;
|
||||
}
|
||||
|
||||
// Change of length for a regular array (i.e. length at location, data at KECCAK256(location)).
|
||||
// stack: ref new_length old_length
|
||||
// store new length
|
||||
_context << Instruction::DUP2;
|
||||
_context << InternalInstruction::DUP2;
|
||||
if (_type.isByteArrayOrString())
|
||||
// For a "long" byte array, store length as 2*length+1
|
||||
_context << Instruction::DUP1 << Instruction::ADD << u256(1) << Instruction::ADD;
|
||||
_context << Instruction::DUP4 << Instruction::SSTORE;
|
||||
_context << InternalInstruction::DUP1 << InternalInstruction::ADD << u256(1) << InternalInstruction::ADD;
|
||||
_context << InternalInstruction::DUP4 << InternalInstruction::SSTORE;
|
||||
// skip if size is not reduced
|
||||
_context << Instruction::DUP2 << Instruction::DUP2
|
||||
<< Instruction::GT << Instruction::ISZERO;
|
||||
_context << InternalInstruction::DUP2 << InternalInstruction::DUP2
|
||||
<< InternalInstruction::GT << InternalInstruction::ISZERO;
|
||||
_context.appendConditionalJumpTo(resizeEnd);
|
||||
|
||||
// size reduced, clear the end of the array
|
||||
// stack: ref new_length old_length
|
||||
ArrayUtils(_context).convertLengthToSize(_type);
|
||||
_context << Instruction::DUP2;
|
||||
_context << InternalInstruction::DUP2;
|
||||
ArrayUtils(_context).convertLengthToSize(_type);
|
||||
// stack: ref new_length old_size new_size
|
||||
// compute data positions
|
||||
_context << Instruction::DUP4;
|
||||
_context << InternalInstruction::DUP4;
|
||||
CompilerUtils(_context).computeHashStatic();
|
||||
// stack: ref new_length old_size new_size data_pos
|
||||
_context << Instruction::SWAP2 << Instruction::DUP3 << Instruction::ADD;
|
||||
_context << InternalInstruction::SWAP2 << InternalInstruction::DUP3 << InternalInstruction::ADD;
|
||||
// stack: ref new_length data_pos new_size delete_end
|
||||
_context << Instruction::SWAP2 << Instruction::ADD;
|
||||
_context << InternalInstruction::SWAP2 << InternalInstruction::ADD;
|
||||
// stack: ref new_length delete_end delete_start
|
||||
if (_type.storageStride() < 32)
|
||||
ArrayUtils(_context).clearStorageLoop(TypeProvider::uint256());
|
||||
@ -784,7 +784,7 @@ void ArrayUtils::resizeDynamicArray(ArrayType const& _typeIn) const
|
||||
|
||||
_context << resizeEnd;
|
||||
// cleanup
|
||||
_context << Instruction::POP << Instruction::POP << Instruction::POP;
|
||||
_context << InternalInstruction::POP << InternalInstruction::POP << InternalInstruction::POP;
|
||||
solAssert(_context.stackHeight() == stackHeightStart - 2, "");
|
||||
}
|
||||
);
|
||||
@ -806,7 +806,7 @@ void ArrayUtils::incrementDynamicArraySize(ArrayType const& _type) const
|
||||
// lowest-order byte (we actually use a mask with fewer bits) must
|
||||
// be (31*2+0) = 62
|
||||
|
||||
m_context << Instruction::DUP1 << Instruction::SLOAD << Instruction::DUP1;
|
||||
m_context << InternalInstruction::DUP1 << InternalInstruction::SLOAD << InternalInstruction::DUP1;
|
||||
m_context.callYulFunction(m_context.utilFunctions().extractByteArrayLengthFunction(), 1, 1);
|
||||
m_context.appendInlineAssembly(R"({
|
||||
// We have to copy if length is exactly 31, because that marks
|
||||
@ -824,7 +824,7 @@ void ArrayUtils::incrementDynamicArraySize(ArrayType const& _type) const
|
||||
// return new length in ref
|
||||
ref := add(length, 1)
|
||||
})", {"ref", "data", "length"});
|
||||
m_context << Instruction::POP << Instruction::POP;
|
||||
m_context << InternalInstruction::POP << InternalInstruction::POP;
|
||||
}
|
||||
else
|
||||
m_context.appendInlineAssembly(R"({
|
||||
@ -843,7 +843,7 @@ void ArrayUtils::popStorageArrayElement(ArrayType const& _type) const
|
||||
|
||||
if (_type.isByteArrayOrString())
|
||||
{
|
||||
m_context << Instruction::DUP1 << Instruction::SLOAD << Instruction::DUP1;
|
||||
m_context << InternalInstruction::DUP1 << InternalInstruction::SLOAD << InternalInstruction::DUP1;
|
||||
m_context.callYulFunction(m_context.utilFunctions().extractByteArrayLengthFunction(), 1, 1);
|
||||
util::Whiskers code(R"({
|
||||
if iszero(length) {
|
||||
@ -892,25 +892,25 @@ void ArrayUtils::popStorageArrayElement(ArrayType const& _type) const
|
||||
code("panicSelector", util::selectorFromSignatureU256("Panic(uint256)").str());
|
||||
code("emptyArrayPop", to_string(unsigned(util::PanicCode::EmptyArrayPop)));
|
||||
m_context.appendInlineAssembly(code.render(), {"ref", "slot_value", "length"});
|
||||
m_context << Instruction::POP << Instruction::POP << Instruction::POP;
|
||||
m_context << InternalInstruction::POP << InternalInstruction::POP << InternalInstruction::POP;
|
||||
}
|
||||
else
|
||||
{
|
||||
// stack: ArrayReference
|
||||
retrieveLength(_type);
|
||||
// stack: ArrayReference oldLength
|
||||
m_context << Instruction::DUP1;
|
||||
m_context << InternalInstruction::DUP1;
|
||||
// stack: ArrayReference oldLength oldLength
|
||||
m_context << Instruction::ISZERO;
|
||||
m_context << InternalInstruction::ISZERO;
|
||||
m_context.appendConditionalPanic(util::PanicCode::EmptyArrayPop);
|
||||
|
||||
// Stack: ArrayReference oldLength
|
||||
m_context << u256(1) << Instruction::SWAP1 << Instruction::SUB;
|
||||
m_context << u256(1) << InternalInstruction::SWAP1 << InternalInstruction::SUB;
|
||||
// Stack ArrayReference newLength
|
||||
|
||||
if (_type.baseType()->category() != Type::Category::Mapping)
|
||||
{
|
||||
m_context << Instruction::DUP2 << Instruction::DUP2;
|
||||
m_context << InternalInstruction::DUP2 << InternalInstruction::DUP2;
|
||||
// Stack ArrayReference newLength ArrayReference newLength;
|
||||
accessIndex(_type, false);
|
||||
// Stack: ArrayReference newLength storage_slot byte_offset
|
||||
@ -918,7 +918,7 @@ void ArrayUtils::popStorageArrayElement(ArrayType const& _type) const
|
||||
}
|
||||
|
||||
// Stack: ArrayReference newLength
|
||||
m_context << Instruction::SWAP1 << Instruction::SSTORE;
|
||||
m_context << InternalInstruction::SWAP1 << InternalInstruction::SSTORE;
|
||||
}
|
||||
}
|
||||
|
||||
@ -934,7 +934,7 @@ void ArrayUtils::clearStorageLoop(Type const* _type) const
|
||||
unsigned stackHeightStart = _context.stackHeight();
|
||||
if (_type->category() == Type::Category::Mapping)
|
||||
{
|
||||
_context << Instruction::POP;
|
||||
_context << InternalInstruction::POP;
|
||||
return;
|
||||
}
|
||||
// stack: end_pos pos
|
||||
@ -943,22 +943,22 @@ void ArrayUtils::clearStorageLoop(Type const* _type) const
|
||||
_context << loopStart;
|
||||
// check for loop condition
|
||||
_context <<
|
||||
Instruction::DUP1 <<
|
||||
Instruction::DUP3 <<
|
||||
Instruction::GT <<
|
||||
Instruction::ISZERO;
|
||||
InternalInstruction::DUP1 <<
|
||||
InternalInstruction::DUP3 <<
|
||||
InternalInstruction::GT <<
|
||||
InternalInstruction::ISZERO;
|
||||
evmasm::AssemblyItem zeroLoopEnd = _context.newTag();
|
||||
_context.appendConditionalJumpTo(zeroLoopEnd);
|
||||
// delete
|
||||
_context << u256(0);
|
||||
StorageItem(_context, *_type).setToZero(SourceLocation(), false);
|
||||
_context << Instruction::POP;
|
||||
_context << InternalInstruction::POP;
|
||||
// increment
|
||||
_context << _type->storageSize() << Instruction::ADD;
|
||||
_context << _type->storageSize() << InternalInstruction::ADD;
|
||||
_context.appendJumpTo(loopStart);
|
||||
// cleanup
|
||||
_context << zeroLoopEnd;
|
||||
_context << Instruction::POP;
|
||||
_context << InternalInstruction::POP;
|
||||
|
||||
solAssert(_context.stackHeight() == stackHeightStart - 1, "");
|
||||
}
|
||||
@ -973,17 +973,17 @@ void ArrayUtils::convertLengthToSize(ArrayType const& _arrayType, bool _pad) con
|
||||
{
|
||||
unsigned baseBytes = _arrayType.baseType()->storageBytes();
|
||||
if (baseBytes == 0)
|
||||
m_context << Instruction::POP << u256(1);
|
||||
m_context << InternalInstruction::POP << u256(1);
|
||||
else if (baseBytes <= 16)
|
||||
{
|
||||
unsigned itemsPerSlot = 32 / baseBytes;
|
||||
m_context
|
||||
<< u256(itemsPerSlot - 1) << Instruction::ADD
|
||||
<< u256(itemsPerSlot) << Instruction::SWAP1 << Instruction::DIV;
|
||||
<< u256(itemsPerSlot - 1) << InternalInstruction::ADD
|
||||
<< u256(itemsPerSlot) << InternalInstruction::SWAP1 << InternalInstruction::DIV;
|
||||
}
|
||||
}
|
||||
else
|
||||
m_context << _arrayType.baseType()->storageSize() << Instruction::MUL;
|
||||
m_context << _arrayType.baseType()->storageSize() << InternalInstruction::MUL;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -993,12 +993,12 @@ void ArrayUtils::convertLengthToSize(ArrayType const& _arrayType, bool _pad) con
|
||||
m_context << _arrayType.memoryStride();
|
||||
else
|
||||
m_context << _arrayType.calldataStride();
|
||||
m_context << Instruction::MUL;
|
||||
m_context << InternalInstruction::MUL;
|
||||
}
|
||||
else if (_pad)
|
||||
m_context << u256(31) << Instruction::ADD
|
||||
<< u256(32) << Instruction::DUP1
|
||||
<< Instruction::SWAP2 << Instruction::DIV << Instruction::MUL;
|
||||
m_context << u256(31) << InternalInstruction::ADD
|
||||
<< u256(32) << InternalInstruction::DUP1
|
||||
<< InternalInstruction::SWAP2 << InternalInstruction::DIV << InternalInstruction::MUL;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1015,10 +1015,10 @@ void ArrayUtils::retrieveLength(ArrayType const& _arrayType, unsigned _stackDept
|
||||
// length is stored on the stack
|
||||
break;
|
||||
case DataLocation::Memory:
|
||||
m_context << Instruction::MLOAD;
|
||||
m_context << InternalInstruction::MLOAD;
|
||||
break;
|
||||
case DataLocation::Storage:
|
||||
m_context << Instruction::SLOAD;
|
||||
m_context << InternalInstruction::SLOAD;
|
||||
if (_arrayType.isByteArrayOrString())
|
||||
m_context.callYulFunction(m_context.utilFunctions().extractByteArrayLengthFunction(), 1, 1);
|
||||
break;
|
||||
@ -1037,13 +1037,13 @@ void ArrayUtils::accessIndex(ArrayType const& _arrayType, bool _doBoundsCheck, b
|
||||
ArrayUtils::retrieveLength(_arrayType, 1);
|
||||
// Stack: ref [length] index length
|
||||
// check out-of-bounds access
|
||||
m_context << Instruction::DUP2 << Instruction::LT << Instruction::ISZERO;
|
||||
m_context << InternalInstruction::DUP2 << InternalInstruction::LT << InternalInstruction::ISZERO;
|
||||
// out-of-bounds access throws exception
|
||||
m_context.appendConditionalPanic(util::PanicCode::ArrayOutOfBounds);
|
||||
}
|
||||
if (location == DataLocation::CallData && _arrayType.isDynamicallySized())
|
||||
// remove length if present
|
||||
m_context << Instruction::SWAP1 << Instruction::POP;
|
||||
m_context << InternalInstruction::SWAP1 << InternalInstruction::POP;
|
||||
|
||||
// stack: <base_ref> <index>
|
||||
switch (location)
|
||||
@ -1051,46 +1051,46 @@ void ArrayUtils::accessIndex(ArrayType const& _arrayType, bool _doBoundsCheck, b
|
||||
case DataLocation::Memory:
|
||||
// stack: <base_ref> <index>
|
||||
if (!_arrayType.isByteArrayOrString())
|
||||
m_context << u256(_arrayType.memoryHeadSize()) << Instruction::MUL;
|
||||
m_context << u256(_arrayType.memoryHeadSize()) << InternalInstruction::MUL;
|
||||
if (_arrayType.isDynamicallySized())
|
||||
m_context << u256(32) << Instruction::ADD;
|
||||
m_context << u256(32) << InternalInstruction::ADD;
|
||||
if (_keepReference)
|
||||
m_context << Instruction::DUP2;
|
||||
m_context << Instruction::ADD;
|
||||
m_context << InternalInstruction::DUP2;
|
||||
m_context << InternalInstruction::ADD;
|
||||
break;
|
||||
case DataLocation::CallData:
|
||||
if (!_arrayType.isByteArrayOrString())
|
||||
{
|
||||
m_context << _arrayType.calldataStride();
|
||||
m_context << Instruction::MUL;
|
||||
m_context << InternalInstruction::MUL;
|
||||
}
|
||||
// stack: <base_ref> <index * size>
|
||||
if (_keepReference)
|
||||
m_context << Instruction::DUP2;
|
||||
m_context << Instruction::ADD;
|
||||
m_context << InternalInstruction::DUP2;
|
||||
m_context << InternalInstruction::ADD;
|
||||
break;
|
||||
case DataLocation::Storage:
|
||||
{
|
||||
if (_keepReference)
|
||||
m_context << Instruction::DUP2;
|
||||
m_context << InternalInstruction::DUP2;
|
||||
else
|
||||
m_context << Instruction::SWAP1;
|
||||
m_context << InternalInstruction::SWAP1;
|
||||
// stack: [<base_ref>] <index> <base_ref>
|
||||
|
||||
evmasm::AssemblyItem endTag = m_context.newTag();
|
||||
if (_arrayType.isByteArrayOrString())
|
||||
{
|
||||
// Special case of short byte arrays.
|
||||
m_context << Instruction::SWAP1;
|
||||
m_context << Instruction::DUP2 << Instruction::SLOAD;
|
||||
m_context << u256(1) << Instruction::AND << Instruction::ISZERO;
|
||||
m_context << InternalInstruction::SWAP1;
|
||||
m_context << InternalInstruction::DUP2 << InternalInstruction::SLOAD;
|
||||
m_context << u256(1) << InternalInstruction::AND << InternalInstruction::ISZERO;
|
||||
// No action needed for short byte arrays.
|
||||
m_context.appendConditionalJumpTo(endTag);
|
||||
m_context << Instruction::SWAP1;
|
||||
m_context << InternalInstruction::SWAP1;
|
||||
}
|
||||
if (_arrayType.isDynamicallySized())
|
||||
CompilerUtils(m_context).computeHashStatic();
|
||||
m_context << Instruction::SWAP1;
|
||||
m_context << InternalInstruction::SWAP1;
|
||||
if (_arrayType.baseType()->storageBytes() <= 16)
|
||||
{
|
||||
// stack: <data_ref> <index>
|
||||
@ -1099,22 +1099,22 @@ void ArrayUtils::accessIndex(ArrayType const& _arrayType, bool _doBoundsCheck, b
|
||||
unsigned byteSize = _arrayType.baseType()->storageBytes();
|
||||
solAssert(byteSize != 0, "");
|
||||
unsigned itemsPerSlot = 32 / byteSize;
|
||||
m_context << u256(itemsPerSlot) << Instruction::SWAP2;
|
||||
m_context << u256(itemsPerSlot) << InternalInstruction::SWAP2;
|
||||
// stack: itemsPerSlot index data_ref
|
||||
m_context
|
||||
<< Instruction::DUP3 << Instruction::DUP3
|
||||
<< Instruction::DIV << Instruction::ADD
|
||||
<< InternalInstruction::DUP3 << InternalInstruction::DUP3
|
||||
<< InternalInstruction::DIV << InternalInstruction::ADD
|
||||
// stack: itemsPerSlot index (data_ref + index / itemsPerSlot)
|
||||
<< Instruction::SWAP2 << Instruction::SWAP1
|
||||
<< Instruction::MOD;
|
||||
<< InternalInstruction::SWAP2 << InternalInstruction::SWAP1
|
||||
<< InternalInstruction::MOD;
|
||||
if (byteSize != 1)
|
||||
m_context << u256(byteSize) << Instruction::MUL;
|
||||
m_context << u256(byteSize) << InternalInstruction::MUL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_arrayType.baseType()->storageSize() != 1)
|
||||
m_context << _arrayType.baseType()->storageSize() << Instruction::MUL;
|
||||
m_context << Instruction::ADD << u256(0);
|
||||
m_context << _arrayType.baseType()->storageSize() << InternalInstruction::MUL;
|
||||
m_context << InternalInstruction::ADD << u256(0);
|
||||
}
|
||||
m_context << endTag;
|
||||
break;
|
||||
@ -1179,26 +1179,26 @@ void ArrayUtils::incrementByteOffset(unsigned _byteSize, unsigned _byteOffsetPos
|
||||
// }
|
||||
if (_byteOffsetPosition > 1)
|
||||
m_context << swapInstruction(_byteOffsetPosition - 1);
|
||||
m_context << u256(_byteSize) << Instruction::ADD;
|
||||
m_context << u256(_byteSize) << InternalInstruction::ADD;
|
||||
if (_byteOffsetPosition > 1)
|
||||
m_context << swapInstruction(_byteOffsetPosition - 1);
|
||||
// compute, X := (byteOffset + byteSize - 1) / 32, should be 1 iff byteOffset + bytesize > 32
|
||||
m_context
|
||||
<< u256(32) << dupInstruction(1 + _byteOffsetPosition) << u256(_byteSize - 1)
|
||||
<< Instruction::ADD << Instruction::DIV;
|
||||
<< InternalInstruction::ADD << InternalInstruction::DIV;
|
||||
// increment storage offset if X == 1 (just add X to it)
|
||||
// stack: X
|
||||
m_context
|
||||
<< swapInstruction(_storageOffsetPosition) << dupInstruction(_storageOffsetPosition + 1)
|
||||
<< Instruction::ADD << swapInstruction(_storageOffsetPosition);
|
||||
<< InternalInstruction::ADD << swapInstruction(_storageOffsetPosition);
|
||||
// stack: X
|
||||
// set source_byte_offset to zero if X == 1 (using source_byte_offset *= 1 - X)
|
||||
m_context << u256(1) << Instruction::SUB;
|
||||
m_context << u256(1) << InternalInstruction::SUB;
|
||||
// stack: 1 - X
|
||||
if (_byteOffsetPosition == 1)
|
||||
m_context << Instruction::MUL;
|
||||
m_context << InternalInstruction::MUL;
|
||||
else
|
||||
m_context
|
||||
<< dupInstruction(_byteOffsetPosition + 1) << Instruction::MUL
|
||||
<< swapInstruction(_byteOffsetPosition) << Instruction::POP;
|
||||
<< dupInstruction(_byteOffsetPosition + 1) << InternalInstruction::MUL
|
||||
<< swapInstruction(_byteOffsetPosition) << InternalInstruction::POP;
|
||||
}
|
||||
|
@ -329,7 +329,7 @@ pair<u256, unsigned> CompilerContext::storageLocationOfVariable(Declaration cons
|
||||
|
||||
CompilerContext& CompilerContext::appendJump(evmasm::AssemblyItem::JumpType _jumpType)
|
||||
{
|
||||
evmasm::AssemblyItem item(Instruction::JUMP);
|
||||
evmasm::AssemblyItem item(InternalInstruction::JUMP);
|
||||
item.setJumpType(_jumpType);
|
||||
return *this << item;
|
||||
}
|
||||
@ -342,7 +342,7 @@ CompilerContext& CompilerContext::appendPanic(util::PanicCode _code)
|
||||
|
||||
CompilerContext& CompilerContext::appendConditionalPanic(util::PanicCode _code)
|
||||
{
|
||||
*this << Instruction::ISZERO;
|
||||
*this << InternalInstruction::ISZERO;
|
||||
evmasm::AssemblyItem afterTag = appendConditionalJump();
|
||||
appendPanic(_code);
|
||||
*this << afterTag;
|
||||
@ -366,7 +366,7 @@ CompilerContext& CompilerContext::appendConditionalRevert(bool _forwardReturnDat
|
||||
})", {"condition"});
|
||||
else
|
||||
appendInlineAssembly("{ if condition { " + revertReasonIfDebug(_message) + " } }", {"condition"});
|
||||
*this << Instruction::POP;
|
||||
*this << InternalInstruction::POP;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -430,7 +430,7 @@ void CompilerContext::appendInlineAssembly(
|
||||
else
|
||||
{
|
||||
_assembly.appendInstruction(swapInstruction(static_cast<unsigned>(stackDiff)));
|
||||
_assembly.appendInstruction(Instruction::POP);
|
||||
_assembly.appendInstruction(InternalInstruction::POP);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -251,7 +251,7 @@ public:
|
||||
|
||||
/// Append elements to the current instruction list and adjust @a m_stackOffset.
|
||||
CompilerContext& operator<<(evmasm::AssemblyItem const& _item) { m_asm->append(_item); return *this; }
|
||||
CompilerContext& operator<<(evmasm::Instruction _instruction) { m_asm->append(_instruction); return *this; }
|
||||
CompilerContext& operator<<(evmasm::InternalInstruction _instruction) { m_asm->append(_instruction); return *this; }
|
||||
CompilerContext& operator<<(u256 const& _value) { m_asm->append(_value); return *this; }
|
||||
CompilerContext& operator<<(bytes const& _data) { m_asm->append(_data); return *this; }
|
||||
|
||||
|
@ -62,33 +62,33 @@ void CompilerUtils::initialiseFreeMemoryPointer()
|
||||
|
||||
void CompilerUtils::fetchFreeMemoryPointer()
|
||||
{
|
||||
m_context << u256(freeMemoryPointer) << Instruction::MLOAD;
|
||||
m_context << u256(freeMemoryPointer) << InternalInstruction::MLOAD;
|
||||
}
|
||||
|
||||
void CompilerUtils::storeFreeMemoryPointer()
|
||||
{
|
||||
m_context << u256(freeMemoryPointer) << Instruction::MSTORE;
|
||||
m_context << u256(freeMemoryPointer) << InternalInstruction::MSTORE;
|
||||
}
|
||||
|
||||
void CompilerUtils::allocateMemory()
|
||||
{
|
||||
fetchFreeMemoryPointer();
|
||||
m_context << Instruction::SWAP1 << Instruction::DUP2 << Instruction::ADD;
|
||||
m_context << InternalInstruction::SWAP1 << InternalInstruction::DUP2 << InternalInstruction::ADD;
|
||||
storeFreeMemoryPointer();
|
||||
}
|
||||
|
||||
void CompilerUtils::allocateMemory(u256 const& size)
|
||||
{
|
||||
fetchFreeMemoryPointer();
|
||||
m_context << Instruction::DUP1 << size << Instruction::ADD;
|
||||
m_context << InternalInstruction::DUP1 << size << InternalInstruction::ADD;
|
||||
storeFreeMemoryPointer();
|
||||
}
|
||||
|
||||
void CompilerUtils::toSizeAfterFreeMemoryPointer()
|
||||
{
|
||||
fetchFreeMemoryPointer();
|
||||
m_context << Instruction::DUP1 << Instruction::SWAP2 << Instruction::SUB;
|
||||
m_context << Instruction::SWAP1;
|
||||
m_context << InternalInstruction::DUP1 << InternalInstruction::SWAP2 << InternalInstruction::SUB;
|
||||
m_context << InternalInstruction::SWAP1;
|
||||
}
|
||||
|
||||
void CompilerUtils::revertWithStringData(Type const& _argumentType)
|
||||
@ -96,12 +96,12 @@ void CompilerUtils::revertWithStringData(Type const& _argumentType)
|
||||
solAssert(_argumentType.isImplicitlyConvertibleTo(*TypeProvider::fromElementaryTypeName("string memory")));
|
||||
fetchFreeMemoryPointer();
|
||||
m_context << util::selectorFromSignatureU256("Error(string)");
|
||||
m_context << Instruction::DUP2 << Instruction::MSTORE;
|
||||
m_context << u256(4) << Instruction::ADD;
|
||||
m_context << InternalInstruction::DUP2 << InternalInstruction::MSTORE;
|
||||
m_context << u256(4) << InternalInstruction::ADD;
|
||||
// Stack: <string data> <mem pos of encoding start>
|
||||
abiEncode({&_argumentType}, {TypeProvider::array(DataLocation::Memory, true)});
|
||||
toSizeAfterFreeMemoryPointer();
|
||||
m_context << Instruction::REVERT;
|
||||
m_context << InternalInstruction::REVERT;
|
||||
}
|
||||
|
||||
void CompilerUtils::revertWithError(
|
||||
@ -112,19 +112,19 @@ void CompilerUtils::revertWithError(
|
||||
{
|
||||
fetchFreeMemoryPointer();
|
||||
m_context << util::selectorFromSignatureU256(_signature);
|
||||
m_context << Instruction::DUP2 << Instruction::MSTORE;
|
||||
m_context << u256(4) << Instruction::ADD;
|
||||
m_context << InternalInstruction::DUP2 << InternalInstruction::MSTORE;
|
||||
m_context << u256(4) << InternalInstruction::ADD;
|
||||
// Stack: <arguments...> <mem pos of encoding start>
|
||||
abiEncode(_argumentTypes, _parameterTypes);
|
||||
toSizeAfterFreeMemoryPointer();
|
||||
m_context << Instruction::REVERT;
|
||||
m_context << InternalInstruction::REVERT;
|
||||
}
|
||||
|
||||
void CompilerUtils::returnDataToArray()
|
||||
{
|
||||
if (m_context.evmVersion().supportsReturndata())
|
||||
{
|
||||
m_context << Instruction::RETURNDATASIZE;
|
||||
m_context << InternalInstruction::RETURNDATASIZE;
|
||||
m_context.appendInlineAssembly(R"({
|
||||
switch v case 0 {
|
||||
v := 0x60
|
||||
@ -142,7 +142,7 @@ void CompilerUtils::returnDataToArray()
|
||||
|
||||
void CompilerUtils::accessCalldataTail(Type const& _type)
|
||||
{
|
||||
m_context << Instruction::SWAP1;
|
||||
m_context << InternalInstruction::SWAP1;
|
||||
m_context.callYulFunction(
|
||||
m_context.utilFunctions().accessCalldataTailFunction(_type),
|
||||
2,
|
||||
@ -170,7 +170,7 @@ void CompilerUtils::loadFromMemoryDynamic(
|
||||
)
|
||||
{
|
||||
if (_keepUpdatedMemoryOffset)
|
||||
m_context << Instruction::DUP1;
|
||||
m_context << InternalInstruction::DUP1;
|
||||
|
||||
if (auto arrayType = dynamic_cast<ArrayType const*>(&_type))
|
||||
{
|
||||
@ -178,7 +178,7 @@ void CompilerUtils::loadFromMemoryDynamic(
|
||||
solAssert(!_fromCalldata);
|
||||
solAssert(_padToWordBoundaries);
|
||||
if (_keepUpdatedMemoryOffset)
|
||||
m_context << arrayType->memoryDataSize() << Instruction::ADD;
|
||||
m_context << arrayType->memoryDataSize() << InternalInstruction::ADD;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -187,7 +187,7 @@ void CompilerUtils::loadFromMemoryDynamic(
|
||||
{
|
||||
// update memory counter
|
||||
moveToStackTop(_type.sizeOnStack());
|
||||
m_context << u256(numBytes) << Instruction::ADD;
|
||||
m_context << u256(numBytes) << InternalInstruction::ADD;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -196,7 +196,7 @@ void CompilerUtils::storeInMemory(unsigned _offset)
|
||||
{
|
||||
unsigned numBytes = prepareMemoryStore(*TypeProvider::uint256(), true);
|
||||
if (numBytes > 0)
|
||||
m_context << u256(_offset) << Instruction::MSTORE;
|
||||
m_context << u256(_offset) << InternalInstruction::MSTORE;
|
||||
}
|
||||
|
||||
void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBoundaries, bool _cleanup)
|
||||
@ -212,13 +212,13 @@ void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBound
|
||||
}
|
||||
else if (auto str = dynamic_cast<StringLiteralType const*>(&_type))
|
||||
{
|
||||
m_context << Instruction::DUP1;
|
||||
m_context << InternalInstruction::DUP1;
|
||||
storeStringData(bytesConstRef(str->value()));
|
||||
if (_padToWordBoundaries)
|
||||
m_context << u256(max<size_t>(32, ((str->value().size() + 31) / 32) * 32));
|
||||
else
|
||||
m_context << u256(str->value().size());
|
||||
m_context << Instruction::ADD;
|
||||
m_context << InternalInstruction::ADD;
|
||||
}
|
||||
else if (
|
||||
_type.category() == Type::Category::Function &&
|
||||
@ -226,14 +226,14 @@ void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBound
|
||||
)
|
||||
{
|
||||
combineExternalFunctionType(true);
|
||||
m_context << Instruction::DUP2 << Instruction::MSTORE;
|
||||
m_context << u256(_padToWordBoundaries ? 32 : 24) << Instruction::ADD;
|
||||
m_context << InternalInstruction::DUP2 << InternalInstruction::MSTORE;
|
||||
m_context << u256(_padToWordBoundaries ? 32 : 24) << InternalInstruction::ADD;
|
||||
}
|
||||
else if (_type.isValueType())
|
||||
{
|
||||
unsigned numBytes = prepareMemoryStore(_type, _padToWordBoundaries, _cleanup);
|
||||
m_context << Instruction::DUP2 << Instruction::MSTORE;
|
||||
m_context << u256(numBytes) << Instruction::ADD;
|
||||
m_context << InternalInstruction::DUP2 << InternalInstruction::MSTORE;
|
||||
m_context << u256(numBytes) << InternalInstruction::ADD;
|
||||
}
|
||||
else // Should never happen
|
||||
{
|
||||
@ -268,12 +268,12 @@ void CompilerUtils::abiDecode(TypePointers const& _typeParameters, bool _fromMem
|
||||
templ("revertString", m_context.revertReasonIfDebug("Calldata too short"));
|
||||
m_context.appendInlineAssembly(templ.render(), {"len"});
|
||||
|
||||
m_context << Instruction::DUP2 << Instruction::ADD;
|
||||
m_context << Instruction::SWAP1;
|
||||
m_context << InternalInstruction::DUP2 << InternalInstruction::ADD;
|
||||
m_context << InternalInstruction::SWAP1;
|
||||
/// Stack: <input_end> <source_offset>
|
||||
|
||||
// Retain the offset pointer as base_offset, the point from which the data offsets are computed.
|
||||
m_context << Instruction::DUP1;
|
||||
m_context << InternalInstruction::DUP1;
|
||||
for (Type const* parameterType: _typeParameters)
|
||||
{
|
||||
// stack: v1 v2 ... v(k-1) input_end base_offset current_offset
|
||||
@ -295,14 +295,14 @@ void CompilerUtils::abiDecode(TypePointers const& _typeParameters, bool _fromMem
|
||||
if (arrayType.isDynamicallySized())
|
||||
{
|
||||
// compute data pointer
|
||||
m_context << Instruction::DUP1 << Instruction::MLOAD;
|
||||
m_context << InternalInstruction::DUP1 << InternalInstruction::MLOAD;
|
||||
// stack: v1 v2 ... v(k-1) input_end base_offset current_offset data_offset
|
||||
|
||||
fetchFreeMemoryPointer();
|
||||
// stack: v1 v2 ... v(k-1) input_end base_offset current_offset data_offset dstmem
|
||||
moveIntoStack(4);
|
||||
// stack: v1 v2 ... v(k-1) dstmem input_end base_offset current_offset data_offset
|
||||
m_context << Instruction::DUP5;
|
||||
m_context << InternalInstruction::DUP5;
|
||||
// stack: v1 v2 ... v(k-1) dstmem input_end base_offset current_offset data_offset dstmem
|
||||
|
||||
// Check that the data pointer is valid and that length times
|
||||
@ -327,19 +327,19 @@ void CompilerUtils::abiDecode(TypePointers const& _typeParameters, bool _fromMem
|
||||
templ("revertStringLength", m_context.revertReasonIfDebug("ABI memory decoding: invalid data length"));
|
||||
m_context.appendInlineAssembly(templ.render(), {"input_end", "base_offset", "offset", "ptr", "dst"});
|
||||
// stack: v1 v2 ... v(k-1) dstmem input_end base_offset current_offset data_ptr dstdata
|
||||
m_context << Instruction::SWAP1;
|
||||
m_context << InternalInstruction::SWAP1;
|
||||
// stack: v1 v2 ... v(k-1) dstmem input_end base_offset current_offset dstdata data_ptr
|
||||
ArrayUtils(m_context).copyArrayToMemory(arrayType, true);
|
||||
// stack: v1 v2 ... v(k-1) dstmem input_end base_offset current_offset mem_end
|
||||
storeFreeMemoryPointer();
|
||||
m_context << u256(0x20) << Instruction::ADD;
|
||||
m_context << u256(0x20) << InternalInstruction::ADD;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Size has already been checked for this one.
|
||||
moveIntoStack(2);
|
||||
m_context << Instruction::DUP3;
|
||||
m_context << u256(arrayType.calldataHeadSize()) << Instruction::ADD;
|
||||
m_context << InternalInstruction::DUP3;
|
||||
m_context << u256(arrayType.calldataHeadSize()) << InternalInstruction::ADD;
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -350,7 +350,7 @@ void CompilerUtils::abiDecode(TypePointers const& _typeParameters, bool _fromMem
|
||||
{
|
||||
// put on stack: data_pointer length
|
||||
loadFromMemoryDynamic(*TypeProvider::uint256(), !_fromMemory);
|
||||
m_context << Instruction::SWAP1;
|
||||
m_context << InternalInstruction::SWAP1;
|
||||
// stack: input_end base_offset next_pointer data_offset
|
||||
m_context.appendInlineAssembly(Whiskers(R"({
|
||||
if gt(data_offset, 0x100000000) { <revertString> }
|
||||
@ -358,7 +358,7 @@ void CompilerUtils::abiDecode(TypePointers const& _typeParameters, bool _fromMem
|
||||
// TODO add test
|
||||
("revertString", m_context.revertReasonIfDebug("ABI calldata decoding: invalid data offset"))
|
||||
.render(), {"data_offset"});
|
||||
m_context << Instruction::DUP3 << Instruction::ADD;
|
||||
m_context << InternalInstruction::DUP3 << InternalInstruction::ADD;
|
||||
// stack: input_end base_offset next_pointer array_head_ptr
|
||||
m_context.appendInlineAssembly(Whiskers(R"({
|
||||
if gt(add(array_head_ptr, 0x20), input_end) { <revertString> }
|
||||
@ -369,7 +369,7 @@ void CompilerUtils::abiDecode(TypePointers const& _typeParameters, bool _fromMem
|
||||
// retrieve length
|
||||
loadFromMemoryDynamic(*TypeProvider::uint256(), !_fromMemory, true);
|
||||
// stack: input_end base_offset next_pointer array_length data_pointer
|
||||
m_context << Instruction::SWAP2;
|
||||
m_context << InternalInstruction::SWAP2;
|
||||
// stack: input_end base_offset data_pointer array_length next_pointer
|
||||
m_context.appendInlineAssembly(Whiskers(R"({
|
||||
if or(
|
||||
@ -384,8 +384,8 @@ void CompilerUtils::abiDecode(TypePointers const& _typeParameters, bool _fromMem
|
||||
{
|
||||
// size has already been checked
|
||||
// stack: input_end base_offset data_offset
|
||||
m_context << Instruction::DUP1;
|
||||
m_context << u256(calldataType->calldataHeadSize()) << Instruction::ADD;
|
||||
m_context << InternalInstruction::DUP1;
|
||||
m_context << u256(calldataType->calldataHeadSize()) << InternalInstruction::ADD;
|
||||
}
|
||||
if (arrayType.location() == DataLocation::Memory)
|
||||
{
|
||||
@ -400,10 +400,10 @@ void CompilerUtils::abiDecode(TypePointers const& _typeParameters, bool _fromMem
|
||||
// move input_end up
|
||||
// stack: input_end base_offset calldata_ref [length] next_calldata
|
||||
moveToStackTop(2 + arrayType.sizeOnStack());
|
||||
m_context << Instruction::SWAP1;
|
||||
m_context << InternalInstruction::SWAP1;
|
||||
// stack: base_offset calldata_ref [length] input_end next_calldata
|
||||
moveToStackTop(2 + arrayType.sizeOnStack());
|
||||
m_context << Instruction::SWAP1;
|
||||
m_context << InternalInstruction::SWAP1;
|
||||
// stack: calldata_ref [length] input_end base_offset next_calldata
|
||||
}
|
||||
}
|
||||
@ -460,7 +460,7 @@ void CompilerUtils::encodeToMemory(
|
||||
// of the nth dynamic parameter, which is filled once the dynamic parts are processed.
|
||||
|
||||
// store memory start pointer
|
||||
m_context << Instruction::DUP1;
|
||||
m_context << InternalInstruction::DUP1;
|
||||
|
||||
unsigned argSize = CompilerUtils::sizeOnStack(_givenTypes);
|
||||
unsigned stackPos = 0; // advances through the argument values
|
||||
@ -472,7 +472,7 @@ void CompilerUtils::encodeToMemory(
|
||||
if (targetType->isDynamicallySized() && !_copyDynamicDataInPlace)
|
||||
{
|
||||
// leave end_of_mem as dyn head pointer
|
||||
m_context << Instruction::DUP1 << u256(32) << Instruction::ADD;
|
||||
m_context << InternalInstruction::DUP1 << u256(32) << InternalInstruction::ADD;
|
||||
dynPointers++;
|
||||
assertThrow(
|
||||
(argSize + dynPointers) < 16,
|
||||
@ -540,10 +540,10 @@ void CompilerUtils::encodeToMemory(
|
||||
StackTooDeepError,
|
||||
util::stackTooDeepString
|
||||
);
|
||||
m_context << dupInstruction(2 + dynPointers) << Instruction::DUP2;
|
||||
m_context << Instruction::SUB;
|
||||
m_context << dupInstruction(2 + dynPointers) << InternalInstruction::DUP2;
|
||||
m_context << InternalInstruction::SUB;
|
||||
m_context << dupInstruction(2 + dynPointers - thisDynPointer);
|
||||
m_context << Instruction::MSTORE;
|
||||
m_context << InternalInstruction::MSTORE;
|
||||
// stack: ... <end_of_mem>
|
||||
if (_givenTypes[i]->category() == Type::Category::StringLiteral)
|
||||
{
|
||||
@ -589,7 +589,7 @@ void CompilerUtils::encodeToMemory(
|
||||
storeInMemoryDynamic(*TypeProvider::uint256(), true);
|
||||
// stack: ... <end_of_mem> <value...> <end_of_mem''>
|
||||
// copy the new memory pointer
|
||||
m_context << swapInstruction(arrayType->sizeOnStack() + 1) << Instruction::POP;
|
||||
m_context << swapInstruction(arrayType->sizeOnStack() + 1) << InternalInstruction::POP;
|
||||
// stack: ... <end_of_mem''> <value...>
|
||||
// copy data part
|
||||
ArrayUtils(m_context).copyArrayToMemory(*arrayType, _padToWordBoundaries);
|
||||
@ -628,8 +628,8 @@ void CompilerUtils::abiEncodeV2(
|
||||
void CompilerUtils::abiDecodeV2(TypePointers const& _parameterTypes, bool _fromMemory)
|
||||
{
|
||||
// stack: <source_offset> <length> [stack top]
|
||||
m_context << Instruction::DUP2 << Instruction::ADD;
|
||||
m_context << Instruction::SWAP1;
|
||||
m_context << InternalInstruction::DUP2 << InternalInstruction::ADD;
|
||||
m_context << InternalInstruction::SWAP1;
|
||||
// stack: <end> <start>
|
||||
string decoderName = m_context.abiFunctions().tupleDecoder(_parameterTypes, _fromMemory);
|
||||
m_context.callYulFunction(decoderName, 2, sizeOnStack(_parameterTypes));
|
||||
@ -655,12 +655,12 @@ void CompilerUtils::zeroInitialiseMemoryArray(ArrayType const& _type)
|
||||
m_context << repeat;
|
||||
pushZeroValue(*_type.baseType());
|
||||
storeInMemoryDynamic(*_type.baseType());
|
||||
m_context << Instruction::SWAP1 << u256(1) << Instruction::SWAP1;
|
||||
m_context << Instruction::SUB << Instruction::SWAP1;
|
||||
m_context << Instruction::DUP2;
|
||||
m_context << InternalInstruction::SWAP1 << u256(1) << InternalInstruction::SWAP1;
|
||||
m_context << InternalInstruction::SUB << InternalInstruction::SWAP1;
|
||||
m_context << InternalInstruction::DUP2;
|
||||
m_context.appendConditionalJumpTo(repeat);
|
||||
}
|
||||
m_context << Instruction::SWAP1 << Instruction::POP;
|
||||
m_context << InternalInstruction::SWAP1 << InternalInstruction::POP;
|
||||
}
|
||||
|
||||
void CompilerUtils::memoryCopy32()
|
||||
@ -676,7 +676,7 @@ void CompilerUtils::memoryCopy32()
|
||||
)",
|
||||
{ "len", "dst", "src" }
|
||||
);
|
||||
m_context << Instruction::POP << Instruction::POP << Instruction::POP;
|
||||
m_context << InternalInstruction::POP << InternalInstruction::POP << InternalInstruction::POP;
|
||||
}
|
||||
|
||||
void CompilerUtils::memoryCopy()
|
||||
@ -705,7 +705,7 @@ void CompilerUtils::memoryCopy()
|
||||
)",
|
||||
{ "len", "dst", "src" }
|
||||
);
|
||||
m_context << Instruction::POP << Instruction::POP << Instruction::POP;
|
||||
m_context << InternalInstruction::POP << InternalInstruction::POP << InternalInstruction::POP;
|
||||
}
|
||||
|
||||
void CompilerUtils::splitExternalFunctionType(bool _leftAligned)
|
||||
@ -714,29 +714,29 @@ void CompilerUtils::splitExternalFunctionType(bool _leftAligned)
|
||||
// address (right aligned), function identifier (right aligned)
|
||||
if (_leftAligned)
|
||||
{
|
||||
m_context << Instruction::DUP1;
|
||||
m_context << InternalInstruction::DUP1;
|
||||
rightShiftNumberOnStack(64 + 32);
|
||||
// <input> <address>
|
||||
m_context << Instruction::SWAP1;
|
||||
m_context << InternalInstruction::SWAP1;
|
||||
rightShiftNumberOnStack(64);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_context << Instruction::DUP1;
|
||||
m_context << InternalInstruction::DUP1;
|
||||
rightShiftNumberOnStack(32);
|
||||
m_context << ((u256(1) << 160) - 1) << Instruction::AND << Instruction::SWAP1;
|
||||
m_context << ((u256(1) << 160) - 1) << InternalInstruction::AND << InternalInstruction::SWAP1;
|
||||
}
|
||||
m_context << u256(0xffffffffUL) << Instruction::AND;
|
||||
m_context << u256(0xffffffffUL) << InternalInstruction::AND;
|
||||
}
|
||||
|
||||
void CompilerUtils::combineExternalFunctionType(bool _leftAligned)
|
||||
{
|
||||
// <address> <function_id>
|
||||
m_context << u256(0xffffffffUL) << Instruction::AND << Instruction::SWAP1;
|
||||
m_context << u256(0xffffffffUL) << InternalInstruction::AND << InternalInstruction::SWAP1;
|
||||
if (!_leftAligned)
|
||||
m_context << ((u256(1) << 160) - 1) << Instruction::AND;
|
||||
m_context << ((u256(1) << 160) - 1) << InternalInstruction::AND;
|
||||
leftShiftNumberOnStack(32);
|
||||
m_context << Instruction::OR;
|
||||
m_context << InternalInstruction::OR;
|
||||
if (_leftAligned)
|
||||
leftShiftNumberOnStack(64);
|
||||
}
|
||||
@ -752,7 +752,7 @@ void CompilerUtils::pushCombinedFunctionEntryLabel(Declaration const& _function,
|
||||
if (_runtimeOnly)
|
||||
m_context <<
|
||||
rtc->functionEntryLabel(_function).toSubAssemblyTag(m_context.runtimeSub()) <<
|
||||
Instruction::OR;
|
||||
InternalInstruction::OR;
|
||||
}
|
||||
}
|
||||
|
||||
@ -839,12 +839,12 @@ void CompilerUtils::convertType(
|
||||
solAssert(targetTypeCategory == Type::Category::FixedBytes, "Invalid type conversion requested.");
|
||||
FixedBytesType const& targetType = dynamic_cast<FixedBytesType const&>(_targetType);
|
||||
if (typeOnStack.numBytes() == 0 || targetType.numBytes() == 0)
|
||||
m_context << Instruction::POP << u256(0);
|
||||
m_context << InternalInstruction::POP << u256(0);
|
||||
else if (targetType.numBytes() > typeOnStack.numBytes() || _cleanupNeeded)
|
||||
{
|
||||
unsigned bytes = min(typeOnStack.numBytes(), targetType.numBytes());
|
||||
m_context << ((u256(1) << (256 - bytes * 8)) - 1);
|
||||
m_context << Instruction::NOT << Instruction::AND;
|
||||
m_context << InternalInstruction::NOT << InternalInstruction::AND;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -855,7 +855,7 @@ void CompilerUtils::convertType(
|
||||
{
|
||||
EnumType const& enumType = dynamic_cast<decltype(enumType)>(_typeOnStack);
|
||||
solAssert(enumType.numberOfMembers() > 0, "empty enum should have caused a parser error.");
|
||||
m_context << u256(enumType.numberOfMembers() - 1) << Instruction::DUP2 << Instruction::GT;
|
||||
m_context << u256(enumType.numberOfMembers() - 1) << InternalInstruction::DUP2 << InternalInstruction::GT;
|
||||
if (_asPartOfArgumentDecoding)
|
||||
m_context.appendConditionalRevert(false, "Enum out of range");
|
||||
else
|
||||
@ -897,7 +897,7 @@ void CompilerUtils::convertType(
|
||||
convertType(_typeOnStack, *_typeOnStack.mobileType(), true);
|
||||
EnumType const& enumType = dynamic_cast<decltype(enumType)>(_targetType);
|
||||
solAssert(enumType.numberOfMembers() > 0, "empty enum should have caused a parser error.");
|
||||
m_context << u256(enumType.numberOfMembers() - 1) << Instruction::DUP2 << Instruction::GT;
|
||||
m_context << u256(enumType.numberOfMembers() - 1) << InternalInstruction::DUP2 << InternalInstruction::GT;
|
||||
m_context.appendConditionalPanic(util::PanicCode::EnumConversionError);
|
||||
enumOverflowCheckPending = false;
|
||||
}
|
||||
@ -951,7 +951,7 @@ void CompilerUtils::convertType(
|
||||
if (targetType.numBits() < 256)
|
||||
m_context
|
||||
<< ((u256(1) << targetType.numBits()) - 1)
|
||||
<< Instruction::AND;
|
||||
<< InternalInstruction::AND;
|
||||
chopSignBitsPending = false;
|
||||
}
|
||||
}
|
||||
@ -975,7 +975,7 @@ void CompilerUtils::convertType(
|
||||
size_t storageSize = 32 + ((data.size() + 31) / 32) * 32;
|
||||
allocateMemory(storageSize);
|
||||
// stack: mempos
|
||||
m_context << Instruction::DUP1 << u256(data.size());
|
||||
m_context << InternalInstruction::DUP1 << u256(data.size());
|
||||
storeInMemoryDynamic(*TypeProvider::uint256());
|
||||
// stack: mempos datapos
|
||||
storeStringData(data);
|
||||
@ -1001,7 +1001,7 @@ void CompilerUtils::convertType(
|
||||
bool fromCalldata = typeOnStack.dataStoredIn(DataLocation::CallData);
|
||||
solAssert(typeOnStack.sizeOnStack() == (fromCalldata ? 2 : 1));
|
||||
if (fromCalldata)
|
||||
m_context << Instruction::SWAP1;
|
||||
m_context << InternalInstruction::SWAP1;
|
||||
|
||||
m_context.callYulFunction(
|
||||
m_context.utilFunctions().bytesToFixedBytesConversionFunction(
|
||||
@ -1039,7 +1039,7 @@ void CompilerUtils::convertType(
|
||||
// stack: offset length(optional in case of dynamically sized array)
|
||||
solAssert(typeOnStack.sizeOnStack() == (typeOnStack.isDynamicallySized() ? 2 : 1));
|
||||
if (typeOnStack.isDynamicallySized())
|
||||
m_context << Instruction::SWAP1;
|
||||
m_context << InternalInstruction::SWAP1;
|
||||
|
||||
m_context.callYulFunction(
|
||||
m_context.utilFunctions().conversionFunction(typeOnStack, targetType),
|
||||
@ -1055,18 +1055,18 @@ void CompilerUtils::convertType(
|
||||
|
||||
// allocate memory
|
||||
// stack: <source ref> (variably sized) <length>
|
||||
m_context << Instruction::DUP1;
|
||||
m_context << InternalInstruction::DUP1;
|
||||
ArrayUtils(m_context).convertLengthToSize(targetType, true);
|
||||
// stack: <source ref> (variably sized) <length> <size>
|
||||
if (targetType.isDynamicallySized())
|
||||
m_context << u256(0x20) << Instruction::ADD;
|
||||
m_context << u256(0x20) << InternalInstruction::ADD;
|
||||
allocateMemory();
|
||||
// stack: <source ref> (variably sized) <length> <mem start>
|
||||
m_context << Instruction::DUP1;
|
||||
m_context << InternalInstruction::DUP1;
|
||||
moveIntoStack(2 + stackSize);
|
||||
if (targetType.isDynamicallySized())
|
||||
{
|
||||
m_context << Instruction::DUP2;
|
||||
m_context << InternalInstruction::DUP2;
|
||||
storeInMemoryDynamic(*TypeProvider::uint256());
|
||||
}
|
||||
// stack: <mem start> <source ref> (variably sized) <length> <mem data pos>
|
||||
@ -1077,12 +1077,12 @@ void CompilerUtils::convertType(
|
||||
}
|
||||
else
|
||||
{
|
||||
m_context << u256(0) << Instruction::SWAP1;
|
||||
m_context << u256(0) << InternalInstruction::SWAP1;
|
||||
// stack: <mem start> <source ref> (variably sized) <length> <counter> <mem data pos>
|
||||
auto repeat = m_context.newTag();
|
||||
m_context << repeat;
|
||||
m_context << Instruction::DUP3 << Instruction::DUP3;
|
||||
m_context << Instruction::LT << Instruction::ISZERO;
|
||||
m_context << InternalInstruction::DUP3 << InternalInstruction::DUP3;
|
||||
m_context << InternalInstruction::LT << InternalInstruction::ISZERO;
|
||||
auto loopEnd = m_context.appendConditionalJump();
|
||||
copyToStackTop(3 + stackSize, stackSize);
|
||||
copyToStackTop(2 + stackSize, 1);
|
||||
@ -1091,11 +1091,11 @@ void CompilerUtils::convertType(
|
||||
StorageItem(m_context, *typeOnStack.baseType()).retrieveValue(SourceLocation(), true);
|
||||
convertType(*typeOnStack.baseType(), *targetType.baseType(), _cleanupNeeded);
|
||||
storeInMemoryDynamic(*targetType.baseType(), true);
|
||||
m_context << Instruction::SWAP1 << u256(1) << Instruction::ADD;
|
||||
m_context << Instruction::SWAP1;
|
||||
m_context << InternalInstruction::SWAP1 << u256(1) << InternalInstruction::ADD;
|
||||
m_context << InternalInstruction::SWAP1;
|
||||
m_context.appendJumpTo(repeat);
|
||||
m_context << loopEnd;
|
||||
m_context << Instruction::POP;
|
||||
m_context << InternalInstruction::POP;
|
||||
}
|
||||
// stack: <mem start> <source ref> (variably sized) <length> <mem data pos updated>
|
||||
popStackSlots(2 + stackSize);
|
||||
@ -1127,7 +1127,7 @@ void CompilerUtils::convertType(
|
||||
solAssert(typeOnStack.dataStoredIn(DataLocation::CallData));
|
||||
solAssert(typeOnStack.sizeOnStack() == 2);
|
||||
|
||||
m_context << Instruction::SWAP1;
|
||||
m_context << InternalInstruction::SWAP1;
|
||||
m_context.callYulFunction(
|
||||
m_context.utilFunctions().bytesToFixedBytesConversionFunction(
|
||||
typeOnStack.arrayType(),
|
||||
@ -1181,13 +1181,13 @@ void CompilerUtils::convertType(
|
||||
CompilerUtils utils(_context);
|
||||
// stack: <source ref>
|
||||
utils.allocateMemory(typeOnStack->memoryDataSize());
|
||||
_context << Instruction::SWAP1 << Instruction::DUP2;
|
||||
_context << InternalInstruction::SWAP1 << InternalInstruction::DUP2;
|
||||
// stack: <memory ptr> <source ref> <memory ptr>
|
||||
for (auto const& member: typeOnStack->members(nullptr))
|
||||
{
|
||||
solAssert(!member.type->containsNestedMapping());
|
||||
pair<u256, unsigned> const& offsets = typeOnStack->storageOffsetsOfMember(member.name);
|
||||
_context << offsets.first << Instruction::DUP3 << Instruction::ADD;
|
||||
_context << offsets.first << InternalInstruction::DUP3 << InternalInstruction::ADD;
|
||||
_context << u256(offsets.second);
|
||||
StorageItem(_context, *member.type).retrieveValue(SourceLocation(), true);
|
||||
Type const* targetMemberType = targetType->memberType(member.name);
|
||||
@ -1195,7 +1195,7 @@ void CompilerUtils::convertType(
|
||||
utils.convertType(*member.type, *targetMemberType, true);
|
||||
utils.storeInMemoryDynamic(*targetMemberType, true);
|
||||
}
|
||||
_context << Instruction::POP << Instruction::POP;
|
||||
_context << InternalInstruction::POP << InternalInstruction::POP;
|
||||
};
|
||||
if (typeOnStack.recursive())
|
||||
m_context.callLowLevelFunction(
|
||||
@ -1221,9 +1221,9 @@ void CompilerUtils::convertType(
|
||||
}
|
||||
else
|
||||
{
|
||||
m_context << Instruction::DUP1;
|
||||
m_context << Instruction::CALLDATASIZE;
|
||||
m_context << Instruction::SUB;
|
||||
m_context << InternalInstruction::DUP1;
|
||||
m_context << InternalInstruction::CALLDATASIZE;
|
||||
m_context << InternalInstruction::SUB;
|
||||
abiDecode({&targetType}, false);
|
||||
}
|
||||
break;
|
||||
@ -1271,12 +1271,12 @@ void CompilerUtils::convertType(
|
||||
for (unsigned j = 0; j < min(sourceSize, targetSize); ++j)
|
||||
m_context <<
|
||||
swapInstruction(depth + targetSize - sourceSize) <<
|
||||
Instruction::POP;
|
||||
InternalInstruction::POP;
|
||||
// Value shrank
|
||||
for (unsigned j = targetSize; j < sourceSize; ++j)
|
||||
{
|
||||
moveToStackTop(depth + targetSize - sourceSize, 1);
|
||||
m_context << Instruction::POP;
|
||||
m_context << InternalInstruction::POP;
|
||||
}
|
||||
// Value grew
|
||||
if (targetSize > sourceSize)
|
||||
@ -1290,7 +1290,7 @@ void CompilerUtils::convertType(
|
||||
case Type::Category::Bool:
|
||||
solAssert(_targetType == _typeOnStack, "Invalid conversion for bool.");
|
||||
if (_cleanupNeeded)
|
||||
m_context << Instruction::ISZERO << Instruction::ISZERO;
|
||||
m_context << InternalInstruction::ISZERO << InternalInstruction::ISZERO;
|
||||
break;
|
||||
default:
|
||||
// we used to allow conversions from function to address
|
||||
@ -1314,7 +1314,7 @@ void CompilerUtils::convertType(
|
||||
if (_cleanupNeeded && _targetType.canBeStored() && _targetType.storageBytes() < 32)
|
||||
m_context
|
||||
<< ((u256(1) << (8 * _targetType.storageBytes())) - 1)
|
||||
<< Instruction::AND;
|
||||
<< InternalInstruction::AND;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1337,7 +1337,7 @@ void CompilerUtils::pushZeroValue(Type const& _type)
|
||||
m_context << runCon->lowLevelFunctionTag("$invalidFunction", 0, 0, [](CompilerContext& _context) {
|
||||
_context.appendPanic(util::PanicCode::InvalidInternalFunction);
|
||||
}).toSubAssemblyTag(m_context.runtimeSub());
|
||||
m_context << Instruction::OR;
|
||||
m_context << InternalInstruction::OR;
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -1352,7 +1352,7 @@ void CompilerUtils::pushZeroValue(Type const& _type)
|
||||
if (referenceType->location() == DataLocation::CallData)
|
||||
{
|
||||
solAssert(referenceType->sizeOnStack() == 1 || referenceType->sizeOnStack() == 2);
|
||||
m_context << Instruction::CALLDATASIZE;
|
||||
m_context << InternalInstruction::CALLDATASIZE;
|
||||
if (referenceType->sizeOnStack() == 2)
|
||||
m_context << 0;
|
||||
return;
|
||||
@ -1376,7 +1376,7 @@ void CompilerUtils::pushZeroValue(Type const& _type)
|
||||
CompilerUtils utils(_context);
|
||||
|
||||
utils.allocateMemory(max<u256>(32u, type->memoryDataSize()));
|
||||
_context << Instruction::DUP1;
|
||||
_context << InternalInstruction::DUP1;
|
||||
|
||||
if (auto structType = dynamic_cast<StructType const*>(type))
|
||||
for (auto const& member: structType->members(nullptr))
|
||||
@ -1389,7 +1389,7 @@ void CompilerUtils::pushZeroValue(Type const& _type)
|
||||
solAssert(!arrayType->isDynamicallySized());
|
||||
if (arrayType->length() > 0)
|
||||
{
|
||||
_context << arrayType->length() << Instruction::SWAP1;
|
||||
_context << arrayType->length() << InternalInstruction::SWAP1;
|
||||
// stack: items_to_do memory_pos
|
||||
utils.zeroInitialiseMemoryArray(*arrayType);
|
||||
// stack: updated_memory_pos
|
||||
@ -1399,7 +1399,7 @@ void CompilerUtils::pushZeroValue(Type const& _type)
|
||||
solAssert(false, "Requested initialisation for unknown type: " + type->toString());
|
||||
|
||||
// remove the updated memory pointer
|
||||
_context << Instruction::POP;
|
||||
_context << InternalInstruction::POP;
|
||||
}
|
||||
);
|
||||
}
|
||||
@ -1422,7 +1422,7 @@ void CompilerUtils::moveToStackVariable(VariableDeclaration const& _variable)
|
||||
util::errinfo_comment(util::stackTooDeepString)
|
||||
);
|
||||
for (unsigned i = 0; i < size; ++i)
|
||||
m_context << swapInstruction(stackPosition - size + 1) << Instruction::POP;
|
||||
m_context << swapInstruction(stackPosition - size + 1) << InternalInstruction::POP;
|
||||
}
|
||||
|
||||
void CompilerUtils::copyToStackTop(unsigned _stackDepth, unsigned _itemSize)
|
||||
@ -1481,7 +1481,7 @@ void CompilerUtils::popStackElement(Type const& _type)
|
||||
void CompilerUtils::popStackSlots(size_t _amount)
|
||||
{
|
||||
for (size_t i = 0; i < _amount; ++i)
|
||||
m_context << Instruction::POP;
|
||||
m_context << InternalInstruction::POP;
|
||||
}
|
||||
|
||||
void CompilerUtils::popAndJump(unsigned _toHeight, evmasm::AssemblyItem const& _jumpTo)
|
||||
@ -1504,7 +1504,7 @@ unsigned CompilerUtils::sizeOnStack(vector<Type const*> const& _variableTypes)
|
||||
void CompilerUtils::computeHashStatic()
|
||||
{
|
||||
storeInMemory(0);
|
||||
m_context << u256(32) << u256(0) << Instruction::KECCAK256;
|
||||
m_context << u256(32) << u256(0) << InternalInstruction::KECCAK256;
|
||||
}
|
||||
|
||||
void CompilerUtils::copyContractCodeToMemory(ContractDefinition const& contract, bool _creation)
|
||||
@ -1523,9 +1523,9 @@ void CompilerUtils::copyContractCodeToMemory(ContractDefinition const& contract,
|
||||
_context.compiledContractRuntime(contract);
|
||||
// pushes size
|
||||
auto subroutine = _context.addSubroutine(assembly);
|
||||
_context << Instruction::DUP1 << subroutine;
|
||||
_context << Instruction::DUP4 << Instruction::CODECOPY;
|
||||
_context << Instruction::ADD;
|
||||
_context << InternalInstruction::DUP1 << subroutine;
|
||||
_context << InternalInstruction::DUP4 << InternalInstruction::CODECOPY;
|
||||
_context << InternalInstruction::ADD;
|
||||
}
|
||||
);
|
||||
}
|
||||
@ -1541,14 +1541,14 @@ void CompilerUtils::storeStringData(bytesConstRef _data)
|
||||
m_context << u256(h256(_data.cropped(i), h256::AlignLeft));
|
||||
storeInMemoryDynamic(*TypeProvider::uint256());
|
||||
}
|
||||
m_context << Instruction::POP;
|
||||
m_context << InternalInstruction::POP;
|
||||
}
|
||||
else
|
||||
{
|
||||
// stack: mempos mempos_data
|
||||
m_context.appendData(_data.toBytes());
|
||||
m_context << u256(_data.size()) << Instruction::SWAP2;
|
||||
m_context << Instruction::CODECOPY;
|
||||
m_context << u256(_data.size()) << InternalInstruction::SWAP2;
|
||||
m_context << InternalInstruction::CODECOPY;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1566,11 +1566,11 @@ unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCallda
|
||||
isExternalFunctionType = true;
|
||||
if (numBytes == 0)
|
||||
{
|
||||
m_context << Instruction::POP << u256(0);
|
||||
m_context << InternalInstruction::POP << u256(0);
|
||||
return numBytes;
|
||||
}
|
||||
solAssert(numBytes <= 32, "Static memory load of more than 32 bytes requested.");
|
||||
m_context << (_fromCalldata ? Instruction::CALLDATALOAD : Instruction::MLOAD);
|
||||
m_context << (_fromCalldata ? InternalInstruction::CALLDATALOAD : InternalInstruction::MLOAD);
|
||||
bool cleanupNeeded = true;
|
||||
if (isExternalFunctionType)
|
||||
splitExternalFunctionType(true);
|
||||
@ -1599,18 +1599,18 @@ void CompilerUtils::cleanHigherOrderBits(IntegerType const& _typeOnStack)
|
||||
if (_typeOnStack.numBits() == 256)
|
||||
return;
|
||||
else if (_typeOnStack.isSigned())
|
||||
m_context << u256(_typeOnStack.numBits() / 8 - 1) << Instruction::SIGNEXTEND;
|
||||
m_context << u256(_typeOnStack.numBits() / 8 - 1) << InternalInstruction::SIGNEXTEND;
|
||||
else
|
||||
m_context << ((u256(1) << _typeOnStack.numBits()) - 1) << Instruction::AND;
|
||||
m_context << ((u256(1) << _typeOnStack.numBits()) - 1) << InternalInstruction::AND;
|
||||
}
|
||||
|
||||
void CompilerUtils::leftShiftNumberOnStack(unsigned _bits)
|
||||
{
|
||||
solAssert(_bits < 256);
|
||||
if (m_context.evmVersion().hasBitwiseShifting())
|
||||
m_context << _bits << Instruction::SHL;
|
||||
m_context << _bits << InternalInstruction::SHL;
|
||||
else
|
||||
m_context << (u256(1) << _bits) << Instruction::MUL;
|
||||
m_context << (u256(1) << _bits) << InternalInstruction::MUL;
|
||||
}
|
||||
|
||||
void CompilerUtils::rightShiftNumberOnStack(unsigned _bits)
|
||||
@ -1618,9 +1618,9 @@ void CompilerUtils::rightShiftNumberOnStack(unsigned _bits)
|
||||
solAssert(_bits < 256);
|
||||
// NOTE: If we add signed right shift, SAR rounds differently than SDIV
|
||||
if (m_context.evmVersion().hasBitwiseShifting())
|
||||
m_context << _bits << Instruction::SHR;
|
||||
m_context << _bits << InternalInstruction::SHR;
|
||||
else
|
||||
m_context << (u256(1) << _bits) << Instruction::SWAP1 << Instruction::DIV;
|
||||
m_context << (u256(1) << _bits) << InternalInstruction::SWAP1 << InternalInstruction::DIV;
|
||||
}
|
||||
|
||||
unsigned CompilerUtils::prepareMemoryStore(Type const& _type, bool _padToWords, bool _cleanup)
|
||||
|
@ -142,7 +142,7 @@ void ContractCompiler::initializeContext(
|
||||
void ContractCompiler::appendCallValueCheck()
|
||||
{
|
||||
// Throw if function is not payable but call contained ether.
|
||||
m_context << Instruction::CALLVALUE;
|
||||
m_context << InternalInstruction::CALLVALUE;
|
||||
m_context.appendConditionalRevert(false, "Ether sent to non-payable function");
|
||||
}
|
||||
|
||||
@ -201,9 +201,9 @@ size_t ContractCompiler::packIntoContractCreator(ContractDefinition const& _cont
|
||||
);
|
||||
m_context.pushSubroutineSize(m_context.runtimeSub());
|
||||
if (immutables.empty())
|
||||
m_context << Instruction::DUP1;
|
||||
m_context << InternalInstruction::DUP1;
|
||||
m_context.pushSubroutineOffset(m_context.runtimeSub());
|
||||
m_context << u256(0) << Instruction::CODECOPY;
|
||||
m_context << u256(0) << InternalInstruction::CODECOPY;
|
||||
// Assign immutable values from stack in reversed order.
|
||||
for (auto const& immutable: immutables | ranges::views::reverse)
|
||||
{
|
||||
@ -216,7 +216,7 @@ size_t ContractCompiler::packIntoContractCreator(ContractDefinition const& _cont
|
||||
}
|
||||
if (!immutables.empty())
|
||||
m_context.pushSubroutineSize(m_context.runtimeSub());
|
||||
m_context << u256(0) << Instruction::RETURN;
|
||||
m_context << u256(0) << InternalInstruction::RETURN;
|
||||
|
||||
return m_context.runtimeSub();
|
||||
}
|
||||
@ -298,13 +298,13 @@ void ContractCompiler::appendConstructor(FunctionDefinition const& _constructor)
|
||||
// which is the size of the generated code (``programSize``)
|
||||
// plus the constructor arguments added to the transaction payload.
|
||||
m_context.appendProgramSize();
|
||||
m_context << Instruction::CODESIZE << Instruction::SUB;
|
||||
m_context << InternalInstruction::CODESIZE << InternalInstruction::SUB;
|
||||
// stack: <memptr> <argument size>
|
||||
m_context << Instruction::DUP1;
|
||||
m_context << InternalInstruction::DUP1;
|
||||
m_context.appendProgramSize();
|
||||
m_context << Instruction::DUP4 << Instruction::CODECOPY;
|
||||
m_context << InternalInstruction::DUP4 << InternalInstruction::CODECOPY;
|
||||
// stack: <memptr> <argument size>
|
||||
m_context << Instruction::DUP2 << Instruction::DUP2 << Instruction::ADD;
|
||||
m_context << InternalInstruction::DUP2 << InternalInstruction::DUP2 << InternalInstruction::ADD;
|
||||
// stack: <memptr> <argument size> <mem end>
|
||||
CompilerUtils(m_context).storeFreeMemoryPointer();
|
||||
// stack: <memptr> <argument size>
|
||||
@ -318,7 +318,7 @@ void ContractCompiler::appendDelegatecallCheck()
|
||||
// Special constant that will be replaced by the address at deploy time.
|
||||
// At compilation time, this is just "PUSH20 00...000".
|
||||
m_context.appendDeployTimeAddress();
|
||||
m_context << Instruction::ADDRESS << Instruction::EQ;
|
||||
m_context << InternalInstruction::ADDRESS << InternalInstruction::EQ;
|
||||
// The result on the stack is
|
||||
// "We have not been called via DELEGATECALL".
|
||||
}
|
||||
@ -366,7 +366,7 @@ void ContractCompiler::appendInternalSelector(
|
||||
{
|
||||
size_t pivotIndex = _ids.size() / 2;
|
||||
FixedHash<4> pivot{_ids.at(pivotIndex)};
|
||||
m_context << dupInstruction(1) << u256(FixedHash<4>::Arith(pivot)) << Instruction::GT;
|
||||
m_context << dupInstruction(1) << u256(FixedHash<4>::Arith(pivot)) << InternalInstruction::GT;
|
||||
evmasm::AssemblyItem lessTag{m_context.appendConditionalJump()};
|
||||
// Here, we have funid >= pivot
|
||||
vector<FixedHash<4>> larger{_ids.begin() + static_cast<ptrdiff_t>(pivotIndex), _ids.end()};
|
||||
@ -380,7 +380,7 @@ void ContractCompiler::appendInternalSelector(
|
||||
{
|
||||
for (auto const& id: _ids)
|
||||
{
|
||||
m_context << dupInstruction(1) << u256(FixedHash<4>::Arith(id)) << Instruction::EQ;
|
||||
m_context << dupInstruction(1) << u256(FixedHash<4>::Arith(id)) << InternalInstruction::EQ;
|
||||
m_context.appendConditionalJumpTo(_entryPoints.at(id));
|
||||
}
|
||||
m_context.appendJumpTo(_notFoundTag);
|
||||
@ -439,7 +439,7 @@ void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contrac
|
||||
|
||||
// directly jump to fallback or ether receiver if the data is too short to contain a function selector
|
||||
// also guards against short data
|
||||
m_context << u256(4) << Instruction::CALLDATASIZE << Instruction::LT;
|
||||
m_context << u256(4) << InternalInstruction::CALLDATASIZE << InternalInstruction::LT;
|
||||
m_context.appendConditionalJumpTo(notFoundOrReceiveEther);
|
||||
|
||||
// retrieve the function signature hash from the calldata
|
||||
@ -467,7 +467,7 @@ void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contrac
|
||||
if (etherReceiver)
|
||||
{
|
||||
// directly jump to fallback, if there is calldata
|
||||
m_context << Instruction::CALLDATASIZE;
|
||||
m_context << InternalInstruction::CALLDATASIZE;
|
||||
m_context.appendConditionalJumpTo(notFound);
|
||||
|
||||
solAssert(!_contract.isLibrary(), "");
|
||||
@ -475,7 +475,7 @@ void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contrac
|
||||
solAssert(FunctionType(*etherReceiver).parameterTypes().empty(), "");
|
||||
solAssert(FunctionType(*etherReceiver).returnParameterTypes().empty(), "");
|
||||
etherReceiver->accept(*this);
|
||||
m_context << Instruction::STOP;
|
||||
m_context << InternalInstruction::STOP;
|
||||
}
|
||||
|
||||
m_context << notFound;
|
||||
@ -489,17 +489,17 @@ void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contrac
|
||||
m_context.setStackOffset(0);
|
||||
|
||||
if (!FunctionType(*fallback).parameterTypes().empty())
|
||||
m_context << u256(0) << Instruction::CALLDATASIZE;
|
||||
m_context << u256(0) << InternalInstruction::CALLDATASIZE;
|
||||
|
||||
fallback->accept(*this);
|
||||
|
||||
if (FunctionType(*fallback).returnParameterTypes().empty())
|
||||
m_context << Instruction::STOP;
|
||||
m_context << InternalInstruction::STOP;
|
||||
else
|
||||
{
|
||||
m_context << Instruction::DUP1 << Instruction::MLOAD << Instruction::SWAP1;
|
||||
m_context << u256(0x20) << Instruction::ADD;
|
||||
m_context << Instruction::RETURN;
|
||||
m_context << InternalInstruction::DUP1 << InternalInstruction::MLOAD << InternalInstruction::SWAP1;
|
||||
m_context << u256(0x20) << InternalInstruction::ADD;
|
||||
m_context << InternalInstruction::RETURN;
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -534,7 +534,7 @@ void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contrac
|
||||
{
|
||||
// Parameter for calldataUnpacker
|
||||
m_context << CompilerUtils::dataStartOffset;
|
||||
m_context << Instruction::DUP1 << Instruction::CALLDATASIZE << Instruction::SUB;
|
||||
m_context << InternalInstruction::DUP1 << InternalInstruction::CALLDATASIZE << InternalInstruction::SUB;
|
||||
CompilerUtils(m_context).abiDecode(functionType->parameterTypes());
|
||||
}
|
||||
m_context.appendJumpTo(
|
||||
@ -557,7 +557,7 @@ void ContractCompiler::appendReturnValuePacker(TypePointers const& _typeParamete
|
||||
{
|
||||
CompilerUtils utils(m_context);
|
||||
if (_typeParameters.empty())
|
||||
m_context << Instruction::STOP;
|
||||
m_context << InternalInstruction::STOP;
|
||||
else
|
||||
{
|
||||
utils.fetchFreeMemoryPointer();
|
||||
@ -565,7 +565,7 @@ void ContractCompiler::appendReturnValuePacker(TypePointers const& _typeParamete
|
||||
// its data to add the needed parts and we avoid a memory copy.
|
||||
utils.abiEncode(_typeParameters, _typeParameters, _isLibrary);
|
||||
utils.toSizeAfterFreeMemoryPointer();
|
||||
m_context << Instruction::RETURN;
|
||||
m_context << InternalInstruction::RETURN;
|
||||
}
|
||||
}
|
||||
|
||||
@ -678,7 +678,7 @@ bool ContractCompiler::visit(FunctionDefinition const& _function)
|
||||
while (!stackLayout.empty() && stackLayout.back() != static_cast<int>(stackLayout.size() - 1))
|
||||
if (stackLayout.back() < 0)
|
||||
{
|
||||
m_context << Instruction::POP;
|
||||
m_context << InternalInstruction::POP;
|
||||
stackLayout.pop_back();
|
||||
}
|
||||
else
|
||||
@ -920,7 +920,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
|
||||
util::errinfo_comment(util::stackTooDeepString)
|
||||
);
|
||||
_assembly.appendInstruction(swapInstruction(stackDiff));
|
||||
_assembly.appendInstruction(Instruction::POP);
|
||||
_assembly.appendInstruction(InternalInstruction::POP);
|
||||
}
|
||||
};
|
||||
|
||||
@ -1046,17 +1046,17 @@ void ContractCompiler::handleCatch(vector<ASTPointer<TryCatchClause>> const& _ca
|
||||
solAssert(m_context.evmVersion().supportsReturndata(), "");
|
||||
|
||||
// stack: <selector>
|
||||
m_context << Instruction::DUP1 << util::selectorFromSignatureU32("Error(string)") << Instruction::EQ;
|
||||
m_context << Instruction::ISZERO;
|
||||
m_context << InternalInstruction::DUP1 << util::selectorFromSignatureU32("Error(string)") << InternalInstruction::EQ;
|
||||
m_context << InternalInstruction::ISZERO;
|
||||
m_context.appendConditionalJumpTo(panicTag);
|
||||
m_context << Instruction::POP; // remove selector
|
||||
m_context << InternalInstruction::POP; // remove selector
|
||||
|
||||
// Try to decode the error message.
|
||||
// If this fails, leaves 0 on the stack, otherwise the pointer to the data string.
|
||||
m_context.callYulFunction(m_context.utilFunctions().tryDecodeErrorMessageFunction(), 0, 1);
|
||||
m_context << Instruction::DUP1;
|
||||
m_context << InternalInstruction::DUP1;
|
||||
AssemblyItem decodeSuccessTag = m_context.appendConditionalJump();
|
||||
m_context << Instruction::POP;
|
||||
m_context << InternalInstruction::POP;
|
||||
m_context.appendJumpTo(fallbackTag);
|
||||
m_context.adjustStackOffset(1);
|
||||
|
||||
@ -1078,15 +1078,15 @@ void ContractCompiler::handleCatch(vector<ASTPointer<TryCatchClause>> const& _ca
|
||||
solAssert(m_context.evmVersion().supportsReturndata(), "");
|
||||
|
||||
// stack: <selector>
|
||||
m_context << util::selectorFromSignatureU32("Panic(uint256)") << Instruction::EQ;
|
||||
m_context << Instruction::ISZERO;
|
||||
m_context << util::selectorFromSignatureU32("Panic(uint256)") << InternalInstruction::EQ;
|
||||
m_context << InternalInstruction::ISZERO;
|
||||
m_context.appendConditionalJumpTo(fallbackTag);
|
||||
|
||||
m_context.callYulFunction(m_context.utilFunctions().tryDecodePanicDataFunction(), 0, 2);
|
||||
m_context << Instruction::SWAP1;
|
||||
m_context << InternalInstruction::SWAP1;
|
||||
// stack: <code> <success>
|
||||
AssemblyItem decodeSuccessTag = m_context.appendConditionalJump();
|
||||
m_context << Instruction::POP;
|
||||
m_context << InternalInstruction::POP;
|
||||
m_context.appendJumpTo(fallbackTag);
|
||||
m_context.adjustStackOffset(1);
|
||||
|
||||
@ -1096,7 +1096,7 @@ void ContractCompiler::handleCatch(vector<ASTPointer<TryCatchClause>> const& _ca
|
||||
m_context.adjustStackOffset(1);
|
||||
}
|
||||
if (error || panic)
|
||||
m_context << Instruction::POP; // selector
|
||||
m_context << InternalInstruction::POP; // selector
|
||||
m_context << fallbackTag;
|
||||
if (fallback)
|
||||
{
|
||||
@ -1156,7 +1156,7 @@ bool ContractCompiler::visit(IfStatement const& _ifStatement)
|
||||
StackHeightChecker checker(m_context);
|
||||
CompilerContext::LocationSetter locationSetter(m_context, _ifStatement);
|
||||
compileExpression(_ifStatement.condition());
|
||||
m_context << Instruction::ISZERO;
|
||||
m_context << InternalInstruction::ISZERO;
|
||||
evmasm::AssemblyItem falseTag = m_context.appendConditionalJump();
|
||||
evmasm::AssemblyItem endTag = falseTag;
|
||||
_ifStatement.trueStatement().accept(*this);
|
||||
@ -1192,14 +1192,14 @@ bool ContractCompiler::visit(WhileStatement const& _whileStatement)
|
||||
|
||||
m_context << condition;
|
||||
compileExpression(_whileStatement.condition());
|
||||
m_context << Instruction::ISZERO << Instruction::ISZERO;
|
||||
m_context << InternalInstruction::ISZERO << InternalInstruction::ISZERO;
|
||||
m_context.appendConditionalJumpTo(loopStart);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_continueTags.emplace_back(loopStart, m_context.stackHeight());
|
||||
compileExpression(_whileStatement.condition());
|
||||
m_context << Instruction::ISZERO;
|
||||
m_context << InternalInstruction::ISZERO;
|
||||
m_context.appendConditionalJumpTo(loopEnd);
|
||||
|
||||
_whileStatement.body().accept(*this);
|
||||
@ -1236,7 +1236,7 @@ bool ContractCompiler::visit(ForStatement const& _forStatement)
|
||||
if (_forStatement.condition())
|
||||
{
|
||||
compileExpression(*_forStatement.condition());
|
||||
m_context << Instruction::ISZERO;
|
||||
m_context << InternalInstruction::ISZERO;
|
||||
m_context.appendConditionalJumpTo(loopEnd);
|
||||
}
|
||||
|
||||
|
@ -150,7 +150,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
|
||||
solAssert(CompilerUtils::freeMemoryPointer >= 0x40, "");
|
||||
|
||||
// pop offset
|
||||
m_context << Instruction::POP;
|
||||
m_context << InternalInstruction::POP;
|
||||
if (paramTypes[i]->isDynamicallySized())
|
||||
{
|
||||
solAssert(
|
||||
@ -175,7 +175,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
|
||||
slot_pos := hash
|
||||
})", {"slot_pos", "key_ptr"});
|
||||
|
||||
m_context << Instruction::POP;
|
||||
m_context << InternalInstruction::POP;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -188,7 +188,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
|
||||
utils().copyToStackTop(static_cast<unsigned>(paramTypes.size() - i), 1);
|
||||
utils().storeInMemory(0);
|
||||
m_context << u256(64) << u256(0);
|
||||
m_context << Instruction::KECCAK256;
|
||||
m_context << InternalInstruction::KECCAK256;
|
||||
}
|
||||
|
||||
// push offset
|
||||
@ -198,15 +198,15 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
|
||||
else if (auto arrayType = dynamic_cast<ArrayType const*>(returnType))
|
||||
{
|
||||
// pop offset
|
||||
m_context << Instruction::POP;
|
||||
m_context << InternalInstruction::POP;
|
||||
utils().copyToStackTop(static_cast<unsigned>(paramTypes.size() - i + 1), 1);
|
||||
|
||||
ArrayUtils(m_context).retrieveLength(*arrayType, 1);
|
||||
// Stack: ref [length] index length
|
||||
// check out-of-bounds access
|
||||
m_context << Instruction::DUP2 << Instruction::LT;
|
||||
m_context << InternalInstruction::DUP2 << InternalInstruction::LT;
|
||||
auto tag = m_context.appendConditionalJump();
|
||||
m_context << u256(0) << Instruction::DUP1 << Instruction::REVERT;
|
||||
m_context << u256(0) << InternalInstruction::DUP1 << InternalInstruction::REVERT;
|
||||
m_context << tag;
|
||||
|
||||
ArrayUtils(m_context).accessIndex(*arrayType, false);
|
||||
@ -217,11 +217,11 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
|
||||
}
|
||||
// remove index arguments.
|
||||
if (paramTypes.size() == 1)
|
||||
m_context << Instruction::SWAP2 << Instruction::POP << Instruction::SWAP1;
|
||||
m_context << InternalInstruction::SWAP2 << InternalInstruction::POP << InternalInstruction::SWAP1;
|
||||
else if (paramTypes.size() >= 2)
|
||||
{
|
||||
m_context << swapInstruction(static_cast<unsigned>(paramTypes.size()));
|
||||
m_context << Instruction::POP;
|
||||
m_context << InternalInstruction::POP;
|
||||
m_context << swapInstruction(static_cast<unsigned>(paramTypes.size()));
|
||||
utils().popStackSlots(paramTypes.size() - 1);
|
||||
}
|
||||
@ -232,7 +232,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
|
||||
{
|
||||
solAssert(!_varDecl.immutable(), "");
|
||||
// remove offset
|
||||
m_context << Instruction::POP;
|
||||
m_context << InternalInstruction::POP;
|
||||
auto const& names = accessorType.returnParameterNames();
|
||||
// struct
|
||||
for (size_t i = 0; i < names.size(); ++i)
|
||||
@ -243,7 +243,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
|
||||
if (!arrayType->isByteArrayOrString())
|
||||
continue;
|
||||
pair<u256, unsigned> const& offsets = structType->storageOffsetsOfMember(names[i]);
|
||||
m_context << Instruction::DUP1 << u256(offsets.first) << Instruction::ADD << u256(offsets.second);
|
||||
m_context << InternalInstruction::DUP1 << u256(offsets.first) << InternalInstruction::ADD << u256(offsets.second);
|
||||
Type const* memberType = structType->memberType(names[i]);
|
||||
StorageItem(m_context, *memberType).retrieveValue(SourceLocation(), true);
|
||||
utils().convertType(*memberType, *returnTypes[i]);
|
||||
@ -251,7 +251,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
|
||||
retSizeOnStack += returnTypes[i]->sizeOnStack();
|
||||
}
|
||||
// remove slot
|
||||
m_context << Instruction::POP;
|
||||
m_context << InternalInstruction::POP;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -355,7 +355,7 @@ bool ExpressionCompiler::visit(Assignment const& _assignment)
|
||||
);
|
||||
// value [lvalue_ref] updated_value
|
||||
for (unsigned i = 0; i < itemSize; ++i)
|
||||
m_context << swapInstruction(itemSize + lvalueSize) << Instruction::POP;
|
||||
m_context << swapInstruction(itemSize + lvalueSize) << InternalInstruction::POP;
|
||||
}
|
||||
m_currentLValue->storeValue(*_assignment.annotation().type, _assignment.location());
|
||||
}
|
||||
@ -371,7 +371,7 @@ bool ExpressionCompiler::visit(TupleExpression const& _tuple)
|
||||
|
||||
solAssert(!arrayType.isDynamicallySized(), "Cannot create dynamically sized inline array.");
|
||||
utils().allocateMemory(max(u256(32u), arrayType.memoryDataSize()));
|
||||
m_context << Instruction::DUP1;
|
||||
m_context << InternalInstruction::DUP1;
|
||||
|
||||
for (auto const& component: _tuple.components())
|
||||
{
|
||||
@ -379,7 +379,7 @@ bool ExpressionCompiler::visit(TupleExpression const& _tuple)
|
||||
utils().storeInMemoryDynamic(*arrayType.baseType(), true);
|
||||
}
|
||||
|
||||
m_context << Instruction::POP;
|
||||
m_context << InternalInstruction::POP;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -422,10 +422,10 @@ bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation)
|
||||
switch (_unaryOperation.getOperator())
|
||||
{
|
||||
case Token::Not: // !
|
||||
m_context << Instruction::ISZERO;
|
||||
m_context << InternalInstruction::ISZERO;
|
||||
break;
|
||||
case Token::BitNot: // ~
|
||||
m_context << Instruction::NOT;
|
||||
m_context << InternalInstruction::NOT;
|
||||
break;
|
||||
case Token::Delete: // delete
|
||||
solAssert(!!m_currentLValue, "LValue not retrieved.");
|
||||
@ -444,7 +444,7 @@ bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation)
|
||||
{
|
||||
// store value for later
|
||||
solUnimplementedAssert(type.sizeOnStack() == 1, "Stack size != 1 not implemented.");
|
||||
m_context << Instruction::DUP1;
|
||||
m_context << InternalInstruction::DUP1;
|
||||
if (m_currentLValue->sizeOnStack() > 0)
|
||||
for (unsigned i = 1 + m_currentLValue->sizeOnStack(); i > 0; --i)
|
||||
m_context << swapInstruction(i);
|
||||
@ -456,7 +456,7 @@ bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation)
|
||||
else
|
||||
{
|
||||
m_context << u256(1);
|
||||
m_context << Instruction::ADD;
|
||||
m_context << InternalInstruction::ADD;
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -466,7 +466,7 @@ bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation)
|
||||
else
|
||||
{
|
||||
m_context << u256(1);
|
||||
m_context << Instruction::SWAP1 << Instruction::SUB;
|
||||
m_context << InternalInstruction::SWAP1 << InternalInstruction::SUB;
|
||||
}
|
||||
}
|
||||
// Stack for prefix: [ref...] (*ref)+-1
|
||||
@ -489,7 +489,7 @@ bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation)
|
||||
if (m_context.arithmetic() == Arithmetic::Checked)
|
||||
m_context.callYulFunction(m_context.utilFunctions().negateNumberCheckedFunction(type), 1, 1);
|
||||
else
|
||||
m_context << u256(0) << Instruction::SUB;
|
||||
m_context << u256(0) << InternalInstruction::SUB;
|
||||
break;
|
||||
default:
|
||||
solAssert(false, "Invalid unary operator: " + string(TokenTraits::toString(_unaryOperation.getOperator())));
|
||||
@ -600,14 +600,14 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||
auto const& structType = dynamic_cast<StructType const&>(*type.actualType());
|
||||
|
||||
utils().allocateMemory(max(u256(32u), structType.memoryDataSize()));
|
||||
m_context << Instruction::DUP1;
|
||||
m_context << InternalInstruction::DUP1;
|
||||
|
||||
for (unsigned i = 0; i < arguments.size(); ++i)
|
||||
{
|
||||
acceptAndConvert(*arguments[i], *functionType->parameterTypes()[i]);
|
||||
utils().storeInMemoryDynamic(*functionType->parameterTypes()[i]);
|
||||
}
|
||||
m_context << Instruction::POP;
|
||||
m_context << InternalInstruction::POP;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -670,7 +670,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||
utils().rightShiftNumberOnStack(32);
|
||||
else
|
||||
// Extract the runtime part.
|
||||
m_context << ((u256(1) << 32) - 1) << Instruction::AND;
|
||||
m_context << ((u256(1) << 32) - 1) << InternalInstruction::AND;
|
||||
|
||||
m_context.appendJump(evmasm::AssemblyItem::JumpType::IntoFunction);
|
||||
m_context << returnLabel;
|
||||
@ -716,7 +716,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||
if (function.saltSet())
|
||||
{
|
||||
m_context << dupInstruction(2 + (function.valueSet() ? 1 : 0));
|
||||
m_context << Instruction::SWAP1;
|
||||
m_context << InternalInstruction::SWAP1;
|
||||
}
|
||||
|
||||
// now: [salt], [value], [salt], memory_end_ptr
|
||||
@ -730,19 +730,19 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||
|
||||
// now: [salt], [value], [salt], size, offset, value
|
||||
if (function.saltSet())
|
||||
m_context << Instruction::CREATE2;
|
||||
m_context << InternalInstruction::CREATE2;
|
||||
else
|
||||
m_context << Instruction::CREATE;
|
||||
m_context << InternalInstruction::CREATE;
|
||||
|
||||
// now: [salt], [value], address
|
||||
|
||||
if (function.valueSet())
|
||||
m_context << swapInstruction(1) << Instruction::POP;
|
||||
m_context << swapInstruction(1) << InternalInstruction::POP;
|
||||
if (function.saltSet())
|
||||
m_context << swapInstruction(1) << Instruction::POP;
|
||||
m_context << swapInstruction(1) << InternalInstruction::POP;
|
||||
|
||||
// Check if zero (reverted)
|
||||
m_context << Instruction::DUP1 << Instruction::ISZERO;
|
||||
m_context << InternalInstruction::DUP1 << InternalInstruction::ISZERO;
|
||||
if (_functionCall.annotation().tryCall)
|
||||
{
|
||||
// If this is a try call, return "<address> 1" in the success case and
|
||||
@ -767,7 +767,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||
if (stackDepth > 0)
|
||||
m_context << swapInstruction(stackDepth);
|
||||
if (function.gasSet())
|
||||
m_context << Instruction::POP;
|
||||
m_context << InternalInstruction::POP;
|
||||
break;
|
||||
}
|
||||
case FunctionType::Kind::SetValue:
|
||||
@ -776,7 +776,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||
// Note that function is not the original function, but the ".value" function.
|
||||
// Its values of gasSet and valueSet is equal to the original function's though.
|
||||
if (function.valueSet())
|
||||
m_context << Instruction::POP;
|
||||
m_context << InternalInstruction::POP;
|
||||
arguments.front()->accept(*this);
|
||||
break;
|
||||
case FunctionType::Kind::Send:
|
||||
@ -788,8 +788,8 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||
m_context << u256(evmasm::GasCosts::callStipend);
|
||||
acceptAndConvert(*arguments.front(), *function.parameterTypes().front(), true);
|
||||
// gas <- gas * !value
|
||||
m_context << Instruction::SWAP1 << Instruction::DUP2;
|
||||
m_context << Instruction::ISZERO << Instruction::MUL << Instruction::SWAP1;
|
||||
m_context << InternalInstruction::SWAP1 << InternalInstruction::DUP2;
|
||||
m_context << InternalInstruction::ISZERO << InternalInstruction::MUL << InternalInstruction::SWAP1;
|
||||
FunctionType::Options callOptions;
|
||||
callOptions.valueSet = true;
|
||||
callOptions.gasSet = true;
|
||||
@ -810,7 +810,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||
if (function.kind() == FunctionType::Kind::Transfer)
|
||||
{
|
||||
// Check if zero (out of stack or not enough balance).
|
||||
m_context << Instruction::ISZERO;
|
||||
m_context << InternalInstruction::ISZERO;
|
||||
// Revert message bubbles up.
|
||||
m_context.appendConditionalRevert(true);
|
||||
}
|
||||
@ -818,7 +818,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||
}
|
||||
case FunctionType::Kind::Selfdestruct:
|
||||
acceptAndConvert(*arguments.front(), *function.parameterTypes().front(), true);
|
||||
m_context << Instruction::SELFDESTRUCT;
|
||||
m_context << InternalInstruction::SELFDESTRUCT;
|
||||
break;
|
||||
case FunctionType::Kind::Revert:
|
||||
{
|
||||
@ -861,15 +861,15 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||
// Optimization: If type is bytes or string, then do not encode,
|
||||
// but directly compute keccak256 on memory.
|
||||
ArrayUtils(m_context).retrieveLength(*TypeProvider::bytesMemory());
|
||||
m_context << Instruction::SWAP1 << u256(0x20) << Instruction::ADD;
|
||||
m_context << Instruction::KECCAK256;
|
||||
m_context << InternalInstruction::SWAP1 << u256(0x20) << InternalInstruction::ADD;
|
||||
m_context << InternalInstruction::KECCAK256;
|
||||
}
|
||||
else
|
||||
{
|
||||
utils().fetchFreeMemoryPointer();
|
||||
utils().packedEncode({argType}, TypePointers());
|
||||
utils().toSizeAfterFreeMemoryPointer();
|
||||
m_context << Instruction::KECCAK256;
|
||||
m_context << InternalInstruction::KECCAK256;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -893,7 +893,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||
{referenceType}
|
||||
);
|
||||
utils().toSizeAfterFreeMemoryPointer();
|
||||
m_context << Instruction::KECCAK256;
|
||||
m_context << InternalInstruction::KECCAK256;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -993,21 +993,21 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||
case FunctionType::Kind::BlockHash:
|
||||
{
|
||||
acceptAndConvert(*arguments[0], *function.parameterTypes()[0], true);
|
||||
m_context << Instruction::BLOCKHASH;
|
||||
m_context << InternalInstruction::BLOCKHASH;
|
||||
break;
|
||||
}
|
||||
case FunctionType::Kind::AddMod:
|
||||
case FunctionType::Kind::MulMod:
|
||||
{
|
||||
acceptAndConvert(*arguments[2], *TypeProvider::uint256());
|
||||
m_context << Instruction::DUP1 << Instruction::ISZERO;
|
||||
m_context << InternalInstruction::DUP1 << InternalInstruction::ISZERO;
|
||||
m_context.appendConditionalPanic(util::PanicCode::DivisionByZero);
|
||||
for (unsigned i = 1; i < 3; i ++)
|
||||
acceptAndConvert(*arguments[2 - i], *TypeProvider::uint256());
|
||||
if (function.kind() == FunctionType::Kind::AddMod)
|
||||
m_context << Instruction::ADDMOD;
|
||||
m_context << InternalInstruction::ADDMOD;
|
||||
else
|
||||
m_context << Instruction::MULMOD;
|
||||
m_context << InternalInstruction::MULMOD;
|
||||
break;
|
||||
}
|
||||
case FunctionType::Kind::ECRecover:
|
||||
@ -1041,10 +1041,10 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||
solAssert(arrayType, "");
|
||||
|
||||
// stack: ArrayReference
|
||||
m_context << u256(1) << Instruction::DUP2;
|
||||
m_context << u256(1) << InternalInstruction::DUP2;
|
||||
ArrayUtils(m_context).incrementDynamicArraySize(*arrayType);
|
||||
// stack: ArrayReference 1 newLength
|
||||
m_context << Instruction::SUB;
|
||||
m_context << InternalInstruction::SUB;
|
||||
// stack: ArrayReference (newLength-1)
|
||||
ArrayUtils(m_context).accessIndex(*arrayType, false);
|
||||
|
||||
@ -1067,10 +1067,10 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||
// stack: ArrayReference argValue
|
||||
utils().moveToStackTop(argType->sizeOnStack(), 1);
|
||||
// stack: argValue ArrayReference
|
||||
m_context << Instruction::DUP1;
|
||||
m_context << InternalInstruction::DUP1;
|
||||
ArrayUtils(m_context).incrementDynamicArraySize(*arrayType);
|
||||
// stack: argValue ArrayReference newLength
|
||||
m_context << u256(1) << Instruction::SWAP1 << Instruction::SUB;
|
||||
m_context << u256(1) << InternalInstruction::SWAP1 << InternalInstruction::SUB;
|
||||
// stack: argValue ArrayReference (newLength-1)
|
||||
ArrayUtils(m_context).accessIndex(*arrayType, false);
|
||||
// stack: argValue storageSlot slotOffset
|
||||
@ -1137,13 +1137,13 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||
}
|
||||
utils().fetchFreeMemoryPointer();
|
||||
// stack: <arg1> <arg2> ... <argn> <free mem>
|
||||
m_context << u256(32) << Instruction::ADD;
|
||||
m_context << u256(32) << InternalInstruction::ADD;
|
||||
utils().packedEncode(argumentTypes, targetTypes);
|
||||
utils().fetchFreeMemoryPointer();
|
||||
m_context.appendInlineAssembly(R"({
|
||||
mstore(mem_ptr, sub(sub(mem_end, mem_ptr), 0x20))
|
||||
})", {"mem_end", "mem_ptr"});
|
||||
m_context << Instruction::SWAP1;
|
||||
m_context << InternalInstruction::SWAP1;
|
||||
utils().storeFreeMemoryPointer();
|
||||
|
||||
break;
|
||||
@ -1159,42 +1159,42 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||
|
||||
// Make sure we can allocate memory without overflow
|
||||
m_context << u256(0xffffffffffffffff);
|
||||
m_context << Instruction::DUP2;
|
||||
m_context << Instruction::GT;
|
||||
m_context << InternalInstruction::DUP2;
|
||||
m_context << InternalInstruction::GT;
|
||||
m_context.appendConditionalPanic(PanicCode::ResourceError);
|
||||
|
||||
// Stack: requested_length
|
||||
utils().fetchFreeMemoryPointer();
|
||||
|
||||
// Stack: requested_length memptr
|
||||
m_context << Instruction::SWAP1;
|
||||
m_context << InternalInstruction::SWAP1;
|
||||
// Stack: memptr requested_length
|
||||
// store length
|
||||
m_context << Instruction::DUP1 << Instruction::DUP3 << Instruction::MSTORE;
|
||||
m_context << InternalInstruction::DUP1 << InternalInstruction::DUP3 << InternalInstruction::MSTORE;
|
||||
// Stack: memptr requested_length
|
||||
// update free memory pointer
|
||||
m_context << Instruction::DUP1;
|
||||
m_context << InternalInstruction::DUP1;
|
||||
// Stack: memptr requested_length requested_length
|
||||
if (arrayType.isByteArrayOrString())
|
||||
// Round up to multiple of 32
|
||||
m_context << u256(31) << Instruction::ADD << u256(31) << Instruction::NOT << Instruction::AND;
|
||||
m_context << u256(31) << InternalInstruction::ADD << u256(31) << InternalInstruction::NOT << InternalInstruction::AND;
|
||||
else
|
||||
m_context << arrayType.baseType()->memoryHeadSize() << Instruction::MUL;
|
||||
m_context << arrayType.baseType()->memoryHeadSize() << InternalInstruction::MUL;
|
||||
// stacK: memptr requested_length data_size
|
||||
m_context << u256(32) << Instruction::ADD;
|
||||
m_context << Instruction::DUP3 << Instruction::ADD;
|
||||
m_context << u256(32) << InternalInstruction::ADD;
|
||||
m_context << InternalInstruction::DUP3 << InternalInstruction::ADD;
|
||||
utils().storeFreeMemoryPointer();
|
||||
// Stack: memptr requested_length
|
||||
|
||||
// Check if length is zero
|
||||
m_context << Instruction::DUP1 << Instruction::ISZERO;
|
||||
m_context << InternalInstruction::DUP1 << InternalInstruction::ISZERO;
|
||||
auto skipInit = m_context.appendConditionalJump();
|
||||
// Always initialize because the free memory pointer might point at
|
||||
// a dirty memory area.
|
||||
m_context << Instruction::DUP2 << u256(32) << Instruction::ADD;
|
||||
m_context << InternalInstruction::DUP2 << u256(32) << InternalInstruction::ADD;
|
||||
utils().zeroInitialiseMemoryArray(arrayType);
|
||||
m_context << skipInit;
|
||||
m_context << Instruction::POP;
|
||||
m_context << InternalInstruction::POP;
|
||||
break;
|
||||
}
|
||||
case FunctionType::Kind::Assert:
|
||||
@ -1227,7 +1227,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||
}
|
||||
// Stack: <error string (unconverted)> <condition>
|
||||
// jump if condition was met
|
||||
m_context << Instruction::ISZERO << Instruction::ISZERO;
|
||||
m_context << InternalInstruction::ISZERO << InternalInstruction::ISZERO;
|
||||
auto success = m_context.appendConditionalJump();
|
||||
if (function.kind() == FunctionType::Kind::Assert)
|
||||
// condition was not met, flag an error
|
||||
@ -1291,7 +1291,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||
// stack now: [<selector/functionPointer/signature>] <arg1> .. <argN> <free_mem>
|
||||
|
||||
// adjust by 32(+4) bytes to accommodate the length(+selector)
|
||||
m_context << u256(32 + (hasSelectorOrSignature ? 4 : 0)) << Instruction::ADD;
|
||||
m_context << u256(32 + (hasSelectorOrSignature ? 4 : 0)) << InternalInstruction::ADD;
|
||||
// stack now: [<selector/functionPointer/signature>] <arg1> .. <argN> <data_encoding_area_start>
|
||||
|
||||
if (isPacked)
|
||||
@ -1311,7 +1311,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||
m_context.appendInlineAssembly(R"({
|
||||
mstore(mem_ptr, sub(sub(mem_end, mem_ptr), 0x20))
|
||||
})", {"mem_end", "mem_ptr"});
|
||||
m_context << Instruction::SWAP1;
|
||||
m_context << InternalInstruction::SWAP1;
|
||||
utils().storeFreeMemoryPointer();
|
||||
// stack: [<selector/functionPointer/signature>] <memory ptr>
|
||||
|
||||
@ -1338,7 +1338,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||
// stack: <memory pointer> <signature> <free mem ptr>
|
||||
utils().packedEncode(TypePointers{selectorType}, TypePointers());
|
||||
utils().toSizeAfterFreeMemoryPointer();
|
||||
m_context << Instruction::KECCAK256;
|
||||
m_context << InternalInstruction::KECCAK256;
|
||||
// stack: <memory pointer> <hash>
|
||||
|
||||
dataOnStack = TypeProvider::fixedBytes(32);
|
||||
@ -1358,7 +1358,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||
solAssert(selectorType->sizeOnStack() == 2);
|
||||
// stack: <memory pointer> <functionPointer>
|
||||
// Extract selector from the stack
|
||||
m_context << Instruction::SWAP1 << Instruction::POP;
|
||||
m_context << InternalInstruction::SWAP1 << InternalInstruction::POP;
|
||||
}
|
||||
// Conversion will be done below
|
||||
dataOnStack = TypeProvider::uint(32);
|
||||
@ -1378,7 +1378,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||
let mask := )" + mask + R"(
|
||||
mstore(data_start, or(and(data, mask), selector))
|
||||
})", {"mem_ptr", "selector"});
|
||||
m_context << Instruction::POP;
|
||||
m_context << InternalInstruction::POP;
|
||||
}
|
||||
|
||||
// stack now: <memory pointer>
|
||||
@ -1405,8 +1405,8 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||
else
|
||||
{
|
||||
utils().convertType(*firstArgType, *TypeProvider::bytesMemory());
|
||||
m_context << Instruction::DUP1 << u256(32) << Instruction::ADD;
|
||||
m_context << Instruction::SWAP1 << Instruction::MLOAD;
|
||||
m_context << InternalInstruction::DUP1 << u256(32) << InternalInstruction::ADD;
|
||||
m_context << InternalInstruction::SWAP1 << InternalInstruction::MLOAD;
|
||||
// stack now: <mem_pos> <length>
|
||||
|
||||
utils().abiDecode(targetTypes, true);
|
||||
@ -1414,7 +1414,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||
break;
|
||||
}
|
||||
case FunctionType::Kind::GasLeft:
|
||||
m_context << Instruction::GAS;
|
||||
m_context << InternalInstruction::GAS;
|
||||
break;
|
||||
case FunctionType::Kind::MetaType:
|
||||
// No code to generate.
|
||||
@ -1649,7 +1649,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
|
||||
dynamic_cast<MagicVariableDeclaration const*>(arg->annotation().referencedDeclaration)
|
||||
)
|
||||
{
|
||||
m_context << Instruction::SELFBALANCE;
|
||||
m_context << InternalInstruction::SELFBALANCE;
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1671,7 +1671,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
|
||||
*TypeProvider::address(),
|
||||
true
|
||||
);
|
||||
m_context << Instruction::EXTCODESIZE;
|
||||
m_context << InternalInstruction::EXTCODESIZE;
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -1713,7 +1713,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
|
||||
*TypeProvider::address(),
|
||||
true
|
||||
);
|
||||
m_context << Instruction::BALANCE;
|
||||
m_context << InternalInstruction::BALANCE;
|
||||
}
|
||||
else if (member == "code")
|
||||
{
|
||||
@ -1724,28 +1724,28 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
|
||||
true
|
||||
);
|
||||
|
||||
m_context << Instruction::DUP1 << Instruction::EXTCODESIZE;
|
||||
m_context << InternalInstruction::DUP1 << InternalInstruction::EXTCODESIZE;
|
||||
// Stack post: <address> <size>
|
||||
|
||||
m_context << Instruction::DUP1;
|
||||
m_context << InternalInstruction::DUP1;
|
||||
// Account for the size field of `bytes memory`
|
||||
m_context << u256(32) << Instruction::ADD;
|
||||
m_context << u256(32) << InternalInstruction::ADD;
|
||||
utils().allocateMemory();
|
||||
// Stack post: <address> <size> <mem_offset>
|
||||
|
||||
// Store size at mem_offset
|
||||
m_context << Instruction::DUP2 << Instruction::DUP2 << Instruction::MSTORE;
|
||||
m_context << InternalInstruction::DUP2 << InternalInstruction::DUP2 << InternalInstruction::MSTORE;
|
||||
|
||||
m_context << u256(0) << Instruction::SWAP1 << Instruction::DUP1;
|
||||
m_context << u256(0) << InternalInstruction::SWAP1 << InternalInstruction::DUP1;
|
||||
// Stack post: <address> <size> 0 <mem_offset> <mem_offset>
|
||||
|
||||
m_context << u256(32) << Instruction::ADD << Instruction::SWAP1;
|
||||
m_context << u256(32) << InternalInstruction::ADD << InternalInstruction::SWAP1;
|
||||
// Stack post: <address> <size> 0 <mem_offset_adjusted> <mem_offset>
|
||||
|
||||
m_context << Instruction::SWAP4;
|
||||
m_context << InternalInstruction::SWAP4;
|
||||
// Stack post: <mem_offset> <size> 0 <mem_offset_adjusted> <address>
|
||||
|
||||
m_context << Instruction::EXTCODECOPY;
|
||||
m_context << InternalInstruction::EXTCODECOPY;
|
||||
// Stack post: <mem_offset>
|
||||
}
|
||||
else if (member == "codehash")
|
||||
@ -1755,7 +1755,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
|
||||
*TypeProvider::address(),
|
||||
true
|
||||
);
|
||||
m_context << Instruction::EXTCODEHASH;
|
||||
m_context << InternalInstruction::EXTCODEHASH;
|
||||
}
|
||||
else if ((set<string>{"send", "transfer"}).count(member))
|
||||
{
|
||||
@ -1785,7 +1785,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
|
||||
|
||||
if (functionType.kind() == FunctionType::Kind::External)
|
||||
CompilerUtils(m_context).popStackSlots(functionType.sizeOnStack() - 2);
|
||||
m_context << Instruction::SWAP1 << Instruction::POP;
|
||||
m_context << InternalInstruction::SWAP1 << InternalInstruction::POP;
|
||||
|
||||
/// need to store it as bytes4
|
||||
utils().leftShiftNumberOnStack(224);
|
||||
@ -1805,34 +1805,34 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
|
||||
case Type::Category::Magic:
|
||||
// we can ignore the kind of magic and only look at the name of the member
|
||||
if (member == "coinbase")
|
||||
m_context << Instruction::COINBASE;
|
||||
m_context << InternalInstruction::COINBASE;
|
||||
else if (member == "timestamp")
|
||||
m_context << Instruction::TIMESTAMP;
|
||||
m_context << InternalInstruction::TIMESTAMP;
|
||||
else if (member == "difficulty")
|
||||
m_context << Instruction::DIFFICULTY;
|
||||
m_context << InternalInstruction::DIFFICULTY;
|
||||
else if (member == "prevrandao")
|
||||
m_context << Instruction::PREVRANDAO;
|
||||
m_context << InternalInstruction::PREVRANDAO;
|
||||
else if (member == "number")
|
||||
m_context << Instruction::NUMBER;
|
||||
m_context << InternalInstruction::NUMBER;
|
||||
else if (member == "gaslimit")
|
||||
m_context << Instruction::GASLIMIT;
|
||||
m_context << InternalInstruction::GASLIMIT;
|
||||
else if (member == "sender")
|
||||
m_context << Instruction::CALLER;
|
||||
m_context << InternalInstruction::CALLER;
|
||||
else if (member == "value")
|
||||
m_context << Instruction::CALLVALUE;
|
||||
m_context << InternalInstruction::CALLVALUE;
|
||||
else if (member == "origin")
|
||||
m_context << Instruction::ORIGIN;
|
||||
m_context << InternalInstruction::ORIGIN;
|
||||
else if (member == "gasprice")
|
||||
m_context << Instruction::GASPRICE;
|
||||
m_context << InternalInstruction::GASPRICE;
|
||||
else if (member == "chainid")
|
||||
m_context << Instruction::CHAINID;
|
||||
m_context << InternalInstruction::CHAINID;
|
||||
else if (member == "basefee")
|
||||
m_context << Instruction::BASEFEE;
|
||||
m_context << InternalInstruction::BASEFEE;
|
||||
else if (member == "data")
|
||||
m_context << u256(0) << Instruction::CALLDATASIZE;
|
||||
m_context << u256(0) << InternalInstruction::CALLDATASIZE;
|
||||
else if (member == "sig")
|
||||
m_context << u256(0) << Instruction::CALLDATALOAD
|
||||
<< (u256(0xffffffff) << (256 - 32)) << Instruction::AND;
|
||||
m_context << u256(0) << InternalInstruction::CALLDATALOAD
|
||||
<< (u256(0xffffffff) << (256 - 32)) << InternalInstruction::AND;
|
||||
else if (member == "gas")
|
||||
solAssert(false, "Gas has been removed.");
|
||||
else if (member == "blockhash")
|
||||
@ -1844,7 +1844,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
|
||||
solAssert(!contractType.isSuper(), "");
|
||||
ContractDefinition const& contract = contractType.contractDefinition();
|
||||
utils().fetchFreeMemoryPointer();
|
||||
m_context << Instruction::DUP1 << u256(32) << Instruction::ADD;
|
||||
m_context << InternalInstruction::DUP1 << u256(32) << InternalInstruction::ADD;
|
||||
utils().copyContractCodeToMemory(contract, member == "creationCode");
|
||||
// Stack: start end
|
||||
m_context.appendInlineAssembly(
|
||||
@ -1854,7 +1854,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
|
||||
})")("free", to_string(CompilerUtils::freeMemoryPointer)).render(),
|
||||
{"start", "end"}
|
||||
);
|
||||
m_context << Instruction::POP;
|
||||
m_context << InternalInstruction::POP;
|
||||
}
|
||||
else if (member == "name")
|
||||
{
|
||||
@ -1865,9 +1865,9 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
|
||||
dynamic_cast<ContractType const&>(*arg).contractDefinition();
|
||||
utils().allocateMemory(((contract.name().length() + 31) / 32) * 32 + 32);
|
||||
// store string length
|
||||
m_context << u256(contract.name().length()) << Instruction::DUP2 << Instruction::MSTORE;
|
||||
m_context << u256(contract.name().length()) << InternalInstruction::DUP2 << InternalInstruction::MSTORE;
|
||||
// adjust pointer
|
||||
m_context << Instruction::DUP1 << u256(32) << Instruction::ADD;
|
||||
m_context << InternalInstruction::DUP1 << u256(32) << InternalInstruction::ADD;
|
||||
utils().storeStringData(contract.name());
|
||||
}
|
||||
else if (member == "interfaceId")
|
||||
@ -1903,13 +1903,13 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
|
||||
case DataLocation::Storage:
|
||||
{
|
||||
pair<u256, unsigned> const& offsets = type.storageOffsetsOfMember(member);
|
||||
m_context << offsets.first << Instruction::ADD << u256(offsets.second);
|
||||
m_context << offsets.first << InternalInstruction::ADD << u256(offsets.second);
|
||||
setLValueToStorageItem(_memberAccess);
|
||||
break;
|
||||
}
|
||||
case DataLocation::Memory:
|
||||
{
|
||||
m_context << type.memoryOffsetOfMember(member) << Instruction::ADD;
|
||||
m_context << type.memoryOffsetOfMember(member) << InternalInstruction::ADD;
|
||||
setLValue<MemoryItem>(_memberAccess, *memberType);
|
||||
break;
|
||||
}
|
||||
@ -1917,13 +1917,13 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
|
||||
{
|
||||
if (_memberAccess.annotation().type->isDynamicallyEncoded())
|
||||
{
|
||||
m_context << Instruction::DUP1;
|
||||
m_context << type.calldataOffsetOfMember(member) << Instruction::ADD;
|
||||
m_context << InternalInstruction::DUP1;
|
||||
m_context << type.calldataOffsetOfMember(member) << InternalInstruction::ADD;
|
||||
CompilerUtils(m_context).accessCalldataTail(*memberType);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_context << type.calldataOffsetOfMember(member) << Instruction::ADD;
|
||||
m_context << type.calldataOffsetOfMember(member) << InternalInstruction::ADD;
|
||||
// For non-value types the calldata offset is returned directly.
|
||||
if (memberType->isValueType())
|
||||
{
|
||||
@ -1971,14 +1971,14 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
|
||||
switch (type.location())
|
||||
{
|
||||
case DataLocation::CallData:
|
||||
m_context << Instruction::SWAP1 << Instruction::POP;
|
||||
m_context << InternalInstruction::SWAP1 << InternalInstruction::POP;
|
||||
break;
|
||||
case DataLocation::Storage:
|
||||
ArrayUtils(m_context).retrieveLength(type);
|
||||
m_context << Instruction::SWAP1 << Instruction::POP;
|
||||
m_context << InternalInstruction::SWAP1 << InternalInstruction::POP;
|
||||
break;
|
||||
case DataLocation::Memory:
|
||||
m_context << Instruction::MLOAD;
|
||||
m_context << InternalInstruction::MLOAD;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -2066,7 +2066,7 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
|
||||
TypePointers{_indexAccess.indexExpression()->annotation().type},
|
||||
TypePointers{keyType}
|
||||
);
|
||||
m_context << Instruction::SWAP1;
|
||||
m_context << InternalInstruction::SWAP1;
|
||||
utils().storeInMemoryDynamic(*TypeProvider::uint256());
|
||||
utils().toSizeAfterFreeMemoryPointer();
|
||||
}
|
||||
@ -2074,12 +2074,12 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
|
||||
{
|
||||
m_context << u256(0); // memory position
|
||||
appendExpressionCopyToMemory(*keyType, *_indexAccess.indexExpression());
|
||||
m_context << Instruction::SWAP1;
|
||||
m_context << InternalInstruction::SWAP1;
|
||||
solAssert(CompilerUtils::freeMemoryPointer >= 0x40, "");
|
||||
utils().storeInMemoryDynamic(*TypeProvider::uint256());
|
||||
m_context << u256(0);
|
||||
}
|
||||
m_context << Instruction::KECCAK256;
|
||||
m_context << InternalInstruction::KECCAK256;
|
||||
m_context << u256(0);
|
||||
setLValueToStorageItem(_indexAccess);
|
||||
break;
|
||||
@ -2138,11 +2138,11 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
|
||||
// stack layout: <value> <index>
|
||||
// check out-of-bounds access
|
||||
m_context << u256(fixedBytesType.numBytes());
|
||||
m_context << Instruction::DUP2 << Instruction::LT << Instruction::ISZERO;
|
||||
m_context << InternalInstruction::DUP2 << InternalInstruction::LT << InternalInstruction::ISZERO;
|
||||
// out-of-bounds access throws exception
|
||||
m_context.appendConditionalPanic(util::PanicCode::ArrayOutOfBounds);
|
||||
|
||||
m_context << Instruction::BYTE;
|
||||
m_context << InternalInstruction::BYTE;
|
||||
utils().leftShiftNumberOnStack(256 - 8);
|
||||
break;
|
||||
}
|
||||
@ -2187,16 +2187,16 @@ bool ExpressionCompiler::visit(IndexRangeAccess const& _indexAccess)
|
||||
m_context << u256(0);
|
||||
// stack: offset length sliceStart
|
||||
|
||||
m_context << Instruction::SWAP1;
|
||||
m_context << InternalInstruction::SWAP1;
|
||||
// stack: offset sliceStart length
|
||||
|
||||
if (_indexAccess.endExpression())
|
||||
acceptAndConvert(*_indexAccess.endExpression(), *TypeProvider::uint256());
|
||||
else
|
||||
m_context << Instruction::DUP1;
|
||||
m_context << InternalInstruction::DUP1;
|
||||
// stack: offset sliceStart length sliceEnd
|
||||
|
||||
m_context << Instruction::SWAP3;
|
||||
m_context << InternalInstruction::SWAP3;
|
||||
// stack: sliceEnd sliceStart length offset
|
||||
|
||||
m_context.callYulFunction(m_context.utilFunctions().calldataArrayIndexRangeAccess(*arrayType), 4, 2);
|
||||
@ -2216,7 +2216,7 @@ void ExpressionCompiler::endVisit(Identifier const& _identifier)
|
||||
if (dynamic_cast<ContractType const*>(magicVar->type()))
|
||||
{
|
||||
solAssert(_identifier.name() == "this", "");
|
||||
m_context << Instruction::ADDRESS;
|
||||
m_context << InternalInstruction::ADDRESS;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -2294,11 +2294,11 @@ void ExpressionCompiler::appendAndOrOperatorCode(BinaryOperation const& _binaryO
|
||||
solAssert(c_op == Token::Or || c_op == Token::And, "");
|
||||
|
||||
_binaryOperation.leftExpression().accept(*this);
|
||||
m_context << Instruction::DUP1;
|
||||
m_context << InternalInstruction::DUP1;
|
||||
if (c_op == Token::And)
|
||||
m_context << Instruction::ISZERO;
|
||||
m_context << InternalInstruction::ISZERO;
|
||||
evmasm::AssemblyItem endLabel = m_context.appendConditionalJump();
|
||||
m_context << Instruction::POP;
|
||||
m_context << InternalInstruction::POP;
|
||||
_binaryOperation.rightExpression().accept(*this);
|
||||
m_context << endLabel;
|
||||
}
|
||||
@ -2311,18 +2311,18 @@ void ExpressionCompiler::appendCompareOperatorCode(Token _operator, Type const&
|
||||
if (functionType && functionType->kind() == FunctionType::Kind::External)
|
||||
{
|
||||
solUnimplementedAssert(functionType->sizeOnStack() == 2, "");
|
||||
m_context << Instruction::SWAP3;
|
||||
m_context << InternalInstruction::SWAP3;
|
||||
|
||||
m_context << ((u256(1) << 160) - 1) << Instruction::AND;
|
||||
m_context << Instruction::SWAP1;
|
||||
m_context << ((u256(1) << 160) - 1) << Instruction::AND;
|
||||
m_context << Instruction::EQ;
|
||||
m_context << Instruction::SWAP2;
|
||||
m_context << ((u256(1) << 32) - 1) << Instruction::AND;
|
||||
m_context << Instruction::SWAP1;
|
||||
m_context << ((u256(1) << 32) - 1) << Instruction::AND;
|
||||
m_context << Instruction::EQ;
|
||||
m_context << Instruction::AND;
|
||||
m_context << ((u256(1) << 160) - 1) << InternalInstruction::AND;
|
||||
m_context << InternalInstruction::SWAP1;
|
||||
m_context << ((u256(1) << 160) - 1) << InternalInstruction::AND;
|
||||
m_context << InternalInstruction::EQ;
|
||||
m_context << InternalInstruction::SWAP2;
|
||||
m_context << ((u256(1) << 32) - 1) << InternalInstruction::AND;
|
||||
m_context << InternalInstruction::SWAP1;
|
||||
m_context << ((u256(1) << 32) - 1) << InternalInstruction::AND;
|
||||
m_context << InternalInstruction::EQ;
|
||||
m_context << InternalInstruction::AND;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -2331,14 +2331,14 @@ void ExpressionCompiler::appendCompareOperatorCode(Token _operator, Type const&
|
||||
{
|
||||
// We have to remove the upper bits (construction time value) because they might
|
||||
// be "unknown" in one of the operands and not in the other.
|
||||
m_context << ((u256(1) << 32) - 1) << Instruction::AND;
|
||||
m_context << Instruction::SWAP1;
|
||||
m_context << ((u256(1) << 32) - 1) << Instruction::AND;
|
||||
m_context << ((u256(1) << 32) - 1) << InternalInstruction::AND;
|
||||
m_context << InternalInstruction::SWAP1;
|
||||
m_context << ((u256(1) << 32) - 1) << InternalInstruction::AND;
|
||||
}
|
||||
m_context << Instruction::EQ;
|
||||
m_context << InternalInstruction::EQ;
|
||||
}
|
||||
if (_operator == Token::NotEqual)
|
||||
m_context << Instruction::ISZERO;
|
||||
m_context << InternalInstruction::ISZERO;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -2351,19 +2351,19 @@ void ExpressionCompiler::appendCompareOperatorCode(Token _operator, Type const&
|
||||
{
|
||||
case Token::GreaterThanOrEqual:
|
||||
m_context <<
|
||||
(isSigned ? Instruction::SLT : Instruction::LT) <<
|
||||
Instruction::ISZERO;
|
||||
(isSigned ? InternalInstruction::SLT : InternalInstruction::LT) <<
|
||||
InternalInstruction::ISZERO;
|
||||
break;
|
||||
case Token::LessThanOrEqual:
|
||||
m_context <<
|
||||
(isSigned ? Instruction::SGT : Instruction::GT) <<
|
||||
Instruction::ISZERO;
|
||||
(isSigned ? InternalInstruction::SGT : InternalInstruction::GT) <<
|
||||
InternalInstruction::ISZERO;
|
||||
break;
|
||||
case Token::GreaterThan:
|
||||
m_context << (isSigned ? Instruction::SGT : Instruction::GT);
|
||||
m_context << (isSigned ? InternalInstruction::SGT : InternalInstruction::GT);
|
||||
break;
|
||||
case Token::LessThan:
|
||||
m_context << (isSigned ? Instruction::SLT : Instruction::LT);
|
||||
m_context << (isSigned ? InternalInstruction::SLT : InternalInstruction::LT);
|
||||
break;
|
||||
default:
|
||||
solAssert(false, "Unknown comparison operator.");
|
||||
@ -2422,25 +2422,25 @@ void ExpressionCompiler::appendArithmeticOperatorCode(Token _operator, Type cons
|
||||
switch (_operator)
|
||||
{
|
||||
case Token::Add:
|
||||
m_context << Instruction::ADD;
|
||||
m_context << InternalInstruction::ADD;
|
||||
break;
|
||||
case Token::Sub:
|
||||
m_context << Instruction::SUB;
|
||||
m_context << InternalInstruction::SUB;
|
||||
break;
|
||||
case Token::Mul:
|
||||
m_context << Instruction::MUL;
|
||||
m_context << InternalInstruction::MUL;
|
||||
break;
|
||||
case Token::Div:
|
||||
case Token::Mod:
|
||||
{
|
||||
// Test for division by zero
|
||||
m_context << Instruction::DUP2 << Instruction::ISZERO;
|
||||
m_context << InternalInstruction::DUP2 << InternalInstruction::ISZERO;
|
||||
m_context.appendConditionalPanic(util::PanicCode::DivisionByZero);
|
||||
|
||||
if (_operator == Token::Div)
|
||||
m_context << (c_isSigned ? Instruction::SDIV : Instruction::DIV);
|
||||
m_context << (c_isSigned ? InternalInstruction::SDIV : InternalInstruction::DIV);
|
||||
else
|
||||
m_context << (c_isSigned ? Instruction::SMOD : Instruction::MOD);
|
||||
m_context << (c_isSigned ? InternalInstruction::SMOD : InternalInstruction::MOD);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@ -2454,13 +2454,13 @@ void ExpressionCompiler::appendBitOperatorCode(Token _operator)
|
||||
switch (_operator)
|
||||
{
|
||||
case Token::BitOr:
|
||||
m_context << Instruction::OR;
|
||||
m_context << InternalInstruction::OR;
|
||||
break;
|
||||
case Token::BitAnd:
|
||||
m_context << Instruction::AND;
|
||||
m_context << InternalInstruction::AND;
|
||||
break;
|
||||
case Token::BitXor:
|
||||
m_context << Instruction::XOR;
|
||||
m_context << InternalInstruction::XOR;
|
||||
break;
|
||||
default:
|
||||
solAssert(false, "Unknown bit operator.");
|
||||
@ -2489,20 +2489,20 @@ void ExpressionCompiler::appendShiftOperatorCode(Token _operator, Type const& _v
|
||||
else
|
||||
solAssert(false, "Invalid shift amount type.");
|
||||
|
||||
m_context << Instruction::SWAP1;
|
||||
m_context << InternalInstruction::SWAP1;
|
||||
// stack: value_to_shift shift_amount
|
||||
|
||||
switch (_operator)
|
||||
{
|
||||
case Token::SHL:
|
||||
if (m_context.evmVersion().hasBitwiseShifting())
|
||||
m_context << Instruction::SHL;
|
||||
m_context << InternalInstruction::SHL;
|
||||
else
|
||||
m_context << u256(2) << Instruction::EXP << Instruction::MUL;
|
||||
m_context << u256(2) << InternalInstruction::EXP << InternalInstruction::MUL;
|
||||
break;
|
||||
case Token::SAR:
|
||||
if (m_context.evmVersion().hasBitwiseShifting())
|
||||
m_context << (c_valueSigned ? Instruction::SAR : Instruction::SHR);
|
||||
m_context << (c_valueSigned ? InternalInstruction::SAR : InternalInstruction::SHR);
|
||||
else
|
||||
{
|
||||
if (c_valueSigned)
|
||||
@ -2528,7 +2528,7 @@ void ExpressionCompiler::appendShiftOperatorCode(Token _operator, Type const& _v
|
||||
m_context.appendInlineAssembly(R"({
|
||||
value_to_shift := div(value_to_shift, exp(2, shift_amount))
|
||||
})", {"value_to_shift", "shift_amount"});
|
||||
m_context << Instruction::POP;
|
||||
m_context << InternalInstruction::POP;
|
||||
|
||||
}
|
||||
break;
|
||||
@ -2550,7 +2550,7 @@ void ExpressionCompiler::appendExpOperatorCode(Type const& _valueType, Type cons
|
||||
dynamic_cast<IntegerType const&>(_exponentType)
|
||||
), 2, 1);
|
||||
else
|
||||
m_context << Instruction::EXP;
|
||||
m_context << InternalInstruction::EXP;
|
||||
}
|
||||
|
||||
void ExpressionCompiler::appendExternalFunctionCall(
|
||||
@ -2626,8 +2626,8 @@ void ExpressionCompiler::appendExternalFunctionCall(
|
||||
// zero bytes (which we cannot detect).
|
||||
solAssert(0 < retSize && retSize <= 32, "");
|
||||
utils().fetchFreeMemoryPointer();
|
||||
m_context << u256(0) << Instruction::DUP2 << Instruction::MSTORE;
|
||||
m_context << u256(32) << Instruction::ADD;
|
||||
m_context << u256(0) << InternalInstruction::DUP2 << InternalInstruction::MSTORE;
|
||||
m_context << u256(32) << InternalInstruction::ADD;
|
||||
utils().storeFreeMemoryPointer();
|
||||
}
|
||||
|
||||
@ -2642,7 +2642,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
|
||||
m_context << u256(0);
|
||||
utils().fetchFreeMemoryPointer();
|
||||
// This touches too much, but that way we save some rounding arithmetic
|
||||
m_context << u256(retSize) << Instruction::ADD << Instruction::MSTORE;
|
||||
m_context << u256(retSize) << InternalInstruction::ADD << InternalInstruction::MSTORE;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2687,15 +2687,15 @@ void ExpressionCompiler::appendExternalFunctionCall(
|
||||
if (funKind == FunctionType::Kind::ECRecover)
|
||||
{
|
||||
// In this case, output is 32 bytes before input and has already been cleared.
|
||||
m_context << u256(32) << Instruction::DUP2 << Instruction::SUB << Instruction::SWAP1;
|
||||
m_context << u256(32) << InternalInstruction::DUP2 << InternalInstruction::SUB << InternalInstruction::SWAP1;
|
||||
// Here: <input end> <output size> <outpos> <input pos>
|
||||
m_context << Instruction::DUP1 << Instruction::DUP5 << Instruction::SUB;
|
||||
m_context << Instruction::SWAP1;
|
||||
m_context << InternalInstruction::DUP1 << InternalInstruction::DUP5 << InternalInstruction::SUB;
|
||||
m_context << InternalInstruction::SWAP1;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_context << Instruction::DUP1 << Instruction::DUP4 << Instruction::SUB;
|
||||
m_context << Instruction::DUP2;
|
||||
m_context << InternalInstruction::DUP1 << InternalInstruction::DUP4 << InternalInstruction::SUB;
|
||||
m_context << InternalInstruction::DUP2;
|
||||
}
|
||||
|
||||
// CALL arguments: outSize, outOff, inSize, inOff (already present up to here)
|
||||
@ -2725,7 +2725,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
|
||||
m_context.revertStrings() >= RevertStrings::Debug
|
||||
)
|
||||
{
|
||||
m_context << Instruction::DUP1 << Instruction::EXTCODESIZE << Instruction::ISZERO;
|
||||
m_context << InternalInstruction::DUP1 << InternalInstruction::EXTCODESIZE << InternalInstruction::ISZERO;
|
||||
m_context.appendConditionalRevert(false, "Target contract does not contain code");
|
||||
existenceChecked = true;
|
||||
}
|
||||
@ -2735,7 +2735,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
|
||||
m_context << dupInstruction(m_context.baseToCurrentStackOffset(gasStackPos));
|
||||
else if (m_context.evmVersion().canOverchargeGasForCall())
|
||||
// Send all gas (requires tangerine whistle EVM)
|
||||
m_context << Instruction::GAS;
|
||||
m_context << InternalInstruction::GAS;
|
||||
else
|
||||
{
|
||||
// send all gas except the amount needed to execute "SUB" and "CALL"
|
||||
@ -2745,15 +2745,15 @@ void ExpressionCompiler::appendExternalFunctionCall(
|
||||
gasNeededByCaller += evmasm::GasCosts::callValueTransferGas;
|
||||
if (!existenceChecked)
|
||||
gasNeededByCaller += evmasm::GasCosts::callNewAccountGas; // we never know
|
||||
m_context << gasNeededByCaller << Instruction::GAS << Instruction::SUB;
|
||||
m_context << gasNeededByCaller << InternalInstruction::GAS << InternalInstruction::SUB;
|
||||
}
|
||||
// Order is important here, STATICCALL might overlap with DELEGATECALL.
|
||||
if (isDelegateCall)
|
||||
m_context << Instruction::DELEGATECALL;
|
||||
m_context << InternalInstruction::DELEGATECALL;
|
||||
else if (useStaticCall)
|
||||
m_context << Instruction::STATICCALL;
|
||||
m_context << InternalInstruction::STATICCALL;
|
||||
else
|
||||
m_context << Instruction::CALL;
|
||||
m_context << InternalInstruction::CALL;
|
||||
|
||||
unsigned remainsSize =
|
||||
2u + // contract address, input_memory_end
|
||||
@ -2766,7 +2766,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
|
||||
if (!returnSuccessConditionAndReturndata && !_tryCall)
|
||||
{
|
||||
// Propagate error condition (if CALL pushes 0 on stack).
|
||||
m_context << Instruction::ISZERO;
|
||||
m_context << InternalInstruction::ISZERO;
|
||||
m_context.appendConditionalRevert(true);
|
||||
}
|
||||
else
|
||||
@ -2777,9 +2777,9 @@ void ExpressionCompiler::appendExternalFunctionCall(
|
||||
|
||||
if (_tryCall)
|
||||
{
|
||||
m_context << Instruction::DUP1 << Instruction::ISZERO;
|
||||
m_context << InternalInstruction::DUP1 << InternalInstruction::ISZERO;
|
||||
m_context.appendConditionalJumpTo(endTag);
|
||||
m_context << Instruction::POP;
|
||||
m_context << InternalInstruction::POP;
|
||||
}
|
||||
|
||||
if (returnSuccessConditionAndReturndata)
|
||||
@ -2804,7 +2804,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
|
||||
// Failing ecrecover cannot be detected, so we clear output before the call.
|
||||
m_context << u256(32);
|
||||
utils().fetchFreeMemoryPointer();
|
||||
m_context << Instruction::SUB << Instruction::MLOAD;
|
||||
m_context << InternalInstruction::SUB << InternalInstruction::MLOAD;
|
||||
}
|
||||
else if (!returnTypes.empty())
|
||||
{
|
||||
@ -2832,7 +2832,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
|
||||
solAssert(retSize > 0, "");
|
||||
// Always use the actual return length, and not our calculated expected length, if returndatacopy is supported.
|
||||
// This ensures it can catch badly formatted input from external calls.
|
||||
m_context << (haveReturndatacopy ? evmasm::AssemblyItem(Instruction::RETURNDATASIZE) : u256(retSize));
|
||||
m_context << (haveReturndatacopy ? evmasm::AssemblyItem(InternalInstruction::RETURNDATASIZE) : u256(retSize));
|
||||
// Stack: return_data_start return_data_size
|
||||
if (needToUpdateFreeMemoryPtr)
|
||||
m_context.appendInlineAssembly(R"({
|
||||
|
@ -70,7 +70,7 @@ void StackVariable::storeValue(Type const&, SourceLocation const& _location, boo
|
||||
);
|
||||
else if (stackDiff > 0)
|
||||
for (unsigned i = 0; i < m_size; ++i)
|
||||
m_context << swapInstruction(stackDiff) << Instruction::POP;
|
||||
m_context << swapInstruction(stackDiff) << InternalInstruction::POP;
|
||||
if (!_move)
|
||||
retrieveValue(_location);
|
||||
}
|
||||
@ -92,11 +92,11 @@ void MemoryItem::retrieveValue(SourceLocation const&, bool _remove) const
|
||||
if (m_dataType->isValueType())
|
||||
{
|
||||
if (!_remove)
|
||||
m_context << Instruction::DUP1;
|
||||
m_context << InternalInstruction::DUP1;
|
||||
CompilerUtils(m_context).loadFromMemoryDynamic(*m_dataType, false, m_padded, false);
|
||||
}
|
||||
else
|
||||
m_context << Instruction::MLOAD;
|
||||
m_context << InternalInstruction::MLOAD;
|
||||
}
|
||||
|
||||
void MemoryItem::storeValue(Type const& _sourceType, SourceLocation const&, bool _move) const
|
||||
@ -117,13 +117,13 @@ void MemoryItem::storeValue(Type const& _sourceType, SourceLocation const&, bool
|
||||
solAssert(m_dataType->calldataEncodedSize(false) == 1, "Invalid non-padded type.");
|
||||
solAssert(m_dataType->category() != Type::Category::UserDefinedValueType, "");
|
||||
if (m_dataType->category() == Type::Category::FixedBytes)
|
||||
m_context << u256(0) << Instruction::BYTE;
|
||||
m_context << Instruction::SWAP1 << Instruction::MSTORE8;
|
||||
m_context << u256(0) << InternalInstruction::BYTE;
|
||||
m_context << InternalInstruction::SWAP1 << InternalInstruction::MSTORE8;
|
||||
}
|
||||
else
|
||||
{
|
||||
utils.storeInMemoryDynamic(*m_dataType, m_padded);
|
||||
m_context << Instruction::POP;
|
||||
m_context << InternalInstruction::POP;
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -132,10 +132,10 @@ void MemoryItem::storeValue(Type const& _sourceType, SourceLocation const&, bool
|
||||
|
||||
solAssert(m_dataType->sizeOnStack() == 1, "");
|
||||
if (!_move)
|
||||
m_context << Instruction::DUP2 << Instruction::SWAP1;
|
||||
m_context << InternalInstruction::DUP2 << InternalInstruction::SWAP1;
|
||||
// stack: [value] value lvalue
|
||||
// only store the reference
|
||||
m_context << Instruction::MSTORE;
|
||||
m_context << InternalInstruction::MSTORE;
|
||||
}
|
||||
}
|
||||
|
||||
@ -145,7 +145,7 @@ void MemoryItem::setToZero(SourceLocation const&, bool _removeReference) const
|
||||
solAssert(_removeReference, "");
|
||||
utils.pushZeroValue(*m_dataType);
|
||||
utils.storeInMemoryDynamic(*m_dataType, m_padded);
|
||||
m_context << Instruction::POP;
|
||||
m_context << InternalInstruction::POP;
|
||||
}
|
||||
|
||||
|
||||
@ -184,7 +184,7 @@ void ImmutableItem::storeValue(Type const& _sourceType, SourceLocation const&, b
|
||||
else
|
||||
utils.copyToStackTop(m_dataType->sizeOnStack() + 1, m_dataType->sizeOnStack());
|
||||
utils.storeInMemoryDynamic(*m_dataType);
|
||||
m_context << Instruction::POP;
|
||||
m_context << InternalInstruction::POP;
|
||||
}
|
||||
|
||||
void ImmutableItem::setToZero(SourceLocation const&, bool) const
|
||||
@ -218,15 +218,15 @@ void StorageItem::retrieveValue(SourceLocation const&, bool _remove) const
|
||||
{
|
||||
solAssert(m_dataType->sizeOnStack() == 1, "Invalid storage ref size.");
|
||||
if (_remove)
|
||||
m_context << Instruction::POP; // remove byte offset
|
||||
m_context << InternalInstruction::POP; // remove byte offset
|
||||
else
|
||||
m_context << Instruction::DUP2;
|
||||
m_context << InternalInstruction::DUP2;
|
||||
return;
|
||||
}
|
||||
if (!_remove)
|
||||
CompilerUtils(m_context).copyToStackTop(sizeOnStack(), sizeOnStack());
|
||||
if (m_dataType->storageBytes() == 32)
|
||||
m_context << Instruction::POP << Instruction::SLOAD;
|
||||
m_context << InternalInstruction::POP << InternalInstruction::SLOAD;
|
||||
else
|
||||
{
|
||||
Type const* type = m_dataType;
|
||||
@ -234,8 +234,8 @@ void StorageItem::retrieveValue(SourceLocation const&, bool _remove) const
|
||||
type = type->encodingType();
|
||||
bool cleaned = false;
|
||||
m_context
|
||||
<< Instruction::SWAP1 << Instruction::SLOAD << Instruction::SWAP1
|
||||
<< u256(0x100) << Instruction::EXP << Instruction::SWAP1 << Instruction::DIV;
|
||||
<< InternalInstruction::SWAP1 << InternalInstruction::SLOAD << InternalInstruction::SWAP1
|
||||
<< u256(0x100) << InternalInstruction::EXP << InternalInstruction::SWAP1 << InternalInstruction::DIV;
|
||||
if (type->category() == Type::Category::FixedPoint)
|
||||
// implementation should be very similar to the integer case.
|
||||
solUnimplemented("Not yet implemented - FixedPointType.");
|
||||
@ -248,9 +248,9 @@ void StorageItem::retrieveValue(SourceLocation const&, bool _remove) const
|
||||
}
|
||||
else if (fun->kind() == FunctionType::Kind::Internal)
|
||||
{
|
||||
m_context << Instruction::DUP1 << Instruction::ISZERO;
|
||||
m_context << InternalInstruction::DUP1 << InternalInstruction::ISZERO;
|
||||
CompilerUtils(m_context).pushZeroValue(*fun);
|
||||
m_context << Instruction::MUL << Instruction::OR;
|
||||
m_context << InternalInstruction::MUL << InternalInstruction::OR;
|
||||
}
|
||||
}
|
||||
else if (type->leftAligned())
|
||||
@ -263,14 +263,14 @@ void StorageItem::retrieveValue(SourceLocation const&, bool _remove) const
|
||||
dynamic_cast<IntegerType const&>(*type).isSigned()
|
||||
)
|
||||
{
|
||||
m_context << u256(type->storageBytes() - 1) << Instruction::SIGNEXTEND;
|
||||
m_context << u256(type->storageBytes() - 1) << InternalInstruction::SIGNEXTEND;
|
||||
cleaned = true;
|
||||
}
|
||||
|
||||
if (!cleaned)
|
||||
{
|
||||
solAssert(type->sizeOnStack() == 1, "");
|
||||
m_context << ((u256(0x1) << (8 * type->storageBytes())) - 1) << Instruction::AND;
|
||||
m_context << ((u256(0x1) << (8 * type->storageBytes())) - 1) << InternalInstruction::AND;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -289,29 +289,29 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc
|
||||
{
|
||||
solAssert(m_dataType->sizeOnStack() == 1, "Invalid stack size.");
|
||||
// offset should be zero
|
||||
m_context << Instruction::POP;
|
||||
m_context << InternalInstruction::POP;
|
||||
if (!_move)
|
||||
m_context << Instruction::DUP2 << Instruction::SWAP1;
|
||||
m_context << InternalInstruction::DUP2 << InternalInstruction::SWAP1;
|
||||
|
||||
m_context << Instruction::SWAP1;
|
||||
m_context << InternalInstruction::SWAP1;
|
||||
utils.convertType(_sourceType, *m_dataType, true);
|
||||
m_context << Instruction::SWAP1;
|
||||
m_context << InternalInstruction::SWAP1;
|
||||
|
||||
m_context << Instruction::SSTORE;
|
||||
m_context << InternalInstruction::SSTORE;
|
||||
}
|
||||
else
|
||||
{
|
||||
// OR the value into the other values in the storage slot
|
||||
m_context << u256(0x100) << Instruction::EXP;
|
||||
m_context << u256(0x100) << InternalInstruction::EXP;
|
||||
// stack: value storage_ref multiplier
|
||||
// fetch old value
|
||||
m_context << Instruction::DUP2 << Instruction::SLOAD;
|
||||
m_context << InternalInstruction::DUP2 << InternalInstruction::SLOAD;
|
||||
// stack: value storage_ref multiplier old_full_value
|
||||
// clear bytes in old value
|
||||
m_context
|
||||
<< Instruction::DUP2 << ((u256(1) << (8 * m_dataType->storageBytes())) - 1)
|
||||
<< Instruction::MUL;
|
||||
m_context << Instruction::NOT << Instruction::AND << Instruction::SWAP1;
|
||||
<< InternalInstruction::DUP2 << ((u256(1) << (8 * m_dataType->storageBytes())) - 1)
|
||||
<< InternalInstruction::MUL;
|
||||
m_context << InternalInstruction::NOT << InternalInstruction::AND << InternalInstruction::SWAP1;
|
||||
// stack: value storage_ref cleared_value multiplier
|
||||
utils.copyToStackTop(3 + m_dataType->sizeOnStack(), m_dataType->sizeOnStack());
|
||||
// stack: value storage_ref cleared_value multiplier value
|
||||
@ -333,7 +333,7 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc
|
||||
solAssert(fun->sizeOnStack() == 1, "");
|
||||
m_context <<
|
||||
((u256(1) << (8 * m_dataType->storageBytes())) - 1) <<
|
||||
Instruction::AND;
|
||||
InternalInstruction::AND;
|
||||
}
|
||||
}
|
||||
else if (m_dataType->leftAligned())
|
||||
@ -350,9 +350,9 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc
|
||||
// remove the higher order bits
|
||||
utils.convertType(_sourceType, *m_dataType, true, true);
|
||||
}
|
||||
m_context << Instruction::MUL << Instruction::OR;
|
||||
m_context << InternalInstruction::MUL << InternalInstruction::OR;
|
||||
// stack: value storage_ref updated_value
|
||||
m_context << Instruction::SWAP1 << Instruction::SSTORE;
|
||||
m_context << InternalInstruction::SWAP1 << InternalInstruction::SSTORE;
|
||||
if (_move)
|
||||
utils.popStackElement(*m_dataType);
|
||||
}
|
||||
@ -365,19 +365,19 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc
|
||||
);
|
||||
if (m_dataType->category() == Type::Category::Array)
|
||||
{
|
||||
m_context << Instruction::POP; // remove byte offset
|
||||
m_context << InternalInstruction::POP; // remove byte offset
|
||||
ArrayUtils(m_context).copyArrayToStorage(
|
||||
dynamic_cast<ArrayType const&>(*m_dataType),
|
||||
dynamic_cast<ArrayType const&>(_sourceType)
|
||||
);
|
||||
if (_move)
|
||||
m_context << Instruction::POP;
|
||||
m_context << InternalInstruction::POP;
|
||||
}
|
||||
else if (m_dataType->category() == Type::Category::Struct)
|
||||
{
|
||||
// stack layout: source_ref target_ref target_offset
|
||||
// note that we have structs, so offset should be zero and are ignored
|
||||
m_context << Instruction::POP;
|
||||
m_context << InternalInstruction::POP;
|
||||
auto const& structType = dynamic_cast<StructType const&>(*m_dataType);
|
||||
auto const& sourceType = dynamic_cast<StructType const&>(_sourceType);
|
||||
solAssert(
|
||||
@ -389,7 +389,7 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc
|
||||
{
|
||||
solAssert(sourceType.sizeOnStack() == 1, "");
|
||||
solAssert(structType.sizeOnStack() == 1, "");
|
||||
m_context << Instruction::DUP2 << Instruction::DUP2;
|
||||
m_context << InternalInstruction::DUP2 << InternalInstruction::DUP2;
|
||||
m_context.callYulFunction(m_context.utilFunctions().updateStorageValueFunction(sourceType, structType, 0), 2, 0);
|
||||
}
|
||||
else
|
||||
@ -404,7 +404,7 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc
|
||||
{
|
||||
// stack layout: source_ref target_ref
|
||||
pair<u256, unsigned> const& offsets = sourceType.storageOffsetsOfMember(member.name);
|
||||
m_context << offsets.first << Instruction::DUP3 << Instruction::ADD;
|
||||
m_context << offsets.first << InternalInstruction::DUP3 << InternalInstruction::ADD;
|
||||
m_context << u256(offsets.second);
|
||||
// stack: source_ref target_ref source_member_ref source_member_off
|
||||
StorageItem(m_context, *sourceMemberType).retrieveValue(_location, true);
|
||||
@ -415,13 +415,13 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc
|
||||
solAssert(sourceType.location() == DataLocation::Memory, "");
|
||||
// stack layout: source_ref target_ref
|
||||
m_context << sourceType.memoryOffsetOfMember(member.name);
|
||||
m_context << Instruction::DUP3 << Instruction::ADD;
|
||||
m_context << InternalInstruction::DUP3 << InternalInstruction::ADD;
|
||||
MemoryItem(m_context, *sourceMemberType).retrieveValue(_location, true);
|
||||
// stack layout: source_ref target_ref source_value...
|
||||
}
|
||||
unsigned stackSize = sourceMemberType->sizeOnStack();
|
||||
pair<u256, unsigned> const& offsets = structType.storageOffsetsOfMember(member.name);
|
||||
m_context << dupInstruction(1 + stackSize) << offsets.first << Instruction::ADD;
|
||||
m_context << dupInstruction(1 + stackSize) << offsets.first << InternalInstruction::ADD;
|
||||
m_context << u256(offsets.second);
|
||||
// stack: source_ref target_ref target_off source_value... target_member_ref target_member_byte_off
|
||||
StorageItem(m_context, *memberType).storeValue(*sourceMemberType, _location, true);
|
||||
@ -432,7 +432,7 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc
|
||||
if (_move)
|
||||
utils.popStackSlots(2);
|
||||
else
|
||||
m_context << Instruction::SWAP1 << Instruction::POP;
|
||||
m_context << InternalInstruction::SWAP1 << InternalInstruction::POP;
|
||||
}
|
||||
else
|
||||
BOOST_THROW_EXCEPTION(
|
||||
@ -464,12 +464,12 @@ void StorageItem::setToZero(SourceLocation const&, bool _removeReference) const
|
||||
continue;
|
||||
pair<u256, unsigned> const& offsets = structType.storageOffsetsOfMember(member.name);
|
||||
m_context
|
||||
<< offsets.first << Instruction::DUP3 << Instruction::ADD
|
||||
<< offsets.first << InternalInstruction::DUP3 << InternalInstruction::ADD
|
||||
<< u256(offsets.second);
|
||||
StorageItem(m_context, *memberType).setToZero();
|
||||
}
|
||||
if (_removeReference)
|
||||
m_context << Instruction::POP << Instruction::POP;
|
||||
m_context << InternalInstruction::POP << InternalInstruction::POP;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -480,23 +480,23 @@ void StorageItem::setToZero(SourceLocation const&, bool _removeReference) const
|
||||
{
|
||||
// offset should be zero
|
||||
m_context
|
||||
<< Instruction::POP << u256(0)
|
||||
<< Instruction::SWAP1 << Instruction::SSTORE;
|
||||
<< InternalInstruction::POP << u256(0)
|
||||
<< InternalInstruction::SWAP1 << InternalInstruction::SSTORE;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_context << u256(0x100) << Instruction::EXP;
|
||||
m_context << u256(0x100) << InternalInstruction::EXP;
|
||||
// stack: storage_ref multiplier
|
||||
// fetch old value
|
||||
m_context << Instruction::DUP2 << Instruction::SLOAD;
|
||||
m_context << InternalInstruction::DUP2 << InternalInstruction::SLOAD;
|
||||
// stack: storage_ref multiplier old_full_value
|
||||
// clear bytes in old value
|
||||
m_context
|
||||
<< Instruction::SWAP1 << ((u256(1) << (8 * m_dataType->storageBytes())) - 1)
|
||||
<< Instruction::MUL;
|
||||
m_context << Instruction::NOT << Instruction::AND;
|
||||
<< InternalInstruction::SWAP1 << ((u256(1) << (8 * m_dataType->storageBytes())) - 1)
|
||||
<< InternalInstruction::MUL;
|
||||
m_context << InternalInstruction::NOT << InternalInstruction::AND;
|
||||
// stack: storage_ref cleared_value
|
||||
m_context << Instruction::SWAP1 << Instruction::SSTORE;
|
||||
m_context << InternalInstruction::SWAP1 << InternalInstruction::SSTORE;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -510,47 +510,47 @@ void StorageByteArrayElement::retrieveValue(SourceLocation const&, bool _remove)
|
||||
{
|
||||
// stack: ref byte_number
|
||||
if (_remove)
|
||||
m_context << Instruction::SWAP1 << Instruction::SLOAD
|
||||
<< Instruction::SWAP1 << Instruction::BYTE;
|
||||
m_context << InternalInstruction::SWAP1 << InternalInstruction::SLOAD
|
||||
<< InternalInstruction::SWAP1 << InternalInstruction::BYTE;
|
||||
else
|
||||
m_context << Instruction::DUP2 << Instruction::SLOAD
|
||||
<< Instruction::DUP2 << Instruction::BYTE;
|
||||
m_context << (u256(1) << (256 - 8)) << Instruction::MUL;
|
||||
m_context << InternalInstruction::DUP2 << InternalInstruction::SLOAD
|
||||
<< InternalInstruction::DUP2 << InternalInstruction::BYTE;
|
||||
m_context << (u256(1) << (256 - 8)) << InternalInstruction::MUL;
|
||||
}
|
||||
|
||||
void StorageByteArrayElement::storeValue(Type const&, SourceLocation const&, bool _move) const
|
||||
{
|
||||
// stack: value ref byte_number
|
||||
m_context << u256(31) << Instruction::SUB << u256(0x100) << Instruction::EXP;
|
||||
m_context << u256(31) << InternalInstruction::SUB << u256(0x100) << InternalInstruction::EXP;
|
||||
// stack: value ref (1<<(8*(31-byte_number)))
|
||||
m_context << Instruction::DUP2 << Instruction::SLOAD;
|
||||
m_context << InternalInstruction::DUP2 << InternalInstruction::SLOAD;
|
||||
// stack: value ref (1<<(8*(31-byte_number))) old_full_value
|
||||
// clear byte in old value
|
||||
m_context << Instruction::DUP2 << u256(0xff) << Instruction::MUL
|
||||
<< Instruction::NOT << Instruction::AND;
|
||||
m_context << InternalInstruction::DUP2 << u256(0xff) << InternalInstruction::MUL
|
||||
<< InternalInstruction::NOT << InternalInstruction::AND;
|
||||
// stack: value ref (1<<(32-byte_number)) old_full_value_with_cleared_byte
|
||||
m_context << Instruction::SWAP1;
|
||||
m_context << (u256(1) << (256 - 8)) << Instruction::DUP5 << Instruction::DIV
|
||||
<< Instruction::MUL << Instruction::OR;
|
||||
m_context << InternalInstruction::SWAP1;
|
||||
m_context << (u256(1) << (256 - 8)) << InternalInstruction::DUP5 << InternalInstruction::DIV
|
||||
<< InternalInstruction::MUL << InternalInstruction::OR;
|
||||
// stack: value ref new_full_value
|
||||
m_context << Instruction::SWAP1 << Instruction::SSTORE;
|
||||
m_context << InternalInstruction::SWAP1 << InternalInstruction::SSTORE;
|
||||
if (_move)
|
||||
m_context << Instruction::POP;
|
||||
m_context << InternalInstruction::POP;
|
||||
}
|
||||
|
||||
void StorageByteArrayElement::setToZero(SourceLocation const&, bool _removeReference) const
|
||||
{
|
||||
// stack: ref byte_number
|
||||
solAssert(_removeReference, "");
|
||||
m_context << u256(31) << Instruction::SUB << u256(0x100) << Instruction::EXP;
|
||||
m_context << u256(31) << InternalInstruction::SUB << u256(0x100) << InternalInstruction::EXP;
|
||||
// stack: ref (1<<(8*(31-byte_number)))
|
||||
m_context << Instruction::DUP2 << Instruction::SLOAD;
|
||||
m_context << InternalInstruction::DUP2 << InternalInstruction::SLOAD;
|
||||
// stack: ref (1<<(8*(31-byte_number))) old_full_value
|
||||
// clear byte in old value
|
||||
m_context << Instruction::SWAP1 << u256(0xff) << Instruction::MUL;
|
||||
m_context << Instruction::NOT << Instruction::AND;
|
||||
m_context << InternalInstruction::SWAP1 << u256(0xff) << InternalInstruction::MUL;
|
||||
m_context << InternalInstruction::NOT << InternalInstruction::AND;
|
||||
// stack: ref old_full_value_with_cleared_byte
|
||||
m_context << Instruction::SWAP1 << Instruction::SSTORE;
|
||||
m_context << InternalInstruction::SWAP1 << InternalInstruction::SSTORE;
|
||||
}
|
||||
|
||||
TupleObject::TupleObject(
|
||||
|
@ -56,26 +56,26 @@ GasEstimator::GasConsumption GasEstimator::functionalEstimation(
|
||||
using Id = ExpressionClasses::Id;
|
||||
using Ids = vector<Id>;
|
||||
Id hashValue = classes.find(u256(util::selectorFromSignatureU32(_signature)));
|
||||
Id calldata = classes.find(Instruction::CALLDATALOAD, Ids{classes.find(u256(0))});
|
||||
Id calldata = classes.find(InternalInstruction::CALLDATALOAD, Ids{classes.find(u256(0))});
|
||||
if (!m_evmVersion.hasBitwiseShifting())
|
||||
// div(calldataload(0), 1 << 224) equals to hashValue
|
||||
classes.forceEqual(
|
||||
hashValue,
|
||||
Instruction::DIV,
|
||||
InternalInstruction::DIV,
|
||||
Ids{calldata, classes.find(u256(1) << 224)}
|
||||
);
|
||||
else
|
||||
// shr(0xe0, calldataload(0)) equals to hashValue
|
||||
classes.forceEqual(
|
||||
hashValue,
|
||||
Instruction::SHR,
|
||||
InternalInstruction::SHR,
|
||||
Ids{classes.find(u256(0xe0)), calldata}
|
||||
);
|
||||
// lt(calldatasize(), 4) equals to 0 (ignore the shortcut for fallback functions)
|
||||
classes.forceEqual(
|
||||
classes.find(u256(0)),
|
||||
Instruction::LT,
|
||||
Ids{classes.find(Instruction::CALLDATASIZE), classes.find(u256(4))}
|
||||
InternalInstruction::LT,
|
||||
Ids{classes.find(InternalInstruction::CALLDATASIZE), classes.find(u256(4))}
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -702,7 +702,7 @@ bool AsmAnalyzer::validateInstructions(std::string const& _instructionIdentifier
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AsmAnalyzer::validateInstructions(evmasm::Instruction _instr, SourceLocation const& _location)
|
||||
bool AsmAnalyzer::validateInstructions(evmasm::InternalInstruction _instr, SourceLocation const& _location)
|
||||
{
|
||||
// We assume that returndatacopy, returndatasize and staticcall are either all available
|
||||
// or all not available.
|
||||
@ -712,9 +712,9 @@ bool AsmAnalyzer::validateInstructions(evmasm::Instruction _instr, SourceLocatio
|
||||
|
||||
// These instructions are disabled in the dialect.
|
||||
yulAssert(
|
||||
_instr != evmasm::Instruction::JUMP &&
|
||||
_instr != evmasm::Instruction::JUMPI &&
|
||||
_instr != evmasm::Instruction::JUMPDEST,
|
||||
_instr != evmasm::InternalInstruction::JUMP &&
|
||||
_instr != evmasm::InternalInstruction::JUMPI &&
|
||||
_instr != evmasm::InternalInstruction::JUMPDEST,
|
||||
"");
|
||||
|
||||
bool returnValue = true;
|
||||
@ -733,29 +733,29 @@ bool AsmAnalyzer::validateInstructions(evmasm::Instruction _instr, SourceLocatio
|
||||
returnValue = false;
|
||||
};
|
||||
|
||||
if (_instr == evmasm::Instruction::RETURNDATACOPY && !m_evmVersion.supportsReturndata())
|
||||
if (_instr == evmasm::InternalInstruction::RETURNDATACOPY && !m_evmVersion.supportsReturndata())
|
||||
errorForVM(7756_error, "only available for Byzantium-compatible");
|
||||
else if (_instr == evmasm::Instruction::RETURNDATASIZE && !m_evmVersion.supportsReturndata())
|
||||
else if (_instr == evmasm::InternalInstruction::RETURNDATASIZE && !m_evmVersion.supportsReturndata())
|
||||
errorForVM(4778_error, "only available for Byzantium-compatible");
|
||||
else if (_instr == evmasm::Instruction::STATICCALL && !m_evmVersion.hasStaticCall())
|
||||
else if (_instr == evmasm::InternalInstruction::STATICCALL && !m_evmVersion.hasStaticCall())
|
||||
errorForVM(1503_error, "only available for Byzantium-compatible");
|
||||
else if (_instr == evmasm::Instruction::SHL && !m_evmVersion.hasBitwiseShifting())
|
||||
else if (_instr == evmasm::InternalInstruction::SHL && !m_evmVersion.hasBitwiseShifting())
|
||||
errorForVM(6612_error, "only available for Constantinople-compatible");
|
||||
else if (_instr == evmasm::Instruction::SHR && !m_evmVersion.hasBitwiseShifting())
|
||||
else if (_instr == evmasm::InternalInstruction::SHR && !m_evmVersion.hasBitwiseShifting())
|
||||
errorForVM(7458_error, "only available for Constantinople-compatible");
|
||||
else if (_instr == evmasm::Instruction::SAR && !m_evmVersion.hasBitwiseShifting())
|
||||
else if (_instr == evmasm::InternalInstruction::SAR && !m_evmVersion.hasBitwiseShifting())
|
||||
errorForVM(2054_error, "only available for Constantinople-compatible");
|
||||
else if (_instr == evmasm::Instruction::CREATE2 && !m_evmVersion.hasCreate2())
|
||||
else if (_instr == evmasm::InternalInstruction::CREATE2 && !m_evmVersion.hasCreate2())
|
||||
errorForVM(6166_error, "only available for Constantinople-compatible");
|
||||
else if (_instr == evmasm::Instruction::EXTCODEHASH && !m_evmVersion.hasExtCodeHash())
|
||||
else if (_instr == evmasm::InternalInstruction::EXTCODEHASH && !m_evmVersion.hasExtCodeHash())
|
||||
errorForVM(7110_error, "only available for Constantinople-compatible");
|
||||
else if (_instr == evmasm::Instruction::CHAINID && !m_evmVersion.hasChainID())
|
||||
else if (_instr == evmasm::InternalInstruction::CHAINID && !m_evmVersion.hasChainID())
|
||||
errorForVM(1561_error, "only available for Istanbul-compatible");
|
||||
else if (_instr == evmasm::Instruction::SELFBALANCE && !m_evmVersion.hasSelfBalance())
|
||||
else if (_instr == evmasm::InternalInstruction::SELFBALANCE && !m_evmVersion.hasSelfBalance())
|
||||
errorForVM(7721_error, "only available for Istanbul-compatible");
|
||||
else if (_instr == evmasm::Instruction::BASEFEE && !m_evmVersion.hasBaseFee())
|
||||
else if (_instr == evmasm::InternalInstruction::BASEFEE && !m_evmVersion.hasBaseFee())
|
||||
errorForVM(5430_error, "only available for London-compatible");
|
||||
else if (_instr == evmasm::Instruction::PC)
|
||||
else if (_instr == evmasm::InternalInstruction::PC)
|
||||
m_errorReporter.error(
|
||||
2450_error,
|
||||
Error::Type::SyntaxError,
|
||||
|
@ -114,7 +114,7 @@ private:
|
||||
void expectValidType(YulString _type, langutil::SourceLocation const& _location);
|
||||
void expectType(YulString _expectedType, YulString _givenType, langutil::SourceLocation const& _location);
|
||||
|
||||
bool validateInstructions(evmasm::Instruction _instr, langutil::SourceLocation const& _location);
|
||||
bool validateInstructions(evmasm::InternalInstruction _instr, langutil::SourceLocation const& _location);
|
||||
bool validateInstructions(std::string const& _instrIdentifier, langutil::SourceLocation const& _location);
|
||||
bool validateInstructions(FunctionCall const& _functionCall);
|
||||
|
||||
|
@ -40,7 +40,7 @@ struct SourceLocation;
|
||||
|
||||
namespace solidity::evmasm
|
||||
{
|
||||
enum class Instruction: uint8_t;
|
||||
enum class InternalInstruction: uint8_t;
|
||||
}
|
||||
|
||||
namespace solidity::yul
|
||||
@ -66,7 +66,7 @@ public:
|
||||
virtual int stackHeight() const = 0;
|
||||
virtual void setStackHeight(int height) = 0;
|
||||
/// Append an EVM instruction.
|
||||
virtual void appendInstruction(evmasm::Instruction _instruction) = 0;
|
||||
virtual void appendInstruction(evmasm::InternalInstruction _instruction) = 0;
|
||||
/// Append a constant.
|
||||
virtual void appendConstant(u256 const& _constant) = 0;
|
||||
/// Append a label.
|
||||
|
@ -48,24 +48,24 @@ struct MiniEVMInterpreter
|
||||
return std::visit(*this, _expr);
|
||||
}
|
||||
|
||||
u256 eval(evmasm::Instruction _instr, vector<Expression> const& _arguments)
|
||||
u256 eval(evmasm::InternalInstruction _instr, vector<Expression> const& _arguments)
|
||||
{
|
||||
vector<u256> args;
|
||||
for (auto const& arg: _arguments)
|
||||
args.emplace_back(eval(arg));
|
||||
switch (_instr)
|
||||
{
|
||||
case evmasm::Instruction::ADD:
|
||||
case evmasm::InternalInstruction::ADD:
|
||||
return args.at(0) + args.at(1);
|
||||
case evmasm::Instruction::SUB:
|
||||
case evmasm::InternalInstruction::SUB:
|
||||
return args.at(0) - args.at(1);
|
||||
case evmasm::Instruction::MUL:
|
||||
case evmasm::InternalInstruction::MUL:
|
||||
return args.at(0) * args.at(1);
|
||||
case evmasm::Instruction::EXP:
|
||||
case evmasm::InternalInstruction::EXP:
|
||||
return exp256(args.at(0), args.at(1));
|
||||
case evmasm::Instruction::SHL:
|
||||
case evmasm::InternalInstruction::SHL:
|
||||
return args.at(0) > 255 ? 0 : (args.at(1) << unsigned(args.at(0)));
|
||||
case evmasm::Instruction::NOT:
|
||||
case evmasm::InternalInstruction::NOT:
|
||||
return ~args.at(0);
|
||||
default:
|
||||
yulAssert(false, "Invalid operation generated in constant optimizer.");
|
||||
|
@ -118,7 +118,7 @@ void CodeTransform::freeUnusedVariables(bool _popUnusedSlotsAtStackTop)
|
||||
while (m_unusedStackSlots.count(m_assembly.stackHeight() - 1))
|
||||
{
|
||||
yulAssert(m_unusedStackSlots.erase(m_assembly.stackHeight() - 1), "");
|
||||
m_assembly.appendInstruction(evmasm::Instruction::POP);
|
||||
m_assembly.appendInstruction(evmasm::InternalInstruction::POP);
|
||||
}
|
||||
}
|
||||
|
||||
@ -168,7 +168,7 @@ void CodeTransform::operator()(VariableDeclaration const& _varDecl)
|
||||
if (atTopOfStack)
|
||||
{
|
||||
m_context->variableStackHeights.erase(&var);
|
||||
m_assembly.appendInstruction(evmasm::Instruction::POP);
|
||||
m_assembly.appendInstruction(evmasm::InternalInstruction::POP);
|
||||
}
|
||||
else
|
||||
m_variablesScheduledForDeletion.insert(&var);
|
||||
@ -186,7 +186,7 @@ void CodeTransform::operator()(VariableDeclaration const& _varDecl)
|
||||
m_context->variableStackHeights[&var] = slot;
|
||||
if (size_t heightDiff = variableHeightDiff(var, varName, true))
|
||||
m_assembly.appendInstruction(evmasm::swapInstruction(static_cast<unsigned>(heightDiff - 1)));
|
||||
m_assembly.appendInstruction(evmasm::Instruction::POP);
|
||||
m_assembly.appendInstruction(evmasm::InternalInstruction::POP);
|
||||
break;
|
||||
}
|
||||
if (!foundUnusedSlot)
|
||||
@ -197,10 +197,10 @@ void CodeTransform::operator()(VariableDeclaration const& _varDecl)
|
||||
|
||||
void CodeTransform::stackError(StackTooDeepError _error, int _targetStackHeight)
|
||||
{
|
||||
m_assembly.appendInstruction(evmasm::Instruction::INVALID);
|
||||
m_assembly.appendInstruction(evmasm::InternalInstruction::INVALID);
|
||||
// Correct the stack.
|
||||
while (m_assembly.stackHeight() > _targetStackHeight)
|
||||
m_assembly.appendInstruction(evmasm::Instruction::POP);
|
||||
m_assembly.appendInstruction(evmasm::InternalInstruction::POP);
|
||||
while (m_assembly.stackHeight() < _targetStackHeight)
|
||||
m_assembly.appendConstant(u256(0));
|
||||
// Store error.
|
||||
@ -303,7 +303,7 @@ void CodeTransform::operator()(If const& _if)
|
||||
{
|
||||
visitExpression(*_if.condition);
|
||||
m_assembly.setSourceLocation(originLocationOf(_if));
|
||||
m_assembly.appendInstruction(evmasm::Instruction::ISZERO);
|
||||
m_assembly.appendInstruction(evmasm::InternalInstruction::ISZERO);
|
||||
AbstractAssembly::LabelID end = m_assembly.newLabelId();
|
||||
m_assembly.appendJumpToIf(end);
|
||||
(*this)(_if.body);
|
||||
@ -327,7 +327,7 @@ void CodeTransform::operator()(Switch const& _switch)
|
||||
caseBodies[&c] = bodyLabel;
|
||||
yulAssert(m_assembly.stackHeight() == expressionHeight + 1, "");
|
||||
m_assembly.appendInstruction(evmasm::dupInstruction(2));
|
||||
m_assembly.appendInstruction(evmasm::Instruction::EQ);
|
||||
m_assembly.appendInstruction(evmasm::InternalInstruction::EQ);
|
||||
m_assembly.appendJumpToIf(bodyLabel);
|
||||
}
|
||||
else
|
||||
@ -353,7 +353,7 @@ void CodeTransform::operator()(Switch const& _switch)
|
||||
|
||||
m_assembly.setSourceLocation(originLocationOf(_switch));
|
||||
m_assembly.appendLabel(end);
|
||||
m_assembly.appendInstruction(evmasm::Instruction::POP);
|
||||
m_assembly.appendInstruction(evmasm::InternalInstruction::POP);
|
||||
}
|
||||
|
||||
void CodeTransform::operator()(FunctionDefinition const& _function)
|
||||
@ -471,7 +471,7 @@ void CodeTransform::operator()(FunctionDefinition const& _function)
|
||||
while (!stackLayout.empty() && stackLayout.back() != static_cast<int>(stackLayout.size() - 1))
|
||||
if (stackLayout.back() < 0)
|
||||
{
|
||||
m_assembly.appendInstruction(evmasm::Instruction::POP);
|
||||
m_assembly.appendInstruction(evmasm::InternalInstruction::POP);
|
||||
stackLayout.pop_back();
|
||||
}
|
||||
else
|
||||
@ -508,7 +508,7 @@ void CodeTransform::operator()(ForLoop const& _forLoop)
|
||||
|
||||
visitExpression(*_forLoop.condition);
|
||||
m_assembly.setSourceLocation(originLocationOf(_forLoop));
|
||||
m_assembly.appendInstruction(evmasm::Instruction::ISZERO);
|
||||
m_assembly.appendInstruction(evmasm::InternalInstruction::ISZERO);
|
||||
m_assembly.appendJumpToIf(loopEnd);
|
||||
|
||||
int const stackHeightBody = m_assembly.stackHeight();
|
||||
@ -533,7 +533,7 @@ int CodeTransform::appendPopUntil(int _targetDepth)
|
||||
{
|
||||
int const stackDiffAfter = m_assembly.stackHeight() - _targetDepth;
|
||||
for (int i = 0; i < stackDiffAfter; ++i)
|
||||
m_assembly.appendInstruction(evmasm::Instruction::POP);
|
||||
m_assembly.appendInstruction(evmasm::InternalInstruction::POP);
|
||||
return stackDiffAfter;
|
||||
}
|
||||
|
||||
@ -733,7 +733,7 @@ void CodeTransform::finalizeBlock(Block const& _block, optional<int> blockStartS
|
||||
yulAssert(!m_context->variableReferences.count(&var), "");
|
||||
}
|
||||
else
|
||||
m_assembly.appendInstruction(evmasm::Instruction::POP);
|
||||
m_assembly.appendInstruction(evmasm::InternalInstruction::POP);
|
||||
}
|
||||
|
||||
if (blockStartStackHeight)
|
||||
@ -758,7 +758,7 @@ void CodeTransform::generateAssignment(Identifier const& _variableName)
|
||||
Scope::Variable const& _var = std::get<Scope::Variable>(*var);
|
||||
if (size_t heightDiff = variableHeightDiff(_var, _variableName.name, true))
|
||||
m_assembly.appendInstruction(evmasm::swapInstruction(static_cast<unsigned>(heightDiff - 1)));
|
||||
m_assembly.appendInstruction(evmasm::Instruction::POP);
|
||||
m_assembly.appendInstruction(evmasm::InternalInstruction::POP);
|
||||
decreaseReference(_variableName.name, _var);
|
||||
}
|
||||
else
|
||||
|
@ -48,7 +48,7 @@ namespace
|
||||
|
||||
pair<YulString, BuiltinFunctionForEVM> createEVMFunction(
|
||||
string const& _name,
|
||||
evmasm::Instruction _instruction
|
||||
evmasm::InternalInstruction _instruction
|
||||
)
|
||||
{
|
||||
evmasm::InstructionInfo info = evmasm::instructionInfo(_instruction);
|
||||
@ -71,7 +71,7 @@ pair<YulString, BuiltinFunctionForEVM> createEVMFunction(
|
||||
f.controlFlowSideEffects.canRevert = false;
|
||||
}
|
||||
}
|
||||
f.isMSize = _instruction == evmasm::Instruction::MSIZE;
|
||||
f.isMSize = _instruction == evmasm::InternalInstruction::MSIZE;
|
||||
f.literalArguments.clear();
|
||||
f.instruction = _instruction;
|
||||
f.generateCode = [_instruction](
|
||||
@ -114,9 +114,9 @@ set<YulString> createReservedIdentifiers(langutil::EVMVersion _evmVersion)
|
||||
{
|
||||
// TODO remove this in 0.9.0. We allow creating functions or identifiers in Yul with the name
|
||||
// basefee for VMs before london.
|
||||
auto baseFeeException = [&](evmasm::Instruction _instr) -> bool
|
||||
auto baseFeeException = [&](evmasm::InternalInstruction _instr) -> bool
|
||||
{
|
||||
return _instr == evmasm::Instruction::BASEFEE && _evmVersion < langutil::EVMVersion::london();
|
||||
return _instr == evmasm::InternalInstruction::BASEFEE && _evmVersion < langutil::EVMVersion::london();
|
||||
};
|
||||
// TODO remove this in 0.9.0. We allow creating functions or identifiers in Yul with the name
|
||||
// prevrandao for VMs before paris.
|
||||
@ -162,12 +162,12 @@ map<YulString, BuiltinFunctionForEVM> createBuiltins(langutil::EVMVersion _evmVe
|
||||
instruction = evmasm::InternalInstruction::DIFFICULTY;
|
||||
|
||||
if (
|
||||
!evmasm::isDupInstruction(opcode) &&
|
||||
!evmasm::isSwapInstruction(opcode) &&
|
||||
!evmasm::isPushInstruction(opcode) &&
|
||||
opcode != evmasm::Instruction::JUMP &&
|
||||
opcode != evmasm::Instruction::JUMPI &&
|
||||
opcode != evmasm::Instruction::JUMPDEST &&
|
||||
!evmasm::isDupInstruction(instruction) &&
|
||||
!evmasm::isSwapInstruction(instruction) &&
|
||||
!evmasm::isPushInstruction(instruction) &&
|
||||
instruction != evmasm::InternalInstruction::JUMP &&
|
||||
instruction != evmasm::InternalInstruction::JUMPI &&
|
||||
instruction != evmasm::InternalInstruction::JUMPDEST &&
|
||||
_evmVersion.hasInstruction(instruction)
|
||||
)
|
||||
builtins.emplace(createEVMFunction(name, instruction));
|
||||
@ -256,7 +256,7 @@ map<YulString, BuiltinFunctionForEVM> createBuiltins(langutil::EVMVersion _evmVe
|
||||
AbstractAssembly& _assembly,
|
||||
BuiltinContext&
|
||||
) {
|
||||
_assembly.appendInstruction(evmasm::Instruction::CODECOPY);
|
||||
_assembly.appendInstruction(evmasm::InternalInstruction::CODECOPY);
|
||||
}
|
||||
));
|
||||
builtins.emplace(createFunction(
|
||||
@ -352,7 +352,7 @@ EVMDialect const& EVMDialect::strictAssemblyForEVMObjects(langutil::EVMVersion _
|
||||
return *dialects[_version];
|
||||
}
|
||||
|
||||
SideEffects EVMDialect::sideEffectsOfInstruction(evmasm::Instruction _instruction)
|
||||
SideEffects EVMDialect::sideEffectsOfInstruction(evmasm::InternalInstruction _instruction)
|
||||
{
|
||||
auto translate = [](evmasm::SemanticInformation::Effect _e) -> SideEffects::Effect
|
||||
{
|
||||
@ -465,11 +465,11 @@ EVMDialectTyped::EVMDialectTyped(langutil::EVMVersion _evmVersion, bool _objectA
|
||||
// TODO this should use a Panic.
|
||||
// A value larger than 1 causes an invalid instruction.
|
||||
_assembly.appendConstant(2);
|
||||
_assembly.appendInstruction(evmasm::Instruction::DUP2);
|
||||
_assembly.appendInstruction(evmasm::Instruction::LT);
|
||||
_assembly.appendInstruction(evmasm::InternalInstruction::DUP2);
|
||||
_assembly.appendInstruction(evmasm::InternalInstruction::LT);
|
||||
AbstractAssembly::LabelID inRange = _assembly.newLabelId();
|
||||
_assembly.appendJumpToIf(inRange);
|
||||
_assembly.appendInstruction(evmasm::Instruction::INVALID);
|
||||
_assembly.appendInstruction(evmasm::InternalInstruction::INVALID);
|
||||
_assembly.appendLabel(inRange);
|
||||
}));
|
||||
m_functions["u256_to_bool"_yulstring].parameters = {"u256"_yulstring};
|
||||
|
@ -50,7 +50,7 @@ struct BuiltinContext
|
||||
|
||||
struct BuiltinFunctionForEVM: public BuiltinFunction
|
||||
{
|
||||
std::optional<evmasm::Instruction> instruction;
|
||||
std::optional<evmasm::InternalInstruction> instruction;
|
||||
/// Function to generate code for the given function call and append it to the abstract
|
||||
/// assembly. Expects all non-literal arguments of the call to be on stack in reverse order
|
||||
/// (i.e. right-most argument pushed first).
|
||||
@ -91,7 +91,7 @@ struct EVMDialect: public Dialect
|
||||
|
||||
bool providesObjectAccess() const { return m_objectAccess; }
|
||||
|
||||
static SideEffects sideEffectsOfInstruction(evmasm::Instruction _instruction);
|
||||
static SideEffects sideEffectsOfInstruction(evmasm::InternalInstruction _instruction);
|
||||
|
||||
protected:
|
||||
BuiltinFunctionForEVM const* verbatimFunction(size_t _arguments, size_t _returnVariables) const;
|
||||
|
@ -41,7 +41,7 @@ bigint GasMeter::costs(Expression const& _expression) const
|
||||
return combineCosts(GasMeterVisitor::costs(_expression, m_dialect, m_isCreation));
|
||||
}
|
||||
|
||||
bigint GasMeter::instructionCosts(evmasm::Instruction _instruction) const
|
||||
bigint GasMeter::instructionCosts(evmasm::InternalInstruction _instruction) const
|
||||
{
|
||||
return combineCosts(GasMeterVisitor::instructionCosts(_instruction, m_dialect, m_isCreation));
|
||||
}
|
||||
@ -64,7 +64,7 @@ pair<bigint, bigint> GasMeterVisitor::costs(
|
||||
}
|
||||
|
||||
pair<bigint, bigint> GasMeterVisitor::instructionCosts(
|
||||
evmasm::Instruction _instruction,
|
||||
evmasm::InternalInstruction _instruction,
|
||||
EVMDialect const& _dialect,
|
||||
bool _isCreation
|
||||
)
|
||||
@ -88,7 +88,7 @@ void GasMeterVisitor::operator()(FunctionCall const& _funCall)
|
||||
|
||||
void GasMeterVisitor::operator()(Literal const& _lit)
|
||||
{
|
||||
m_runGas += evmasm::GasMeter::runGas(evmasm::Instruction::PUSH1);
|
||||
m_runGas += evmasm::GasMeter::runGas(evmasm::InternalInstruction::PUSH1);
|
||||
m_dataGas +=
|
||||
singleByteDataGas() +
|
||||
evmasm::GasMeter::dataGas(
|
||||
@ -100,7 +100,7 @@ void GasMeterVisitor::operator()(Literal const& _lit)
|
||||
|
||||
void GasMeterVisitor::operator()(Identifier const&)
|
||||
{
|
||||
m_runGas += evmasm::GasMeter::runGas(evmasm::Instruction::DUP1);
|
||||
m_runGas += evmasm::GasMeter::runGas(evmasm::InternalInstruction::DUP1);
|
||||
m_dataGas += singleByteDataGas();
|
||||
}
|
||||
|
||||
@ -112,11 +112,11 @@ bigint GasMeterVisitor::singleByteDataGas() const
|
||||
return evmasm::GasCosts::createDataGas;
|
||||
}
|
||||
|
||||
void GasMeterVisitor::instructionCostsInternal(evmasm::Instruction _instruction)
|
||||
void GasMeterVisitor::instructionCostsInternal(evmasm::InternalInstruction _instruction)
|
||||
{
|
||||
if (_instruction == evmasm::Instruction::EXP)
|
||||
if (_instruction == evmasm::InternalInstruction::EXP)
|
||||
m_runGas += evmasm::GasCosts::expGas + evmasm::GasCosts::expByteGas(m_dialect.evmVersion());
|
||||
else if (_instruction == evmasm::Instruction::KECCAK256)
|
||||
else if (_instruction == evmasm::InternalInstruction::KECCAK256)
|
||||
// Assumes that Keccak-256 is computed on a single word (rounded up).
|
||||
m_runGas += evmasm::GasCosts::keccak256Gas + evmasm::GasCosts::keccak256WordGas;
|
||||
else
|
||||
|
@ -53,7 +53,7 @@ public:
|
||||
bigint costs(Expression const& _expression) const;
|
||||
/// @returns the combined costs of deploying and running the instruction, not including
|
||||
/// the costs for its arguments.
|
||||
bigint instructionCosts(evmasm::Instruction _instruction) const;
|
||||
bigint instructionCosts(evmasm::InternalInstruction _instruction) const;
|
||||
|
||||
private:
|
||||
bigint combineCosts(std::pair<bigint, bigint> _costs) const;
|
||||
@ -73,7 +73,7 @@ public:
|
||||
);
|
||||
|
||||
static std::pair<bigint, bigint> instructionCosts(
|
||||
evmasm::Instruction _instruction,
|
||||
evmasm::InternalInstruction _instruction,
|
||||
EVMDialect const& _dialect,
|
||||
bool _isCreation = false
|
||||
);
|
||||
@ -93,7 +93,7 @@ private:
|
||||
/// Computes the cost of storing and executing the single instruction (excluding its arguments).
|
||||
/// For EXP, it assumes that the exponent is at most 255.
|
||||
/// Does not work particularly exact for anything apart from arithmetic.
|
||||
void instructionCostsInternal(evmasm::Instruction _instruction);
|
||||
void instructionCostsInternal(evmasm::InternalInstruction _instruction);
|
||||
|
||||
EVMDialect const& m_dialect;
|
||||
bool m_isCreation = false;
|
||||
|
@ -59,7 +59,7 @@ void EthAssemblyAdapter::setStackHeight(int height)
|
||||
m_assembly.setDeposit(height);
|
||||
}
|
||||
|
||||
void EthAssemblyAdapter::appendInstruction(evmasm::Instruction _instruction)
|
||||
void EthAssemblyAdapter::appendInstruction(evmasm::InternalInstruction _instruction)
|
||||
{
|
||||
m_assembly.append(_instruction);
|
||||
}
|
||||
@ -101,7 +101,7 @@ void EthAssemblyAdapter::appendVerbatim(bytes _data, size_t _arguments, size_t _
|
||||
|
||||
void EthAssemblyAdapter::appendJump(int _stackDiffAfter, JumpType _jumpType)
|
||||
{
|
||||
appendJumpInstruction(evmasm::Instruction::JUMP, _jumpType);
|
||||
appendJumpInstruction(evmasm::InternalInstruction::JUMP, _jumpType);
|
||||
m_assembly.adjustDeposit(_stackDiffAfter);
|
||||
}
|
||||
|
||||
@ -114,7 +114,7 @@ void EthAssemblyAdapter::appendJumpTo(LabelID _labelId, int _stackDiffAfter, Jum
|
||||
void EthAssemblyAdapter::appendJumpToIf(LabelID _labelId, JumpType _jumpType)
|
||||
{
|
||||
appendLabelReference(_labelId);
|
||||
appendJumpInstruction(evmasm::Instruction::JUMPI, _jumpType);
|
||||
appendJumpInstruction(evmasm::InternalInstruction::JUMPI, _jumpType);
|
||||
}
|
||||
|
||||
void EthAssemblyAdapter::appendAssemblySize()
|
||||
@ -188,9 +188,9 @@ EthAssemblyAdapter::LabelID EthAssemblyAdapter::assemblyTagToIdentifier(evmasm::
|
||||
return LabelID(id);
|
||||
}
|
||||
|
||||
void EthAssemblyAdapter::appendJumpInstruction(evmasm::Instruction _instruction, JumpType _jumpType)
|
||||
void EthAssemblyAdapter::appendJumpInstruction(evmasm::InternalInstruction _instruction, JumpType _jumpType)
|
||||
{
|
||||
yulAssert(_instruction == evmasm::Instruction::JUMP || _instruction == evmasm::Instruction::JUMPI, "");
|
||||
yulAssert(_instruction == evmasm::InternalInstruction::JUMP || _instruction == evmasm::InternalInstruction::JUMPI, "");
|
||||
evmasm::AssemblyItem jump(_instruction);
|
||||
switch (_jumpType)
|
||||
{
|
||||
|
@ -43,7 +43,7 @@ public:
|
||||
void setSourceLocation(langutil::SourceLocation const& _location) override;
|
||||
int stackHeight() const override;
|
||||
void setStackHeight(int height) override;
|
||||
void appendInstruction(evmasm::Instruction _instruction) override;
|
||||
void appendInstruction(evmasm::InternalInstruction _instruction) override;
|
||||
void appendConstant(u256 const& _constant) override;
|
||||
void appendLabel(LabelID _labelId) override;
|
||||
void appendLabelReference(LabelID _labelId) override;
|
||||
@ -69,7 +69,7 @@ public:
|
||||
|
||||
private:
|
||||
static LabelID assemblyTagToIdentifier(evmasm::AssemblyItem const& _tag);
|
||||
void appendJumpInstruction(evmasm::Instruction _instruction, JumpType _jumpType);
|
||||
void appendJumpInstruction(evmasm::InternalInstruction _instruction, JumpType _jumpType);
|
||||
|
||||
evmasm::Assembly& m_assembly;
|
||||
std::map<SubID, u256> m_dataHashBySubId;
|
||||
|
@ -35,7 +35,7 @@ using namespace solidity::util;
|
||||
using namespace solidity::langutil;
|
||||
|
||||
|
||||
void NoOutputAssembly::appendInstruction(evmasm::Instruction _instr)
|
||||
void NoOutputAssembly::appendInstruction(evmasm::InternalInstruction _instr)
|
||||
{
|
||||
m_stackHeight += instructionInfo(_instr).ret - instructionInfo(_instr).args;
|
||||
}
|
||||
@ -47,7 +47,7 @@ void NoOutputAssembly::appendConstant(u256 const&)
|
||||
|
||||
void NoOutputAssembly::appendLabel(LabelID)
|
||||
{
|
||||
appendInstruction(evmasm::Instruction::JUMPDEST);
|
||||
appendInstruction(evmasm::InternalInstruction::JUMPDEST);
|
||||
}
|
||||
|
||||
void NoOutputAssembly::appendLabelReference(LabelID)
|
||||
@ -77,7 +77,7 @@ void NoOutputAssembly::appendVerbatim(bytes, size_t _arguments, size_t _returnVa
|
||||
|
||||
void NoOutputAssembly::appendJump(int _stackDiffAfter, JumpType)
|
||||
{
|
||||
appendInstruction(evmasm::Instruction::JUMP);
|
||||
appendInstruction(evmasm::InternalInstruction::JUMP);
|
||||
m_stackHeight += _stackDiffAfter;
|
||||
}
|
||||
|
||||
@ -90,12 +90,12 @@ void NoOutputAssembly::appendJumpTo(LabelID _labelId, int _stackDiffAfter, JumpT
|
||||
void NoOutputAssembly::appendJumpToIf(LabelID _labelId, JumpType)
|
||||
{
|
||||
appendLabelReference(_labelId);
|
||||
appendInstruction(evmasm::Instruction::JUMPI);
|
||||
appendInstruction(evmasm::InternalInstruction::JUMPI);
|
||||
}
|
||||
|
||||
void NoOutputAssembly::appendAssemblySize()
|
||||
{
|
||||
appendInstruction(evmasm::Instruction::PUSH1);
|
||||
appendInstruction(evmasm::InternalInstruction::PUSH1);
|
||||
}
|
||||
|
||||
pair<shared_ptr<AbstractAssembly>, AbstractAssembly::SubID> NoOutputAssembly::createSubAssembly(bool, std::string)
|
||||
@ -106,12 +106,12 @@ pair<shared_ptr<AbstractAssembly>, AbstractAssembly::SubID> NoOutputAssembly::cr
|
||||
|
||||
void NoOutputAssembly::appendDataOffset(std::vector<AbstractAssembly::SubID> const&)
|
||||
{
|
||||
appendInstruction(evmasm::Instruction::PUSH1);
|
||||
appendInstruction(evmasm::InternalInstruction::PUSH1);
|
||||
}
|
||||
|
||||
void NoOutputAssembly::appendDataSize(std::vector<AbstractAssembly::SubID> const&)
|
||||
{
|
||||
appendInstruction(evmasm::Instruction::PUSH1);
|
||||
appendInstruction(evmasm::InternalInstruction::PUSH1);
|
||||
}
|
||||
|
||||
AbstractAssembly::SubID NoOutputAssembly::appendData(bytes const&)
|
||||
@ -140,7 +140,7 @@ NoOutputEVMDialect::NoOutputEVMDialect(EVMDialect const& _copyFrom):
|
||||
{
|
||||
for (size_t i: ranges::views::iota(0u, _call.arguments.size()))
|
||||
if (!fun.second.literalArgument(i))
|
||||
_assembly.appendInstruction(evmasm::Instruction::POP);
|
||||
_assembly.appendInstruction(evmasm::InternalInstruction::POP);
|
||||
|
||||
for (size_t i = 0; i < returns; i++)
|
||||
_assembly.appendConstant(u256(0));
|
||||
|
@ -51,7 +51,7 @@ public:
|
||||
void setSourceLocation(langutil::SourceLocation const&) override {}
|
||||
int stackHeight() const override { return m_stackHeight; }
|
||||
void setStackHeight(int height) override { m_stackHeight = height; }
|
||||
void appendInstruction(evmasm::Instruction _instruction) override;
|
||||
void appendInstruction(evmasm::InternalInstruction _instruction) override;
|
||||
void appendConstant(u256 const& _constant) override;
|
||||
void appendLabel(LabelID _labelId) override;
|
||||
void appendLabelReference(LabelID _labelId) override;
|
||||
|
@ -345,14 +345,14 @@ void OptimizedEVMCodeTransform::createStackLayout(std::shared_ptr<DebugData cons
|
||||
[&](JunkSlot const&)
|
||||
{
|
||||
// Note: this will always be popped, so we can push anything.
|
||||
m_assembly.appendInstruction(evmasm::Instruction::CODESIZE);
|
||||
m_assembly.appendInstruction(evmasm::InternalInstruction::CODESIZE);
|
||||
}
|
||||
}, _slot);
|
||||
},
|
||||
// Pop callback.
|
||||
[&]()
|
||||
{
|
||||
m_assembly.appendInstruction(evmasm::Instruction::POP);
|
||||
m_assembly.appendInstruction(evmasm::InternalInstruction::POP);
|
||||
}
|
||||
);
|
||||
yulAssert(m_assembly.stackHeight() == static_cast<int>(m_stack.size()), "");
|
||||
@ -407,7 +407,7 @@ void OptimizedEVMCodeTransform::operator()(CFG::BasicBlock const& _block)
|
||||
std::visit(util::GenericVisitor{
|
||||
[&](CFG::BasicBlock::MainExit const&)
|
||||
{
|
||||
m_assembly.appendInstruction(evmasm::Instruction::STOP);
|
||||
m_assembly.appendInstruction(evmasm::InternalInstruction::STOP);
|
||||
},
|
||||
[&](CFG::BasicBlock::Jump const& _jump)
|
||||
{
|
||||
|
@ -763,7 +763,7 @@ void StackLayoutGenerator::fillInJunk(CFG::BasicBlock const& _block)
|
||||
opGas += 1000;
|
||||
}
|
||||
};
|
||||
auto pop = [&]() { opGas += evmasm::GasMeter::runGas(evmasm::Instruction::POP); };
|
||||
auto pop = [&]() { opGas += evmasm::GasMeter::runGas(evmasm::InternalInstruction::POP); };
|
||||
createStackLayout(_source, _target, swap, dupOrPush, pop);
|
||||
return opGas;
|
||||
};
|
||||
|
@ -50,7 +50,7 @@ void ExpressionSimplifier::visit(Expression& _expression)
|
||||
_expression = match->action().toExpression(debugDataOf(_expression));
|
||||
|
||||
if (auto* functionCall = get_if<FunctionCall>(&_expression))
|
||||
if (optional<evmasm::Instruction> instruction = toEVMInstruction(m_dialect, functionCall->functionName.name))
|
||||
if (optional<evmasm::InternalInstruction> instruction = toEVMInstruction(m_dialect, functionCall->functionName.name))
|
||||
for (auto op: evmasm::SemanticInformation::readWriteOperations(*instruction))
|
||||
if (op.startParameter && op.lengthParameter)
|
||||
{
|
||||
|
@ -178,7 +178,7 @@ void CodeCost::visit(Expression const& _expression)
|
||||
ASTWalker::visit(_expression);
|
||||
}
|
||||
|
||||
void CodeCost::addInstructionCost(evmasm::Instruction _instruction)
|
||||
void CodeCost::addInstructionCost(evmasm::InternalInstruction _instruction)
|
||||
{
|
||||
evmasm::Tier gasPriceTier = evmasm::instructionInfo(_instruction).gasPriceTier;
|
||||
if (gasPriceTier < evmasm::Tier::VeryLow)
|
||||
|
@ -124,7 +124,7 @@ private:
|
||||
void visit(Expression const& _expression) override;
|
||||
|
||||
private:
|
||||
void addInstructionCost(evmasm::Instruction _instruction);
|
||||
void addInstructionCost(evmasm::InternalInstruction _instruction);
|
||||
|
||||
Dialect const& m_dialect;
|
||||
size_t m_cost = 0;
|
||||
|
@ -50,7 +50,7 @@ bool yul::isRestrictedIdentifier(Dialect const& _dialect, YulString const& _iden
|
||||
return _identifier.empty() || TokenTraits::isYulKeyword(_identifier.str()) || _dialect.reservedIdentifier(_identifier);
|
||||
}
|
||||
|
||||
optional<evmasm::Instruction> yul::toEVMInstruction(Dialect const& _dialect, YulString const& _name)
|
||||
optional<evmasm::InternalInstruction> yul::toEVMInstruction(Dialect const& _dialect, YulString const& _name)
|
||||
{
|
||||
if (auto const* dialect = dynamic_cast<EVMDialect const*>(&_dialect))
|
||||
if (BuiltinFunctionForEVM const* builtin = dialect->builtin(_name))
|
||||
|
@ -31,7 +31,7 @@
|
||||
|
||||
namespace solidity::evmasm
|
||||
{
|
||||
enum class Instruction: uint8_t;
|
||||
enum class InternalInstruction: uint8_t;
|
||||
}
|
||||
|
||||
namespace solidity::yul
|
||||
@ -47,7 +47,7 @@ void removeEmptyBlocks(Block& _block);
|
||||
bool isRestrictedIdentifier(Dialect const& _dialect, YulString const& _identifier);
|
||||
|
||||
/// Helper function that returns the instruction, if the `_name` is a BuiltinFunction
|
||||
std::optional<evmasm::Instruction> toEVMInstruction(Dialect const& _dialect, YulString const& _name);
|
||||
std::optional<evmasm::InternalInstruction> toEVMInstruction(Dialect const& _dialect, YulString const& _name);
|
||||
|
||||
class StatementRemover: public ASTModifier
|
||||
{
|
||||
|
@ -109,7 +109,7 @@ ReasoningBasedSimplifier::ReasoningBasedSimplifier(
|
||||
|
||||
|
||||
smtutil::Expression ReasoningBasedSimplifier::encodeEVMBuiltin(
|
||||
evmasm::Instruction _instruction,
|
||||
evmasm::InternalInstruction _instruction,
|
||||
vector<yul::Expression> const& _arguments
|
||||
)
|
||||
{
|
||||
@ -119,19 +119,19 @@ smtutil::Expression ReasoningBasedSimplifier::encodeEVMBuiltin(
|
||||
);
|
||||
switch (_instruction)
|
||||
{
|
||||
case evmasm::Instruction::ADD:
|
||||
case evmasm::InternalInstruction::ADD:
|
||||
return wrap(arguments.at(0) + arguments.at(1));
|
||||
case evmasm::Instruction::MUL:
|
||||
case evmasm::InternalInstruction::MUL:
|
||||
return wrap(arguments.at(0) * arguments.at(1));
|
||||
case evmasm::Instruction::SUB:
|
||||
case evmasm::InternalInstruction::SUB:
|
||||
return wrap(arguments.at(0) - arguments.at(1));
|
||||
case evmasm::Instruction::DIV:
|
||||
case evmasm::InternalInstruction::DIV:
|
||||
return smtutil::Expression::ite(
|
||||
arguments.at(1) == constantValue(0),
|
||||
constantValue(0),
|
||||
arguments.at(0) / arguments.at(1)
|
||||
);
|
||||
case evmasm::Instruction::SDIV:
|
||||
case evmasm::InternalInstruction::SDIV:
|
||||
return smtutil::Expression::ite(
|
||||
arguments.at(1) == constantValue(0),
|
||||
constantValue(0),
|
||||
@ -143,13 +143,13 @@ smtutil::Expression ReasoningBasedSimplifier::encodeEVMBuiltin(
|
||||
twosComplementToSigned(arguments.at(1))
|
||||
))
|
||||
);
|
||||
case evmasm::Instruction::MOD:
|
||||
case evmasm::InternalInstruction::MOD:
|
||||
return smtutil::Expression::ite(
|
||||
arguments.at(1) == constantValue(0),
|
||||
constantValue(0),
|
||||
arguments.at(0) % arguments.at(1)
|
||||
);
|
||||
case evmasm::Instruction::SMOD:
|
||||
case evmasm::InternalInstruction::SMOD:
|
||||
return smtutil::Expression::ite(
|
||||
arguments.at(1) == constantValue(0),
|
||||
constantValue(0),
|
||||
@ -158,61 +158,61 @@ smtutil::Expression ReasoningBasedSimplifier::encodeEVMBuiltin(
|
||||
twosComplementToSigned(arguments.at(1))
|
||||
))
|
||||
);
|
||||
case evmasm::Instruction::LT:
|
||||
case evmasm::InternalInstruction::LT:
|
||||
return booleanValue(arguments.at(0) < arguments.at(1));
|
||||
case evmasm::Instruction::SLT:
|
||||
case evmasm::InternalInstruction::SLT:
|
||||
return booleanValue(twosComplementToSigned(arguments.at(0)) < twosComplementToSigned(arguments.at(1)));
|
||||
case evmasm::Instruction::GT:
|
||||
case evmasm::InternalInstruction::GT:
|
||||
return booleanValue(arguments.at(0) > arguments.at(1));
|
||||
case evmasm::Instruction::SGT:
|
||||
case evmasm::InternalInstruction::SGT:
|
||||
return booleanValue(twosComplementToSigned(arguments.at(0)) > twosComplementToSigned(arguments.at(1)));
|
||||
case evmasm::Instruction::EQ:
|
||||
case evmasm::InternalInstruction::EQ:
|
||||
return booleanValue(arguments.at(0) == arguments.at(1));
|
||||
case evmasm::Instruction::ISZERO:
|
||||
case evmasm::InternalInstruction::ISZERO:
|
||||
return booleanValue(arguments.at(0) == constantValue(0));
|
||||
case evmasm::Instruction::AND:
|
||||
case evmasm::InternalInstruction::AND:
|
||||
return smtutil::Expression::ite(
|
||||
(arguments.at(0) == 0 || arguments.at(0) == 1) &&
|
||||
(arguments.at(1) == 0 || arguments.at(1) == 1),
|
||||
booleanValue(arguments.at(0) == 1 && arguments.at(1) == 1),
|
||||
bv2int(int2bv(arguments.at(0)) & int2bv(arguments.at(1)))
|
||||
);
|
||||
case evmasm::Instruction::OR:
|
||||
case evmasm::InternalInstruction::OR:
|
||||
return smtutil::Expression::ite(
|
||||
(arguments.at(0) == 0 || arguments.at(0) == 1) &&
|
||||
(arguments.at(1) == 0 || arguments.at(1) == 1),
|
||||
booleanValue(arguments.at(0) == 1 || arguments.at(1) == 1),
|
||||
bv2int(int2bv(arguments.at(0)) | int2bv(arguments.at(1)))
|
||||
);
|
||||
case evmasm::Instruction::XOR:
|
||||
case evmasm::InternalInstruction::XOR:
|
||||
return bv2int(int2bv(arguments.at(0)) ^ int2bv(arguments.at(1)));
|
||||
case evmasm::Instruction::NOT:
|
||||
case evmasm::InternalInstruction::NOT:
|
||||
return smtutil::Expression(u256(-1)) - arguments.at(0);
|
||||
case evmasm::Instruction::SHL:
|
||||
case evmasm::InternalInstruction::SHL:
|
||||
return smtutil::Expression::ite(
|
||||
arguments.at(0) > 255,
|
||||
constantValue(0),
|
||||
bv2int(int2bv(arguments.at(1)) << int2bv(arguments.at(0)))
|
||||
);
|
||||
case evmasm::Instruction::SHR:
|
||||
case evmasm::InternalInstruction::SHR:
|
||||
return smtutil::Expression::ite(
|
||||
arguments.at(0) > 255,
|
||||
constantValue(0),
|
||||
bv2int(int2bv(arguments.at(1)) >> int2bv(arguments.at(0)))
|
||||
);
|
||||
case evmasm::Instruction::SAR:
|
||||
case evmasm::InternalInstruction::SAR:
|
||||
return smtutil::Expression::ite(
|
||||
arguments.at(0) > 255,
|
||||
constantValue(0),
|
||||
bv2int(smtutil::Expression::ashr(int2bv(arguments.at(1)), int2bv(arguments.at(0))))
|
||||
);
|
||||
case evmasm::Instruction::ADDMOD:
|
||||
case evmasm::InternalInstruction::ADDMOD:
|
||||
return smtutil::Expression::ite(
|
||||
arguments.at(2) == constantValue(0),
|
||||
constantValue(0),
|
||||
(arguments.at(0) + arguments.at(1)) % arguments.at(2)
|
||||
);
|
||||
case evmasm::Instruction::MULMOD:
|
||||
case evmasm::InternalInstruction::MULMOD:
|
||||
return smtutil::Expression::ite(
|
||||
arguments.at(2) == constantValue(0),
|
||||
constantValue(0),
|
||||
|
@ -65,7 +65,7 @@ private:
|
||||
);
|
||||
|
||||
smtutil::Expression encodeEVMBuiltin(
|
||||
evmasm::Instruction _instruction,
|
||||
evmasm::InternalInstruction _instruction,
|
||||
std::vector<Expression> const& _arguments
|
||||
) override;
|
||||
|
||||
|
@ -58,7 +58,7 @@ protected:
|
||||
/// The encoding for a builtin. The type of encoding determines what we are
|
||||
/// solving for.
|
||||
virtual smtutil::Expression encodeEVMBuiltin(
|
||||
evmasm::Instruction _instruction,
|
||||
evmasm::InternalInstruction _instruction,
|
||||
std::vector<Expression> const& _arguments
|
||||
) = 0;
|
||||
|
||||
|
@ -72,10 +72,10 @@ SimplificationRules::Rule const* SimplificationRules::findFirstMatch(
|
||||
|
||||
bool SimplificationRules::isInitialized() const
|
||||
{
|
||||
return !m_rules[uint8_t(evmasm::Instruction::ADD)].empty();
|
||||
return !m_rules[uint8_t(evmasm::InternalInstruction::ADD)].empty();
|
||||
}
|
||||
|
||||
std::optional<std::pair<evmasm::Instruction, vector<Expression> const*>>
|
||||
std::optional<std::pair<evmasm::InternalInstruction, vector<Expression> const*>>
|
||||
SimplificationRules::instructionAndArguments(Dialect const& _dialect, Expression const& _expr)
|
||||
{
|
||||
if (holds_alternative<FunctionCall>(_expr))
|
||||
@ -122,7 +122,7 @@ SimplificationRules::SimplificationRules(std::optional<langutil::EVMVersion> _ev
|
||||
assertThrow(isInitialized(), OptimizerException, "Rule list not properly initialized.");
|
||||
}
|
||||
|
||||
yul::Pattern::Pattern(evmasm::Instruction _instruction, initializer_list<Pattern> _arguments):
|
||||
yul::Pattern::Pattern(evmasm::InternalInstruction _instruction, initializer_list<Pattern> _arguments):
|
||||
m_kind(PatternKind::Operation),
|
||||
m_instruction(_instruction),
|
||||
m_arguments(_arguments)
|
||||
@ -229,7 +229,7 @@ bool Pattern::matches(
|
||||
return true;
|
||||
}
|
||||
|
||||
evmasm::Instruction Pattern::instruction() const
|
||||
evmasm::InternalInstruction Pattern::instruction() const
|
||||
{
|
||||
assertThrow(m_kind == PatternKind::Operation, OptimizerException, "");
|
||||
return m_instruction;
|
||||
|
@ -69,7 +69,7 @@ public:
|
||||
/// by the constructor, but we had some issues with static initialization.
|
||||
bool isInitialized() const;
|
||||
|
||||
static std::optional<std::pair<evmasm::Instruction, std::vector<Expression> const*>>
|
||||
static std::optional<std::pair<evmasm::InternalInstruction, std::vector<Expression> const*>>
|
||||
instructionAndArguments(Dialect const& _dialect, Expression const& _expr);
|
||||
|
||||
private:
|
||||
@ -110,7 +110,7 @@ public:
|
||||
// Matches a specific constant value.
|
||||
Pattern(u256 const& _value): m_kind(PatternKind::Constant), m_data(std::make_shared<u256>(_value)) {}
|
||||
// Matches a given instruction with given arguments
|
||||
Pattern(evmasm::Instruction _instruction, std::initializer_list<Pattern> _arguments = {});
|
||||
Pattern(evmasm::InternalInstruction _instruction, std::initializer_list<Pattern> _arguments = {});
|
||||
/// Sets this pattern to be part of the match group with the identifier @a _group.
|
||||
/// Inside one rule, all patterns in the same match group have to match expressions from the
|
||||
/// same expression equivalence class.
|
||||
@ -127,7 +127,7 @@ public:
|
||||
/// @returns the data of the matched expression if this pattern is part of a match group.
|
||||
u256 d() const;
|
||||
|
||||
evmasm::Instruction instruction() const;
|
||||
evmasm::InternalInstruction instruction() const;
|
||||
|
||||
/// Turns this pattern into an actual expression. Should only be called
|
||||
/// for patterns resulting from an action, i.e. with match groups assigned.
|
||||
@ -137,7 +137,7 @@ private:
|
||||
Expression const& matchGroupValue() const;
|
||||
|
||||
PatternKind m_kind = PatternKind::Any;
|
||||
evmasm::Instruction m_instruction; ///< Only valid if m_kind is Operation
|
||||
evmasm::InternalInstruction m_instruction; ///< Only valid if m_kind is Operation
|
||||
std::shared_ptr<u256> m_data; ///< Only valid if m_kind is Constant
|
||||
std::vector<Pattern> m_arguments;
|
||||
unsigned m_matchGroup = 0;
|
||||
|
@ -129,7 +129,7 @@ void UnusedStoreEliminator::operator()(Leave const&)
|
||||
|
||||
void UnusedStoreEliminator::visit(Statement const& _statement)
|
||||
{
|
||||
using evmasm::Instruction;
|
||||
using evmasm::InternalInstruction;
|
||||
|
||||
UnusedStoreBase::visit(_statement);
|
||||
|
||||
@ -139,7 +139,7 @@ void UnusedStoreEliminator::visit(Statement const& _statement)
|
||||
|
||||
FunctionCall const* funCall = get_if<FunctionCall>(&exprStatement->expression);
|
||||
yulAssert(funCall);
|
||||
optional<Instruction> instruction = toEVMInstruction(m_dialect, funCall->functionName.name);
|
||||
optional<InternalInstruction> instruction = toEVMInstruction(m_dialect, funCall->functionName.name);
|
||||
if (!instruction)
|
||||
return;
|
||||
|
||||
@ -152,14 +152,14 @@ void UnusedStoreEliminator::visit(Statement const& _statement)
|
||||
// both by querying a combination of semantic information and by listing the instructions.
|
||||
// This way the assert below should be triggered on any change.
|
||||
using evmasm::SemanticInformation;
|
||||
bool isStorageWrite = (*instruction == Instruction::SSTORE);
|
||||
bool isStorageWrite = (*instruction == InternalInstruction::SSTORE);
|
||||
bool isMemoryWrite =
|
||||
*instruction == Instruction::EXTCODECOPY ||
|
||||
*instruction == Instruction::CODECOPY ||
|
||||
*instruction == Instruction::CALLDATACOPY ||
|
||||
*instruction == Instruction::RETURNDATACOPY ||
|
||||
*instruction == Instruction::MSTORE ||
|
||||
*instruction == Instruction::MSTORE8;
|
||||
*instruction == InternalInstruction::EXTCODECOPY ||
|
||||
*instruction == InternalInstruction::CODECOPY ||
|
||||
*instruction == InternalInstruction::CALLDATACOPY ||
|
||||
*instruction == InternalInstruction::RETURNDATACOPY ||
|
||||
*instruction == InternalInstruction::MSTORE ||
|
||||
*instruction == InternalInstruction::MSTORE8;
|
||||
bool isCandidateForRemoval =
|
||||
SemanticInformation::otherState(*instruction) != SemanticInformation::Write && (
|
||||
SemanticInformation::storage(*instruction) == SemanticInformation::Write ||
|
||||
@ -169,7 +169,7 @@ void UnusedStoreEliminator::visit(Statement const& _statement)
|
||||
if (isCandidateForRemoval)
|
||||
{
|
||||
State initialState = State::Undecided;
|
||||
if (*instruction == Instruction::RETURNDATACOPY)
|
||||
if (*instruction == InternalInstruction::RETURNDATACOPY)
|
||||
{
|
||||
initialState = State::Used;
|
||||
auto startOffset = identifierNameIfSSA(funCall->arguments.at(1));
|
||||
@ -181,7 +181,7 @@ void UnusedStoreEliminator::visit(Statement const& _statement)
|
||||
if (
|
||||
knowledge.knownToBeZero(*startOffset) &&
|
||||
lengthCall &&
|
||||
toEVMInstruction(m_dialect, lengthCall->functionName.name) == Instruction::RETURNDATASIZE
|
||||
toEVMInstruction(m_dialect, lengthCall->functionName.name) == InternalInstruction::RETURNDATASIZE
|
||||
)
|
||||
initialState = State::Undecided;
|
||||
}
|
||||
@ -203,7 +203,7 @@ vector<UnusedStoreEliminator::Operation> UnusedStoreEliminator::operationsFromFu
|
||||
FunctionCall const& _functionCall
|
||||
) const
|
||||
{
|
||||
using evmasm::Instruction;
|
||||
using evmasm::InternalInstruction;
|
||||
|
||||
YulString functionName = _functionCall.functionName.name;
|
||||
SideEffects sideEffects;
|
||||
@ -212,7 +212,7 @@ vector<UnusedStoreEliminator::Operation> UnusedStoreEliminator::operationsFromFu
|
||||
else
|
||||
sideEffects = m_functionSideEffects.at(functionName);
|
||||
|
||||
optional<Instruction> instruction = toEVMInstruction(m_dialect, functionName);
|
||||
optional<InternalInstruction> instruction = toEVMInstruction(m_dialect, functionName);
|
||||
if (!instruction)
|
||||
{
|
||||
vector<Operation> result;
|
||||
|
@ -74,12 +74,12 @@ BOOST_AUTO_TEST_CASE(all_assembly_items)
|
||||
// PushImmutable
|
||||
_subAsm.appendImmutable("someImmutable");
|
||||
_subAsm.append(AssemblyItem(PushTag, 0));
|
||||
_subAsm.append(Instruction::INVALID);
|
||||
_subAsm.append(InternalInstruction::INVALID);
|
||||
shared_ptr<Assembly> _subAsmPtr = make_shared<Assembly>(_subAsm);
|
||||
|
||||
_verbatimAsm.appendVerbatim({0xff,0xff}, 0, 0);
|
||||
_verbatimAsm.appendVerbatim({0x74, 0x65, 0x73, 0x74}, 0, 1);
|
||||
_verbatimAsm.append(Instruction::MSTORE);
|
||||
_verbatimAsm.append(InternalInstruction::MSTORE);
|
||||
shared_ptr<Assembly> _verbatimAsmPtr = make_shared<Assembly>(_verbatimAsm);
|
||||
|
||||
// Tag
|
||||
@ -89,7 +89,7 @@ BOOST_AUTO_TEST_CASE(all_assembly_items)
|
||||
_assembly.append(u256(1));
|
||||
_assembly.append(u256(2));
|
||||
// Push
|
||||
auto keccak256 = AssemblyItem(Instruction::KECCAK256);
|
||||
auto keccak256 = AssemblyItem(InternalInstruction::KECCAK256);
|
||||
_assembly.m_currentModifierDepth = 1;
|
||||
_assembly.append(keccak256);
|
||||
_assembly.m_currentModifierDepth = 0;
|
||||
@ -117,7 +117,7 @@ BOOST_AUTO_TEST_CASE(all_assembly_items)
|
||||
_assembly.append(u256(2));
|
||||
_assembly.appendImmutableAssignment("someImmutable");
|
||||
// Operation
|
||||
_assembly.append(Instruction::STOP);
|
||||
_assembly.append(InternalInstruction::STOP);
|
||||
_assembly.appendToAuxiliaryData(bytes{0x42, 0x66});
|
||||
_assembly.appendToAuxiliaryData(bytes{0xee, 0xaa});
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -197,7 +197,7 @@ BOOST_AUTO_TEST_CASE(literal_true)
|
||||
)";
|
||||
bytes code = compileFirstExpression(sourceCode);
|
||||
|
||||
bytes expectation({uint8_t(Instruction::PUSH1), 0x1});
|
||||
bytes expectation({uint8_t(InternalInstruction::PUSH1), 0x1});
|
||||
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
|
||||
}
|
||||
|
||||
@ -210,7 +210,7 @@ BOOST_AUTO_TEST_CASE(literal_false)
|
||||
)";
|
||||
bytes code = compileFirstExpression(sourceCode);
|
||||
|
||||
bytes expectation({uint8_t(Instruction::PUSH1), 0x0});
|
||||
bytes expectation({uint8_t(InternalInstruction::PUSH1), 0x0});
|
||||
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
|
||||
}
|
||||
|
||||
@ -223,7 +223,7 @@ BOOST_AUTO_TEST_CASE(int_literal)
|
||||
)";
|
||||
bytes code = compileFirstExpression(sourceCode);
|
||||
|
||||
bytes expectation({uint8_t(Instruction::PUSH10), 0x12, 0x34, 0x56, 0x78, 0x90,
|
||||
bytes expectation({uint8_t(InternalInstruction::PUSH10), 0x12, 0x34, 0x56, 0x78, 0x90,
|
||||
0x12, 0x34, 0x56, 0x78, 0x90});
|
||||
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
|
||||
}
|
||||
@ -239,7 +239,7 @@ BOOST_AUTO_TEST_CASE(int_with_wei_ether_subdenomination)
|
||||
)";
|
||||
bytes code = compileFirstExpression(sourceCode);
|
||||
|
||||
bytes expectation({uint8_t(Instruction::PUSH1), 0x1});
|
||||
bytes expectation({uint8_t(InternalInstruction::PUSH1), 0x1});
|
||||
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
|
||||
}
|
||||
|
||||
@ -254,7 +254,7 @@ BOOST_AUTO_TEST_CASE(int_with_gwei_ether_subdenomination)
|
||||
)";
|
||||
bytes code = compileFirstExpression(sourceCode);
|
||||
|
||||
bytes expectation({uint8_t(Instruction::PUSH4), 0x3b, 0x9a, 0xca, 0x00});
|
||||
bytes expectation({uint8_t(InternalInstruction::PUSH4), 0x3b, 0x9a, 0xca, 0x00});
|
||||
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
|
||||
}
|
||||
|
||||
@ -269,7 +269,7 @@ BOOST_AUTO_TEST_CASE(int_with_ether_ether_subdenomination)
|
||||
)";
|
||||
bytes code = compileFirstExpression(sourceCode);
|
||||
|
||||
bytes expectation({uint8_t(Instruction::PUSH8), 0xd, 0xe0, 0xb6, 0xb3, 0xa7, 0x64, 0x00, 0x00});
|
||||
bytes expectation({uint8_t(InternalInstruction::PUSH8), 0xd, 0xe0, 0xb6, 0xb3, 0xa7, 0x64, 0x00, 0x00});
|
||||
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
|
||||
}
|
||||
|
||||
@ -285,22 +285,22 @@ BOOST_AUTO_TEST_CASE(comparison)
|
||||
bytes expectation;
|
||||
if (solidity::test::CommonOptions::get().optimize)
|
||||
expectation = {
|
||||
uint8_t(Instruction::PUSH2), 0x11, 0xaa,
|
||||
uint8_t(Instruction::PUSH2), 0x10, 0xaa,
|
||||
uint8_t(Instruction::LT), uint8_t(Instruction::ISZERO), uint8_t(Instruction::ISZERO),
|
||||
uint8_t(Instruction::PUSH1), 0x1,
|
||||
uint8_t(Instruction::ISZERO), uint8_t(Instruction::ISZERO),
|
||||
uint8_t(Instruction::EQ),
|
||||
uint8_t(Instruction::ISZERO)
|
||||
uint8_t(InternalInstruction::PUSH2), 0x11, 0xaa,
|
||||
uint8_t(InternalInstruction::PUSH2), 0x10, 0xaa,
|
||||
uint8_t(InternalInstruction::LT), uint8_t(InternalInstruction::ISZERO), uint8_t(InternalInstruction::ISZERO),
|
||||
uint8_t(InternalInstruction::PUSH1), 0x1,
|
||||
uint8_t(InternalInstruction::ISZERO), uint8_t(InternalInstruction::ISZERO),
|
||||
uint8_t(InternalInstruction::EQ),
|
||||
uint8_t(InternalInstruction::ISZERO)
|
||||
};
|
||||
else
|
||||
expectation = {
|
||||
uint8_t(Instruction::PUSH1), 0x1, uint8_t(Instruction::ISZERO), uint8_t(Instruction::ISZERO),
|
||||
uint8_t(Instruction::PUSH2), 0x11, 0xaa,
|
||||
uint8_t(Instruction::PUSH2), 0x10, 0xaa,
|
||||
uint8_t(Instruction::LT), uint8_t(Instruction::ISZERO), uint8_t(Instruction::ISZERO),
|
||||
uint8_t(Instruction::EQ),
|
||||
uint8_t(Instruction::ISZERO)
|
||||
uint8_t(InternalInstruction::PUSH1), 0x1, uint8_t(InternalInstruction::ISZERO), uint8_t(InternalInstruction::ISZERO),
|
||||
uint8_t(InternalInstruction::PUSH2), 0x11, 0xaa,
|
||||
uint8_t(InternalInstruction::PUSH2), 0x10, 0xaa,
|
||||
uint8_t(InternalInstruction::LT), uint8_t(InternalInstruction::ISZERO), uint8_t(InternalInstruction::ISZERO),
|
||||
uint8_t(InternalInstruction::EQ),
|
||||
uint8_t(InternalInstruction::ISZERO)
|
||||
};
|
||||
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
|
||||
}
|
||||
@ -315,23 +315,23 @@ BOOST_AUTO_TEST_CASE(short_circuiting)
|
||||
bytes code = compileFirstExpression(sourceCode);
|
||||
|
||||
bytes expectation{
|
||||
uint8_t(Instruction::PUSH1), 0x12, // 8 + 10
|
||||
uint8_t(Instruction::PUSH1), 0x4,
|
||||
uint8_t(Instruction::GT),
|
||||
uint8_t(Instruction::ISZERO), // after this we have 4 <= 8 + 10
|
||||
uint8_t(Instruction::DUP1),
|
||||
uint8_t(Instruction::PUSH1), 0x11,
|
||||
uint8_t(Instruction::JUMPI), // short-circuit if it is true
|
||||
uint8_t(Instruction::POP),
|
||||
uint8_t(Instruction::PUSH1), 0x2,
|
||||
uint8_t(Instruction::PUSH1), 0x9,
|
||||
uint8_t(Instruction::EQ),
|
||||
uint8_t(Instruction::ISZERO), // after this we have 9 != 2
|
||||
uint8_t(Instruction::JUMPDEST),
|
||||
uint8_t(Instruction::ISZERO), uint8_t(Instruction::ISZERO),
|
||||
uint8_t(Instruction::PUSH1), 0x1, uint8_t(Instruction::ISZERO), uint8_t(Instruction::ISZERO),
|
||||
uint8_t(Instruction::EQ),
|
||||
uint8_t(Instruction::ISZERO)
|
||||
uint8_t(InternalInstruction::PUSH1), 0x12, // 8 + 10
|
||||
uint8_t(InternalInstruction::PUSH1), 0x4,
|
||||
uint8_t(InternalInstruction::GT),
|
||||
uint8_t(InternalInstruction::ISZERO), // after this we have 4 <= 8 + 10
|
||||
uint8_t(InternalInstruction::DUP1),
|
||||
uint8_t(InternalInstruction::PUSH1), 0x11,
|
||||
uint8_t(InternalInstruction::JUMPI), // short-circuit if it is true
|
||||
uint8_t(InternalInstruction::POP),
|
||||
uint8_t(InternalInstruction::PUSH1), 0x2,
|
||||
uint8_t(InternalInstruction::PUSH1), 0x9,
|
||||
uint8_t(InternalInstruction::EQ),
|
||||
uint8_t(InternalInstruction::ISZERO), // after this we have 9 != 2
|
||||
uint8_t(InternalInstruction::JUMPDEST),
|
||||
uint8_t(InternalInstruction::ISZERO), uint8_t(InternalInstruction::ISZERO),
|
||||
uint8_t(InternalInstruction::PUSH1), 0x1, uint8_t(InternalInstruction::ISZERO), uint8_t(InternalInstruction::ISZERO),
|
||||
uint8_t(InternalInstruction::EQ),
|
||||
uint8_t(InternalInstruction::ISZERO)
|
||||
};
|
||||
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
|
||||
}
|
||||
@ -347,108 +347,108 @@ BOOST_AUTO_TEST_CASE(arithmetic)
|
||||
|
||||
bytes panic =
|
||||
bytes{
|
||||
uint8_t(Instruction::JUMPDEST),
|
||||
uint8_t(Instruction::PUSH32)
|
||||
uint8_t(InternalInstruction::JUMPDEST),
|
||||
uint8_t(InternalInstruction::PUSH32)
|
||||
} +
|
||||
util::fromHex("4E487B7100000000000000000000000000000000000000000000000000000000") +
|
||||
bytes{
|
||||
uint8_t(Instruction::PUSH1), 0x0,
|
||||
uint8_t(Instruction::MSTORE),
|
||||
uint8_t(Instruction::PUSH1), 0x12,
|
||||
uint8_t(Instruction::PUSH1), 0x4,
|
||||
uint8_t(Instruction::MSTORE),
|
||||
uint8_t(Instruction::PUSH1), 0x24,
|
||||
uint8_t(Instruction::PUSH1), 0x0,
|
||||
uint8_t(Instruction::REVERT),
|
||||
uint8_t(Instruction::JUMPDEST),
|
||||
uint8_t(Instruction::JUMP),
|
||||
uint8_t(Instruction::JUMPDEST)
|
||||
uint8_t(InternalInstruction::PUSH1), 0x0,
|
||||
uint8_t(InternalInstruction::MSTORE),
|
||||
uint8_t(InternalInstruction::PUSH1), 0x12,
|
||||
uint8_t(InternalInstruction::PUSH1), 0x4,
|
||||
uint8_t(InternalInstruction::MSTORE),
|
||||
uint8_t(InternalInstruction::PUSH1), 0x24,
|
||||
uint8_t(InternalInstruction::PUSH1), 0x0,
|
||||
uint8_t(InternalInstruction::REVERT),
|
||||
uint8_t(InternalInstruction::JUMPDEST),
|
||||
uint8_t(InternalInstruction::JUMP),
|
||||
uint8_t(InternalInstruction::JUMPDEST)
|
||||
};
|
||||
|
||||
bytes expectation;
|
||||
if (solidity::test::CommonOptions::get().optimize)
|
||||
expectation = bytes{
|
||||
uint8_t(Instruction::PUSH1), 0x2,
|
||||
uint8_t(Instruction::PUSH1), 0x3,
|
||||
uint8_t(Instruction::PUSH1), 0x5,
|
||||
uint8_t(Instruction::DUP4),
|
||||
uint8_t(Instruction::PUSH1), 0x8,
|
||||
uint8_t(Instruction::XOR),
|
||||
uint8_t(Instruction::PUSH1), 0x7,
|
||||
uint8_t(Instruction::AND),
|
||||
uint8_t(Instruction::PUSH1), 0x6,
|
||||
uint8_t(Instruction::OR),
|
||||
uint8_t(Instruction::SUB),
|
||||
uint8_t(Instruction::PUSH1), 0x4,
|
||||
uint8_t(Instruction::ADD),
|
||||
uint8_t(Instruction::DUP2),
|
||||
uint8_t(Instruction::ISZERO),
|
||||
uint8_t(Instruction::ISZERO),
|
||||
uint8_t(Instruction::PUSH1), 0x20,
|
||||
uint8_t(Instruction::JUMPI),
|
||||
uint8_t(Instruction::PUSH1), 0x1f,
|
||||
uint8_t(Instruction::PUSH1), 0x36,
|
||||
uint8_t(Instruction::JUMP),
|
||||
uint8_t(Instruction::JUMPDEST),
|
||||
uint8_t(Instruction::JUMPDEST),
|
||||
uint8_t(Instruction::MOD),
|
||||
uint8_t(Instruction::DUP2),
|
||||
uint8_t(Instruction::ISZERO),
|
||||
uint8_t(Instruction::ISZERO),
|
||||
uint8_t(Instruction::PUSH1), 0x2e,
|
||||
uint8_t(Instruction::JUMPI),
|
||||
uint8_t(Instruction::PUSH1), 0x2d,
|
||||
uint8_t(Instruction::PUSH1), 0x36,
|
||||
uint8_t(Instruction::JUMP),
|
||||
uint8_t(Instruction::JUMPDEST),
|
||||
uint8_t(Instruction::JUMPDEST),
|
||||
uint8_t(Instruction::DIV),
|
||||
uint8_t(Instruction::PUSH1), 0x1,
|
||||
uint8_t(Instruction::MUL),
|
||||
uint8_t(Instruction::PUSH1), 0x67,
|
||||
uint8_t(Instruction::JUMP)
|
||||
uint8_t(InternalInstruction::PUSH1), 0x2,
|
||||
uint8_t(InternalInstruction::PUSH1), 0x3,
|
||||
uint8_t(InternalInstruction::PUSH1), 0x5,
|
||||
uint8_t(InternalInstruction::DUP4),
|
||||
uint8_t(InternalInstruction::PUSH1), 0x8,
|
||||
uint8_t(InternalInstruction::XOR),
|
||||
uint8_t(InternalInstruction::PUSH1), 0x7,
|
||||
uint8_t(InternalInstruction::AND),
|
||||
uint8_t(InternalInstruction::PUSH1), 0x6,
|
||||
uint8_t(InternalInstruction::OR),
|
||||
uint8_t(InternalInstruction::SUB),
|
||||
uint8_t(InternalInstruction::PUSH1), 0x4,
|
||||
uint8_t(InternalInstruction::ADD),
|
||||
uint8_t(InternalInstruction::DUP2),
|
||||
uint8_t(InternalInstruction::ISZERO),
|
||||
uint8_t(InternalInstruction::ISZERO),
|
||||
uint8_t(InternalInstruction::PUSH1), 0x20,
|
||||
uint8_t(InternalInstruction::JUMPI),
|
||||
uint8_t(InternalInstruction::PUSH1), 0x1f,
|
||||
uint8_t(InternalInstruction::PUSH1), 0x36,
|
||||
uint8_t(InternalInstruction::JUMP),
|
||||
uint8_t(InternalInstruction::JUMPDEST),
|
||||
uint8_t(InternalInstruction::JUMPDEST),
|
||||
uint8_t(InternalInstruction::MOD),
|
||||
uint8_t(InternalInstruction::DUP2),
|
||||
uint8_t(InternalInstruction::ISZERO),
|
||||
uint8_t(InternalInstruction::ISZERO),
|
||||
uint8_t(InternalInstruction::PUSH1), 0x2e,
|
||||
uint8_t(InternalInstruction::JUMPI),
|
||||
uint8_t(InternalInstruction::PUSH1), 0x2d,
|
||||
uint8_t(InternalInstruction::PUSH1), 0x36,
|
||||
uint8_t(InternalInstruction::JUMP),
|
||||
uint8_t(InternalInstruction::JUMPDEST),
|
||||
uint8_t(InternalInstruction::JUMPDEST),
|
||||
uint8_t(InternalInstruction::DIV),
|
||||
uint8_t(InternalInstruction::PUSH1), 0x1,
|
||||
uint8_t(InternalInstruction::MUL),
|
||||
uint8_t(InternalInstruction::PUSH1), 0x67,
|
||||
uint8_t(InternalInstruction::JUMP)
|
||||
} + panic;
|
||||
else
|
||||
expectation = bytes{
|
||||
uint8_t(Instruction::PUSH1), 0x1,
|
||||
uint8_t(Instruction::PUSH1), 0x2,
|
||||
uint8_t(Instruction::PUSH1), 0x3,
|
||||
uint8_t(Instruction::PUSH1), 0x4,
|
||||
uint8_t(Instruction::PUSH1), 0x5,
|
||||
uint8_t(Instruction::PUSH1), 0x6,
|
||||
uint8_t(Instruction::PUSH1), 0x7,
|
||||
uint8_t(Instruction::PUSH1), 0x8,
|
||||
uint8_t(Instruction::DUP9),
|
||||
uint8_t(Instruction::XOR),
|
||||
uint8_t(Instruction::AND),
|
||||
uint8_t(Instruction::OR),
|
||||
uint8_t(Instruction::SUB),
|
||||
uint8_t(Instruction::ADD),
|
||||
uint8_t(Instruction::DUP2),
|
||||
uint8_t(Instruction::ISZERO),
|
||||
uint8_t(Instruction::ISZERO),
|
||||
uint8_t(Instruction::PUSH1), 0x22,
|
||||
uint8_t(Instruction::JUMPI),
|
||||
uint8_t(Instruction::PUSH1), 0x21,
|
||||
uint8_t(Instruction::PUSH1), 0x36,
|
||||
uint8_t(Instruction::JUMP),
|
||||
uint8_t(Instruction::JUMPDEST),
|
||||
uint8_t(Instruction::JUMPDEST),
|
||||
uint8_t(Instruction::MOD),
|
||||
uint8_t(Instruction::DUP2),
|
||||
uint8_t(Instruction::ISZERO),
|
||||
uint8_t(Instruction::ISZERO),
|
||||
uint8_t(Instruction::PUSH1), 0x30,
|
||||
uint8_t(Instruction::JUMPI),
|
||||
uint8_t(Instruction::PUSH1), 0x2f,
|
||||
uint8_t(Instruction::PUSH1), 0x36,
|
||||
uint8_t(Instruction::JUMP),
|
||||
uint8_t(Instruction::JUMPDEST),
|
||||
uint8_t(Instruction::JUMPDEST),
|
||||
uint8_t(Instruction::DIV),
|
||||
uint8_t(Instruction::MUL),
|
||||
uint8_t(Instruction::PUSH1), 0x67,
|
||||
uint8_t(Instruction::JUMP)
|
||||
uint8_t(InternalInstruction::PUSH1), 0x1,
|
||||
uint8_t(InternalInstruction::PUSH1), 0x2,
|
||||
uint8_t(InternalInstruction::PUSH1), 0x3,
|
||||
uint8_t(InternalInstruction::PUSH1), 0x4,
|
||||
uint8_t(InternalInstruction::PUSH1), 0x5,
|
||||
uint8_t(InternalInstruction::PUSH1), 0x6,
|
||||
uint8_t(InternalInstruction::PUSH1), 0x7,
|
||||
uint8_t(InternalInstruction::PUSH1), 0x8,
|
||||
uint8_t(InternalInstruction::DUP9),
|
||||
uint8_t(InternalInstruction::XOR),
|
||||
uint8_t(InternalInstruction::AND),
|
||||
uint8_t(InternalInstruction::OR),
|
||||
uint8_t(InternalInstruction::SUB),
|
||||
uint8_t(InternalInstruction::ADD),
|
||||
uint8_t(InternalInstruction::DUP2),
|
||||
uint8_t(InternalInstruction::ISZERO),
|
||||
uint8_t(InternalInstruction::ISZERO),
|
||||
uint8_t(InternalInstruction::PUSH1), 0x22,
|
||||
uint8_t(InternalInstruction::JUMPI),
|
||||
uint8_t(InternalInstruction::PUSH1), 0x21,
|
||||
uint8_t(InternalInstruction::PUSH1), 0x36,
|
||||
uint8_t(InternalInstruction::JUMP),
|
||||
uint8_t(InternalInstruction::JUMPDEST),
|
||||
uint8_t(InternalInstruction::JUMPDEST),
|
||||
uint8_t(InternalInstruction::MOD),
|
||||
uint8_t(InternalInstruction::DUP2),
|
||||
uint8_t(InternalInstruction::ISZERO),
|
||||
uint8_t(InternalInstruction::ISZERO),
|
||||
uint8_t(InternalInstruction::PUSH1), 0x30,
|
||||
uint8_t(InternalInstruction::JUMPI),
|
||||
uint8_t(InternalInstruction::PUSH1), 0x2f,
|
||||
uint8_t(InternalInstruction::PUSH1), 0x36,
|
||||
uint8_t(InternalInstruction::JUMP),
|
||||
uint8_t(InternalInstruction::JUMPDEST),
|
||||
uint8_t(InternalInstruction::JUMPDEST),
|
||||
uint8_t(InternalInstruction::DIV),
|
||||
uint8_t(InternalInstruction::MUL),
|
||||
uint8_t(InternalInstruction::PUSH1), 0x67,
|
||||
uint8_t(InternalInstruction::JUMP)
|
||||
} + panic;
|
||||
|
||||
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
|
||||
@ -466,23 +466,23 @@ BOOST_AUTO_TEST_CASE(unary_operators)
|
||||
bytes expectation;
|
||||
if (solidity::test::CommonOptions::get().optimize)
|
||||
expectation = {
|
||||
uint8_t(Instruction::DUP1),
|
||||
uint8_t(Instruction::PUSH1), 0x0,
|
||||
uint8_t(Instruction::SUB),
|
||||
uint8_t(Instruction::NOT),
|
||||
uint8_t(Instruction::PUSH1), 0x2,
|
||||
uint8_t(Instruction::EQ),
|
||||
uint8_t(Instruction::ISZERO)
|
||||
uint8_t(InternalInstruction::DUP1),
|
||||
uint8_t(InternalInstruction::PUSH1), 0x0,
|
||||
uint8_t(InternalInstruction::SUB),
|
||||
uint8_t(InternalInstruction::NOT),
|
||||
uint8_t(InternalInstruction::PUSH1), 0x2,
|
||||
uint8_t(InternalInstruction::EQ),
|
||||
uint8_t(InternalInstruction::ISZERO)
|
||||
};
|
||||
else
|
||||
expectation = {
|
||||
uint8_t(Instruction::PUSH1), 0x2,
|
||||
uint8_t(Instruction::DUP2),
|
||||
uint8_t(Instruction::PUSH1), 0x0,
|
||||
uint8_t(Instruction::SUB),
|
||||
uint8_t(Instruction::NOT),
|
||||
uint8_t(Instruction::EQ),
|
||||
uint8_t(Instruction::ISZERO)
|
||||
uint8_t(InternalInstruction::PUSH1), 0x2,
|
||||
uint8_t(InternalInstruction::DUP2),
|
||||
uint8_t(InternalInstruction::PUSH1), 0x0,
|
||||
uint8_t(InternalInstruction::SUB),
|
||||
uint8_t(InternalInstruction::NOT),
|
||||
uint8_t(InternalInstruction::EQ),
|
||||
uint8_t(InternalInstruction::ISZERO)
|
||||
};
|
||||
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
|
||||
}
|
||||
@ -498,47 +498,47 @@ BOOST_AUTO_TEST_CASE(unary_inc_dec)
|
||||
|
||||
// Stack: a, x
|
||||
bytes expectation{
|
||||
uint8_t(Instruction::DUP2),
|
||||
uint8_t(Instruction::DUP1),
|
||||
uint8_t(Instruction::PUSH1), 0x1,
|
||||
uint8_t(Instruction::ADD),
|
||||
uint8_t(InternalInstruction::DUP2),
|
||||
uint8_t(InternalInstruction::DUP1),
|
||||
uint8_t(InternalInstruction::PUSH1), 0x1,
|
||||
uint8_t(InternalInstruction::ADD),
|
||||
// Stack here: a x a (a+1)
|
||||
uint8_t(Instruction::SWAP3),
|
||||
uint8_t(Instruction::POP), // first ++
|
||||
uint8_t(InternalInstruction::SWAP3),
|
||||
uint8_t(InternalInstruction::POP), // first ++
|
||||
// Stack here: (a+1) x a
|
||||
uint8_t(Instruction::DUP3),
|
||||
uint8_t(Instruction::PUSH1), 0x1,
|
||||
uint8_t(Instruction::ADD),
|
||||
uint8_t(InternalInstruction::DUP3),
|
||||
uint8_t(InternalInstruction::PUSH1), 0x1,
|
||||
uint8_t(InternalInstruction::ADD),
|
||||
// Stack here: (a+1) x a (a+2)
|
||||
uint8_t(Instruction::SWAP3),
|
||||
uint8_t(Instruction::POP),
|
||||
uint8_t(InternalInstruction::SWAP3),
|
||||
uint8_t(InternalInstruction::POP),
|
||||
// Stack here: (a+2) x a
|
||||
uint8_t(Instruction::DUP3), // second ++
|
||||
uint8_t(Instruction::XOR),
|
||||
uint8_t(InternalInstruction::DUP3), // second ++
|
||||
uint8_t(InternalInstruction::XOR),
|
||||
// Stack here: (a+2) x a^(a+2)
|
||||
uint8_t(Instruction::DUP3),
|
||||
uint8_t(Instruction::DUP1),
|
||||
uint8_t(Instruction::PUSH1), 0x1,
|
||||
uint8_t(Instruction::SWAP1),
|
||||
uint8_t(Instruction::SUB),
|
||||
uint8_t(InternalInstruction::DUP3),
|
||||
uint8_t(InternalInstruction::DUP1),
|
||||
uint8_t(InternalInstruction::PUSH1), 0x1,
|
||||
uint8_t(InternalInstruction::SWAP1),
|
||||
uint8_t(InternalInstruction::SUB),
|
||||
// Stack here: (a+2) x a^(a+2) (a+2) (a+1)
|
||||
uint8_t(Instruction::SWAP4),
|
||||
uint8_t(Instruction::POP), // first --
|
||||
uint8_t(Instruction::XOR),
|
||||
uint8_t(InternalInstruction::SWAP4),
|
||||
uint8_t(InternalInstruction::POP), // first --
|
||||
uint8_t(InternalInstruction::XOR),
|
||||
// Stack here: (a+1) x a^(a+2)^(a+2)
|
||||
uint8_t(Instruction::DUP3),
|
||||
uint8_t(Instruction::PUSH1), 0x1,
|
||||
uint8_t(Instruction::SWAP1),
|
||||
uint8_t(Instruction::SUB),
|
||||
uint8_t(InternalInstruction::DUP3),
|
||||
uint8_t(InternalInstruction::PUSH1), 0x1,
|
||||
uint8_t(InternalInstruction::SWAP1),
|
||||
uint8_t(InternalInstruction::SUB),
|
||||
// Stack here: (a+1) x a^(a+2)^(a+2) a
|
||||
uint8_t(Instruction::SWAP3),
|
||||
uint8_t(Instruction::POP), // second ++
|
||||
uint8_t(InternalInstruction::SWAP3),
|
||||
uint8_t(InternalInstruction::POP), // second ++
|
||||
// Stack here: a x a^(a+2)^(a+2)
|
||||
uint8_t(Instruction::DUP3), // will change
|
||||
uint8_t(Instruction::XOR),
|
||||
uint8_t(Instruction::SWAP1),
|
||||
uint8_t(Instruction::POP),
|
||||
uint8_t(Instruction::DUP1)
|
||||
uint8_t(InternalInstruction::DUP3), // will change
|
||||
uint8_t(InternalInstruction::XOR),
|
||||
uint8_t(InternalInstruction::SWAP1),
|
||||
uint8_t(InternalInstruction::POP),
|
||||
uint8_t(InternalInstruction::DUP1)
|
||||
};
|
||||
// Stack here: a x a^(a+2)^(a+2)^a
|
||||
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
|
||||
@ -557,27 +557,27 @@ BOOST_AUTO_TEST_CASE(assignment)
|
||||
bytes expectation;
|
||||
if (solidity::test::CommonOptions::get().optimize)
|
||||
expectation = {
|
||||
uint8_t(Instruction::DUP1),
|
||||
uint8_t(Instruction::DUP3),
|
||||
uint8_t(Instruction::ADD),
|
||||
uint8_t(Instruction::SWAP2),
|
||||
uint8_t(Instruction::POP),
|
||||
uint8_t(Instruction::DUP2),
|
||||
uint8_t(Instruction::PUSH1), 0x2,
|
||||
uint8_t(Instruction::MUL)
|
||||
uint8_t(InternalInstruction::DUP1),
|
||||
uint8_t(InternalInstruction::DUP3),
|
||||
uint8_t(InternalInstruction::ADD),
|
||||
uint8_t(InternalInstruction::SWAP2),
|
||||
uint8_t(InternalInstruction::POP),
|
||||
uint8_t(InternalInstruction::DUP2),
|
||||
uint8_t(InternalInstruction::PUSH1), 0x2,
|
||||
uint8_t(InternalInstruction::MUL)
|
||||
};
|
||||
else
|
||||
expectation = {
|
||||
uint8_t(Instruction::PUSH1), 0x2,
|
||||
uint8_t(Instruction::DUP2),
|
||||
uint8_t(Instruction::DUP4),
|
||||
uint8_t(Instruction::ADD),
|
||||
uint8_t(InternalInstruction::PUSH1), 0x2,
|
||||
uint8_t(InternalInstruction::DUP2),
|
||||
uint8_t(InternalInstruction::DUP4),
|
||||
uint8_t(InternalInstruction::ADD),
|
||||
// Stack here: a b 2 a+b
|
||||
uint8_t(Instruction::SWAP3),
|
||||
uint8_t(Instruction::POP),
|
||||
uint8_t(Instruction::DUP3),
|
||||
uint8_t(InternalInstruction::SWAP3),
|
||||
uint8_t(InternalInstruction::POP),
|
||||
uint8_t(InternalInstruction::DUP3),
|
||||
// Stack here: a+b b 2 a+b
|
||||
uint8_t(Instruction::MUL)
|
||||
uint8_t(InternalInstruction::MUL)
|
||||
};
|
||||
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
|
||||
}
|
||||
@ -591,7 +591,7 @@ BOOST_AUTO_TEST_CASE(negative_literals_8bits)
|
||||
)";
|
||||
bytes code = compileFirstExpression(sourceCode);
|
||||
|
||||
bytes expectation(bytes({uint8_t(Instruction::PUSH32)}) + bytes(31, 0xff) + bytes(1, 0x80));
|
||||
bytes expectation(bytes({uint8_t(InternalInstruction::PUSH32)}) + bytes(31, 0xff) + bytes(1, 0x80));
|
||||
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
|
||||
}
|
||||
|
||||
@ -604,7 +604,7 @@ BOOST_AUTO_TEST_CASE(negative_literals_16bits)
|
||||
)";
|
||||
bytes code = compileFirstExpression(sourceCode);
|
||||
|
||||
bytes expectation(bytes({uint8_t(Instruction::PUSH32)}) + bytes(30, 0xff) + bytes{0xf5, 0x43});
|
||||
bytes expectation(bytes({uint8_t(InternalInstruction::PUSH32)}) + bytes(30, 0xff) + bytes{0xf5, 0x43});
|
||||
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
|
||||
}
|
||||
|
||||
@ -619,7 +619,7 @@ BOOST_AUTO_TEST_CASE(intermediately_overflowing_literals)
|
||||
)";
|
||||
bytes code = compileFirstExpression(sourceCode);
|
||||
|
||||
bytes expectation(bytes({uint8_t(Instruction::PUSH1), 0xbf}));
|
||||
bytes expectation(bytes({uint8_t(InternalInstruction::PUSH1), 0xbf}));
|
||||
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
|
||||
}
|
||||
|
||||
@ -635,8 +635,8 @@ BOOST_AUTO_TEST_CASE(blockhash)
|
||||
|
||||
bytes code = compileFirstExpression(sourceCode, {}, {});
|
||||
|
||||
bytes expectation({uint8_t(Instruction::PUSH1), 0x03,
|
||||
uint8_t(Instruction::BLOCKHASH)});
|
||||
bytes expectation({uint8_t(InternalInstruction::PUSH1), 0x03,
|
||||
uint8_t(InternalInstruction::BLOCKHASH)});
|
||||
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
|
||||
}
|
||||
|
||||
@ -651,7 +651,7 @@ BOOST_AUTO_TEST_CASE(gas_left)
|
||||
)";
|
||||
bytes code = compileFirstExpression(sourceCode, {}, {});
|
||||
|
||||
bytes expectation = bytes({uint8_t(Instruction::GAS)});
|
||||
bytes expectation = bytes({uint8_t(InternalInstruction::GAS)});
|
||||
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
|
||||
}
|
||||
|
||||
@ -669,7 +669,7 @@ BOOST_AUTO_TEST_CASE(selfbalance)
|
||||
|
||||
if (solidity::test::CommonOptions::get().evmVersion().hasSelfBalance())
|
||||
{
|
||||
bytes expectation({uint8_t(Instruction::SELFBALANCE)});
|
||||
bytes expectation({uint8_t(InternalInstruction::SELFBALANCE)});
|
||||
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
|
||||
}
|
||||
}
|
||||
|
@ -104,12 +104,12 @@ public:
|
||||
|
||||
/// @returns the number of instructions in the given bytecode, not taking the metadata hash
|
||||
/// into account.
|
||||
size_t numInstructions(bytes const& _bytecode, std::optional<Instruction> _which = std::optional<Instruction>{})
|
||||
size_t numInstructions(bytes const& _bytecode, std::optional<InternalInstruction> _which = std::optional<InternalInstruction>{})
|
||||
{
|
||||
bytes realCode = bytecodeSansMetadata(_bytecode);
|
||||
BOOST_REQUIRE_MESSAGE(!realCode.empty(), "Invalid or missing metadata in bytecode.");
|
||||
size_t instructions = 0;
|
||||
evmasm::eachInstruction(realCode, [&](Instruction _instr, u256 const&) {
|
||||
evmasm::eachInstruction(realCode, langutil::EVMVersion(), [&](InternalInstruction _instr, u256 const&) {
|
||||
if (!_which || *_which == _instr)
|
||||
instructions++;
|
||||
});
|
||||
@ -287,8 +287,8 @@ BOOST_AUTO_TEST_CASE(retain_information_in_branches)
|
||||
|
||||
bytes optimizedBytecode = compileAndRunWithOptimizer(sourceCode, 0, "c", true);
|
||||
size_t numSHA3s = 0;
|
||||
eachInstruction(optimizedBytecode, [&](Instruction _instr, u256 const&) {
|
||||
if (_instr == Instruction::KECCAK256)
|
||||
eachInstruction(optimizedBytecode, langutil::EVMVersion(), [&](InternalInstruction _instr, u256 const&) {
|
||||
if (_instr == InternalInstruction::KECCAK256)
|
||||
numSHA3s++;
|
||||
});
|
||||
// TEST DISABLED - OPTIMIZER IS NOT EFFECTIVE ON THIS ONE ANYMORE
|
||||
@ -330,8 +330,8 @@ BOOST_AUTO_TEST_CASE(store_tags_as_unions)
|
||||
|
||||
bytes optimizedBytecode = compileAndRunWithOptimizer(sourceCode, 0, "test", true);
|
||||
size_t numSHA3s = 0;
|
||||
eachInstruction(optimizedBytecode, [&](Instruction _instr, u256 const&) {
|
||||
if (_instr == Instruction::KECCAK256)
|
||||
eachInstruction(optimizedBytecode, langutil::EVMVersion(), [&](InternalInstruction _instr, u256 const&) {
|
||||
if (_instr == InternalInstruction::KECCAK256)
|
||||
numSHA3s++;
|
||||
});
|
||||
// TEST DISABLED UNTIL 93693404 IS IMPLEMENTED
|
||||
@ -635,8 +635,8 @@ BOOST_AUTO_TEST_CASE(optimise_multi_stores)
|
||||
)";
|
||||
compileBothVersions(sourceCode);
|
||||
compareVersions("f()");
|
||||
BOOST_CHECK_EQUAL(numInstructions(m_nonOptimizedBytecode, Instruction::SSTORE), 8);
|
||||
BOOST_CHECK_EQUAL(numInstructions(m_optimizedBytecode, Instruction::SSTORE), 7);
|
||||
BOOST_CHECK_EQUAL(numInstructions(m_nonOptimizedBytecode, InternalInstruction::SSTORE), 8);
|
||||
BOOST_CHECK_EQUAL(numInstructions(m_optimizedBytecode, InternalInstruction::SSTORE), 7);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(optimise_constant_to_codecopy)
|
||||
@ -672,8 +672,8 @@ BOOST_AUTO_TEST_CASE(optimise_constant_to_codecopy)
|
||||
compareVersions("h()");
|
||||
compareVersions("i()");
|
||||
// This is counting in the deployed code.
|
||||
BOOST_CHECK_EQUAL(numInstructions(m_nonOptimizedBytecode, Instruction::CODECOPY), 0);
|
||||
BOOST_CHECK_EQUAL(numInstructions(m_optimizedBytecode, Instruction::CODECOPY), 4);
|
||||
BOOST_CHECK_EQUAL(numInstructions(m_nonOptimizedBytecode, InternalInstruction::CODECOPY), 0);
|
||||
BOOST_CHECK_EQUAL(numInstructions(m_optimizedBytecode, InternalInstruction::CODECOPY), 4);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(byte_access)
|
||||
@ -722,7 +722,7 @@ BOOST_AUTO_TEST_CASE(avoid_double_cleanup)
|
||||
)";
|
||||
compileBothVersions(sourceCode, 0, "C", 50);
|
||||
// Check that there is no double AND instruction in the resulting code
|
||||
BOOST_CHECK_EQUAL(numInstructions(m_nonOptimizedBytecode, Instruction::AND), 1);
|
||||
BOOST_CHECK_EQUAL(numInstructions(m_nonOptimizedBytecode, InternalInstruction::AND), 1);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
@ -87,12 +87,12 @@ void copyZeroExtended(
|
||||
using u512 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<512, 256, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>;
|
||||
|
||||
u256 EVMInstructionInterpreter::eval(
|
||||
evmasm::Instruction _instruction,
|
||||
evmasm::InternalInstruction _instruction,
|
||||
vector<u256> const& _arguments
|
||||
)
|
||||
{
|
||||
using namespace solidity::evmasm;
|
||||
using evmasm::Instruction;
|
||||
using evmasm::InternalInstruction;
|
||||
|
||||
auto info = instructionInfo(_instruction);
|
||||
yulAssert(static_cast<size_t>(info.args) == _arguments.size(), "");
|
||||
@ -100,53 +100,53 @@ u256 EVMInstructionInterpreter::eval(
|
||||
auto const& arg = _arguments;
|
||||
switch (_instruction)
|
||||
{
|
||||
case Instruction::STOP:
|
||||
case InternalInstruction::STOP:
|
||||
logTrace(_instruction);
|
||||
BOOST_THROW_EXCEPTION(ExplicitlyTerminated());
|
||||
// --------------- arithmetic ---------------
|
||||
case Instruction::ADD:
|
||||
case InternalInstruction::ADD:
|
||||
return arg[0] + arg[1];
|
||||
case Instruction::MUL:
|
||||
case InternalInstruction::MUL:
|
||||
return arg[0] * arg[1];
|
||||
case Instruction::SUB:
|
||||
case InternalInstruction::SUB:
|
||||
return arg[0] - arg[1];
|
||||
case Instruction::DIV:
|
||||
case InternalInstruction::DIV:
|
||||
return arg[1] == 0 ? 0 : arg[0] / arg[1];
|
||||
case Instruction::SDIV:
|
||||
case InternalInstruction::SDIV:
|
||||
return arg[1] == 0 ? 0 : s2u(u2s(arg[0]) / u2s(arg[1]));
|
||||
case Instruction::MOD:
|
||||
case InternalInstruction::MOD:
|
||||
return arg[1] == 0 ? 0 : arg[0] % arg[1];
|
||||
case Instruction::SMOD:
|
||||
case InternalInstruction::SMOD:
|
||||
return arg[1] == 0 ? 0 : s2u(u2s(arg[0]) % u2s(arg[1]));
|
||||
case Instruction::EXP:
|
||||
case InternalInstruction::EXP:
|
||||
return exp256(arg[0], arg[1]);
|
||||
case Instruction::NOT:
|
||||
case InternalInstruction::NOT:
|
||||
return ~arg[0];
|
||||
case Instruction::LT:
|
||||
case InternalInstruction::LT:
|
||||
return arg[0] < arg[1] ? 1 : 0;
|
||||
case Instruction::GT:
|
||||
case InternalInstruction::GT:
|
||||
return arg[0] > arg[1] ? 1 : 0;
|
||||
case Instruction::SLT:
|
||||
case InternalInstruction::SLT:
|
||||
return u2s(arg[0]) < u2s(arg[1]) ? 1 : 0;
|
||||
case Instruction::SGT:
|
||||
case InternalInstruction::SGT:
|
||||
return u2s(arg[0]) > u2s(arg[1]) ? 1 : 0;
|
||||
case Instruction::EQ:
|
||||
case InternalInstruction::EQ:
|
||||
return arg[0] == arg[1] ? 1 : 0;
|
||||
case Instruction::ISZERO:
|
||||
case InternalInstruction::ISZERO:
|
||||
return arg[0] == 0 ? 1 : 0;
|
||||
case Instruction::AND:
|
||||
case InternalInstruction::AND:
|
||||
return arg[0] & arg[1];
|
||||
case Instruction::OR:
|
||||
case InternalInstruction::OR:
|
||||
return arg[0] | arg[1];
|
||||
case Instruction::XOR:
|
||||
case InternalInstruction::XOR:
|
||||
return arg[0] ^ arg[1];
|
||||
case Instruction::BYTE:
|
||||
case InternalInstruction::BYTE:
|
||||
return arg[0] >= 32 ? 0 : (arg[1] >> unsigned(8 * (31 - arg[0]))) & 0xff;
|
||||
case Instruction::SHL:
|
||||
case InternalInstruction::SHL:
|
||||
return arg[0] > 255 ? 0 : (arg[1] << unsigned(arg[0]));
|
||||
case Instruction::SHR:
|
||||
case InternalInstruction::SHR:
|
||||
return arg[0] > 255 ? 0 : (arg[1] >> unsigned(arg[0]));
|
||||
case Instruction::SAR:
|
||||
case InternalInstruction::SAR:
|
||||
{
|
||||
static u256 const hibit = u256(1) << 255;
|
||||
if (arg[0] >= 256)
|
||||
@ -160,11 +160,11 @@ u256 EVMInstructionInterpreter::eval(
|
||||
return v;
|
||||
}
|
||||
}
|
||||
case Instruction::ADDMOD:
|
||||
case InternalInstruction::ADDMOD:
|
||||
return arg[2] == 0 ? 0 : u256((u512(arg[0]) + u512(arg[1])) % arg[2]);
|
||||
case Instruction::MULMOD:
|
||||
case InternalInstruction::MULMOD:
|
||||
return arg[2] == 0 ? 0 : u256((u512(arg[0]) * u512(arg[1])) % arg[2]);
|
||||
case Instruction::SIGNEXTEND:
|
||||
case InternalInstruction::SIGNEXTEND:
|
||||
if (arg[0] >= 31)
|
||||
return arg[1];
|
||||
else
|
||||
@ -179,7 +179,7 @@ u256 EVMInstructionInterpreter::eval(
|
||||
return ret;
|
||||
}
|
||||
// --------------- blockchain stuff ---------------
|
||||
case Instruction::KECCAK256:
|
||||
case InternalInstruction::KECCAK256:
|
||||
{
|
||||
if (!accessMemory(arg[0], arg[1]))
|
||||
return u256("0x1234cafe1234cafe1234cafe") + arg[0];
|
||||
@ -187,26 +187,26 @@ u256 EVMInstructionInterpreter::eval(
|
||||
uint64_t size = uint64_t(arg[1] & uint64_t(-1));
|
||||
return u256(keccak256(readMemory(offset, size)));
|
||||
}
|
||||
case Instruction::ADDRESS:
|
||||
case InternalInstruction::ADDRESS:
|
||||
return h256(m_state.address, h256::AlignRight);
|
||||
case Instruction::BALANCE:
|
||||
case InternalInstruction::BALANCE:
|
||||
if (arg[0] == h256(m_state.address, h256::AlignRight))
|
||||
return m_state.selfbalance;
|
||||
else
|
||||
return m_state.balance;
|
||||
case Instruction::SELFBALANCE:
|
||||
case InternalInstruction::SELFBALANCE:
|
||||
return m_state.selfbalance;
|
||||
case Instruction::ORIGIN:
|
||||
case InternalInstruction::ORIGIN:
|
||||
return h256(m_state.origin, h256::AlignRight);
|
||||
case Instruction::CALLER:
|
||||
case InternalInstruction::CALLER:
|
||||
return h256(m_state.caller, h256::AlignRight);
|
||||
case Instruction::CALLVALUE:
|
||||
case InternalInstruction::CALLVALUE:
|
||||
return m_state.callvalue;
|
||||
case Instruction::CALLDATALOAD:
|
||||
case InternalInstruction::CALLDATALOAD:
|
||||
return readZeroExtended(m_state.calldata, arg[0]);
|
||||
case Instruction::CALLDATASIZE:
|
||||
case InternalInstruction::CALLDATASIZE:
|
||||
return m_state.calldata.size();
|
||||
case Instruction::CALLDATACOPY:
|
||||
case InternalInstruction::CALLDATACOPY:
|
||||
logTrace(_instruction, arg);
|
||||
if (accessMemory(arg[0], arg[2]))
|
||||
copyZeroExtended(
|
||||
@ -214,9 +214,9 @@ u256 EVMInstructionInterpreter::eval(
|
||||
size_t(arg[0]), size_t(arg[1]), size_t(arg[2])
|
||||
);
|
||||
return 0;
|
||||
case Instruction::CODESIZE:
|
||||
case InternalInstruction::CODESIZE:
|
||||
return m_state.code.size();
|
||||
case Instruction::CODECOPY:
|
||||
case InternalInstruction::CODECOPY:
|
||||
logTrace(_instruction, arg);
|
||||
if (accessMemory(arg[0], arg[2]))
|
||||
copyZeroExtended(
|
||||
@ -224,17 +224,17 @@ u256 EVMInstructionInterpreter::eval(
|
||||
size_t(arg[0]), size_t(arg[1]), size_t(arg[2])
|
||||
);
|
||||
return 0;
|
||||
case Instruction::GASPRICE:
|
||||
case InternalInstruction::GASPRICE:
|
||||
return m_state.gasprice;
|
||||
case Instruction::CHAINID:
|
||||
case InternalInstruction::CHAINID:
|
||||
return m_state.chainid;
|
||||
case Instruction::BASEFEE:
|
||||
case InternalInstruction::BASEFEE:
|
||||
return m_state.basefee;
|
||||
case Instruction::EXTCODESIZE:
|
||||
case InternalInstruction::EXTCODESIZE:
|
||||
return u256(keccak256(h256(arg[0]))) & 0xffffff;
|
||||
case Instruction::EXTCODEHASH:
|
||||
case InternalInstruction::EXTCODEHASH:
|
||||
return u256(keccak256(h256(arg[0] + 1)));
|
||||
case Instruction::EXTCODECOPY:
|
||||
case InternalInstruction::EXTCODECOPY:
|
||||
logTrace(_instruction, arg);
|
||||
if (accessMemory(arg[1], arg[3]))
|
||||
// TODO this way extcodecopy and codecopy do the same thing.
|
||||
@ -243,9 +243,9 @@ u256 EVMInstructionInterpreter::eval(
|
||||
size_t(arg[1]), size_t(arg[2]), size_t(arg[3])
|
||||
);
|
||||
return 0;
|
||||
case Instruction::RETURNDATASIZE:
|
||||
case InternalInstruction::RETURNDATASIZE:
|
||||
return m_state.returndata.size();
|
||||
case Instruction::RETURNDATACOPY:
|
||||
case InternalInstruction::RETURNDATACOPY:
|
||||
logTrace(_instruction, arg);
|
||||
if (accessMemory(arg[0], arg[2]))
|
||||
copyZeroExtended(
|
||||
@ -253,87 +253,89 @@ u256 EVMInstructionInterpreter::eval(
|
||||
size_t(arg[0]), size_t(arg[1]), size_t(arg[2])
|
||||
);
|
||||
return 0;
|
||||
case Instruction::BLOCKHASH:
|
||||
case InternalInstruction::BLOCKHASH:
|
||||
if (arg[0] >= m_state.blockNumber || arg[0] + 256 < m_state.blockNumber)
|
||||
return 0;
|
||||
else
|
||||
return 0xaaaaaaaa + (arg[0] - m_state.blockNumber - 256);
|
||||
case Instruction::COINBASE:
|
||||
case InternalInstruction::COINBASE:
|
||||
return h256(m_state.coinbase, h256::AlignRight);
|
||||
case Instruction::TIMESTAMP:
|
||||
case InternalInstruction::TIMESTAMP:
|
||||
return m_state.timestamp;
|
||||
case Instruction::NUMBER:
|
||||
case InternalInstruction::NUMBER:
|
||||
return m_state.blockNumber;
|
||||
case Instruction::DIFFICULTY:
|
||||
case InternalInstruction::DIFFICULTY:
|
||||
// TODO should be properly implemented
|
||||
case InternalInstruction::PREVRANDAO:
|
||||
return m_state.difficulty;
|
||||
case Instruction::GASLIMIT:
|
||||
case InternalInstruction::GASLIMIT:
|
||||
return m_state.gaslimit;
|
||||
// --------------- memory / storage / logs ---------------
|
||||
case Instruction::MLOAD:
|
||||
case InternalInstruction::MLOAD:
|
||||
accessMemory(arg[0], 0x20);
|
||||
return readMemoryWord(arg[0]);
|
||||
case Instruction::MSTORE:
|
||||
case InternalInstruction::MSTORE:
|
||||
accessMemory(arg[0], 0x20);
|
||||
writeMemoryWord(arg[0], arg[1]);
|
||||
return 0;
|
||||
case Instruction::MSTORE8:
|
||||
case InternalInstruction::MSTORE8:
|
||||
accessMemory(arg[0], 1);
|
||||
m_state.memory[arg[0]] = uint8_t(arg[1] & 0xff);
|
||||
return 0;
|
||||
case Instruction::SLOAD:
|
||||
case InternalInstruction::SLOAD:
|
||||
return m_state.storage[h256(arg[0])];
|
||||
case Instruction::SSTORE:
|
||||
case InternalInstruction::SSTORE:
|
||||
m_state.storage[h256(arg[0])] = h256(arg[1]);
|
||||
return 0;
|
||||
case Instruction::PC:
|
||||
case InternalInstruction::PC:
|
||||
return 0x77;
|
||||
case Instruction::MSIZE:
|
||||
case InternalInstruction::MSIZE:
|
||||
return m_state.msize;
|
||||
case Instruction::GAS:
|
||||
case InternalInstruction::GAS:
|
||||
return 0x99;
|
||||
case Instruction::LOG0:
|
||||
case InternalInstruction::LOG0:
|
||||
accessMemory(arg[0], arg[1]);
|
||||
logTrace(_instruction, arg);
|
||||
return 0;
|
||||
case Instruction::LOG1:
|
||||
case InternalInstruction::LOG1:
|
||||
accessMemory(arg[0], arg[1]);
|
||||
logTrace(_instruction, arg);
|
||||
return 0;
|
||||
case Instruction::LOG2:
|
||||
case InternalInstruction::LOG2:
|
||||
accessMemory(arg[0], arg[1]);
|
||||
logTrace(_instruction, arg);
|
||||
return 0;
|
||||
case Instruction::LOG3:
|
||||
case InternalInstruction::LOG3:
|
||||
accessMemory(arg[0], arg[1]);
|
||||
logTrace(_instruction, arg);
|
||||
return 0;
|
||||
case Instruction::LOG4:
|
||||
case InternalInstruction::LOG4:
|
||||
accessMemory(arg[0], arg[1]);
|
||||
logTrace(_instruction, arg);
|
||||
return 0;
|
||||
// --------------- calls ---------------
|
||||
case Instruction::CREATE:
|
||||
case InternalInstruction::CREATE:
|
||||
accessMemory(arg[1], arg[2]);
|
||||
logTrace(_instruction, arg);
|
||||
return (0xcccccc + arg[1]) & u256("0xffffffffffffffffffffffffffffffffffffffff");
|
||||
case Instruction::CREATE2:
|
||||
case InternalInstruction::CREATE2:
|
||||
accessMemory(arg[1], arg[2]);
|
||||
logTrace(_instruction, arg);
|
||||
return (0xdddddd + arg[1]) & u256("0xffffffffffffffffffffffffffffffffffffffff");
|
||||
case Instruction::CALL:
|
||||
case Instruction::CALLCODE:
|
||||
case InternalInstruction::CALL:
|
||||
case InternalInstruction::CALLCODE:
|
||||
// TODO assign returndata
|
||||
accessMemory(arg[3], arg[4]);
|
||||
accessMemory(arg[5], arg[6]);
|
||||
logTrace(_instruction, arg);
|
||||
return arg[0] & 1;
|
||||
case Instruction::DELEGATECALL:
|
||||
case Instruction::STATICCALL:
|
||||
case InternalInstruction::DELEGATECALL:
|
||||
case InternalInstruction::STATICCALL:
|
||||
accessMemory(arg[2], arg[3]);
|
||||
accessMemory(arg[4], arg[5]);
|
||||
logTrace(_instruction, arg);
|
||||
return 0;
|
||||
case Instruction::RETURN:
|
||||
case InternalInstruction::RETURN:
|
||||
{
|
||||
bytes data;
|
||||
if (accessMemory(arg[0], arg[1]))
|
||||
@ -341,92 +343,93 @@ u256 EVMInstructionInterpreter::eval(
|
||||
logTrace(_instruction, arg, data);
|
||||
BOOST_THROW_EXCEPTION(ExplicitlyTerminated());
|
||||
}
|
||||
case Instruction::REVERT:
|
||||
case InternalInstruction::REVERT:
|
||||
accessMemory(arg[0], arg[1]);
|
||||
logTrace(_instruction, arg);
|
||||
m_state.storage.clear();
|
||||
m_state.trace.clear();
|
||||
BOOST_THROW_EXCEPTION(ExplicitlyTerminated());
|
||||
case Instruction::INVALID:
|
||||
case InternalInstruction::INVALID:
|
||||
logTrace(_instruction);
|
||||
m_state.storage.clear();
|
||||
m_state.trace.clear();
|
||||
BOOST_THROW_EXCEPTION(ExplicitlyTerminated());
|
||||
case Instruction::SELFDESTRUCT:
|
||||
case InternalInstruction::SELFDESTRUCT:
|
||||
logTrace(_instruction, arg);
|
||||
m_state.storage.clear();
|
||||
m_state.trace.clear();
|
||||
BOOST_THROW_EXCEPTION(ExplicitlyTerminated());
|
||||
case Instruction::POP:
|
||||
case InternalInstruction::POP:
|
||||
break;
|
||||
// --------------- invalid in strict assembly ---------------
|
||||
case Instruction::JUMP:
|
||||
case Instruction::JUMPI:
|
||||
case Instruction::JUMPDEST:
|
||||
case Instruction::PUSH1:
|
||||
case Instruction::PUSH2:
|
||||
case Instruction::PUSH3:
|
||||
case Instruction::PUSH4:
|
||||
case Instruction::PUSH5:
|
||||
case Instruction::PUSH6:
|
||||
case Instruction::PUSH7:
|
||||
case Instruction::PUSH8:
|
||||
case Instruction::PUSH9:
|
||||
case Instruction::PUSH10:
|
||||
case Instruction::PUSH11:
|
||||
case Instruction::PUSH12:
|
||||
case Instruction::PUSH13:
|
||||
case Instruction::PUSH14:
|
||||
case Instruction::PUSH15:
|
||||
case Instruction::PUSH16:
|
||||
case Instruction::PUSH17:
|
||||
case Instruction::PUSH18:
|
||||
case Instruction::PUSH19:
|
||||
case Instruction::PUSH20:
|
||||
case Instruction::PUSH21:
|
||||
case Instruction::PUSH22:
|
||||
case Instruction::PUSH23:
|
||||
case Instruction::PUSH24:
|
||||
case Instruction::PUSH25:
|
||||
case Instruction::PUSH26:
|
||||
case Instruction::PUSH27:
|
||||
case Instruction::PUSH28:
|
||||
case Instruction::PUSH29:
|
||||
case Instruction::PUSH30:
|
||||
case Instruction::PUSH31:
|
||||
case Instruction::PUSH32:
|
||||
case Instruction::DUP1:
|
||||
case Instruction::DUP2:
|
||||
case Instruction::DUP3:
|
||||
case Instruction::DUP4:
|
||||
case Instruction::DUP5:
|
||||
case Instruction::DUP6:
|
||||
case Instruction::DUP7:
|
||||
case Instruction::DUP8:
|
||||
case Instruction::DUP9:
|
||||
case Instruction::DUP10:
|
||||
case Instruction::DUP11:
|
||||
case Instruction::DUP12:
|
||||
case Instruction::DUP13:
|
||||
case Instruction::DUP14:
|
||||
case Instruction::DUP15:
|
||||
case Instruction::DUP16:
|
||||
case Instruction::SWAP1:
|
||||
case Instruction::SWAP2:
|
||||
case Instruction::SWAP3:
|
||||
case Instruction::SWAP4:
|
||||
case Instruction::SWAP5:
|
||||
case Instruction::SWAP6:
|
||||
case Instruction::SWAP7:
|
||||
case Instruction::SWAP8:
|
||||
case Instruction::SWAP9:
|
||||
case Instruction::SWAP10:
|
||||
case Instruction::SWAP11:
|
||||
case Instruction::SWAP12:
|
||||
case Instruction::SWAP13:
|
||||
case Instruction::SWAP14:
|
||||
case Instruction::SWAP15:
|
||||
case Instruction::SWAP16:
|
||||
case InternalInstruction::JUMP:
|
||||
case InternalInstruction::JUMPI:
|
||||
case InternalInstruction::JUMPDEST:
|
||||
case InternalInstruction::PUSH1:
|
||||
case InternalInstruction::PUSH2:
|
||||
case InternalInstruction::PUSH3:
|
||||
case InternalInstruction::PUSH4:
|
||||
case InternalInstruction::PUSH5:
|
||||
case InternalInstruction::PUSH6:
|
||||
case InternalInstruction::PUSH7:
|
||||
case InternalInstruction::PUSH8:
|
||||
case InternalInstruction::PUSH9:
|
||||
case InternalInstruction::PUSH10:
|
||||
case InternalInstruction::PUSH11:
|
||||
case InternalInstruction::PUSH12:
|
||||
case InternalInstruction::PUSH13:
|
||||
case InternalInstruction::PUSH14:
|
||||
case InternalInstruction::PUSH15:
|
||||
case InternalInstruction::PUSH16:
|
||||
case InternalInstruction::PUSH17:
|
||||
case InternalInstruction::PUSH18:
|
||||
case InternalInstruction::PUSH19:
|
||||
case InternalInstruction::PUSH20:
|
||||
case InternalInstruction::PUSH21:
|
||||
case InternalInstruction::PUSH22:
|
||||
case InternalInstruction::PUSH23:
|
||||
case InternalInstruction::PUSH24:
|
||||
case InternalInstruction::PUSH25:
|
||||
case InternalInstruction::PUSH26:
|
||||
case InternalInstruction::PUSH27:
|
||||
case InternalInstruction::PUSH28:
|
||||
case InternalInstruction::PUSH29:
|
||||
case InternalInstruction::PUSH30:
|
||||
case InternalInstruction::PUSH31:
|
||||
case InternalInstruction::PUSH32:
|
||||
case InternalInstruction::DUP1:
|
||||
case InternalInstruction::DUP2:
|
||||
case InternalInstruction::DUP3:
|
||||
case InternalInstruction::DUP4:
|
||||
case InternalInstruction::DUP5:
|
||||
case InternalInstruction::DUP6:
|
||||
case InternalInstruction::DUP7:
|
||||
case InternalInstruction::DUP8:
|
||||
case InternalInstruction::DUP9:
|
||||
case InternalInstruction::DUP10:
|
||||
case InternalInstruction::DUP11:
|
||||
case InternalInstruction::DUP12:
|
||||
case InternalInstruction::DUP13:
|
||||
case InternalInstruction::DUP14:
|
||||
case InternalInstruction::DUP15:
|
||||
case InternalInstruction::DUP16:
|
||||
case InternalInstruction::SWAP1:
|
||||
case InternalInstruction::SWAP2:
|
||||
case InternalInstruction::SWAP3:
|
||||
case InternalInstruction::SWAP4:
|
||||
case InternalInstruction::SWAP5:
|
||||
case InternalInstruction::SWAP6:
|
||||
case InternalInstruction::SWAP7:
|
||||
case InternalInstruction::SWAP8:
|
||||
case InternalInstruction::SWAP9:
|
||||
case InternalInstruction::SWAP10:
|
||||
case InternalInstruction::SWAP11:
|
||||
case InternalInstruction::SWAP12:
|
||||
case InternalInstruction::SWAP13:
|
||||
case InternalInstruction::SWAP14:
|
||||
case InternalInstruction::SWAP15:
|
||||
case InternalInstruction::SWAP16:
|
||||
case InternalInstruction::MAX_INTERNAL_INSTRUCTION:
|
||||
{
|
||||
yulAssert(false, "");
|
||||
return 0;
|
||||
@ -519,7 +522,7 @@ void EVMInstructionInterpreter::writeMemoryWord(u256 const& _offset, u256 const&
|
||||
|
||||
|
||||
void EVMInstructionInterpreter::logTrace(
|
||||
evmasm::Instruction _instruction,
|
||||
evmasm::InternalInstruction _instruction,
|
||||
std::vector<u256> const& _arguments,
|
||||
bytes const& _data
|
||||
)
|
||||
|
@ -30,7 +30,7 @@
|
||||
|
||||
namespace solidity::evmasm
|
||||
{
|
||||
enum class Instruction: uint8_t;
|
||||
enum class InternalInstruction: uint8_t;
|
||||
}
|
||||
|
||||
namespace solidity::yul
|
||||
@ -71,7 +71,7 @@ public:
|
||||
m_disableMemoryWriteInstructions(_disableMemWriteTrace)
|
||||
{}
|
||||
/// Evaluate instruction
|
||||
u256 eval(evmasm::Instruction _instruction, std::vector<u256> const& _arguments);
|
||||
u256 eval(evmasm::InternalInstruction _instruction, std::vector<u256> const& _arguments);
|
||||
/// Evaluate builtin function
|
||||
u256 evalBuiltin(
|
||||
BuiltinFunctionForEVM const& _fun,
|
||||
@ -95,7 +95,7 @@ private:
|
||||
void writeMemoryWord(u256 const& _offset, u256 const& _value);
|
||||
|
||||
void logTrace(
|
||||
evmasm::Instruction _instruction,
|
||||
evmasm::InternalInstruction _instruction,
|
||||
std::vector<u256> const& _arguments = {},
|
||||
bytes const& _data = {}
|
||||
);
|
||||
|
@ -180,7 +180,7 @@ u256 EwasmBuiltinInterpreter::evalBuiltin(
|
||||
return arg.at(0) & uint32_t(-1);
|
||||
else if (fun == "unreachable")
|
||||
{
|
||||
logTrace(evmasm::Instruction::INVALID, {});
|
||||
logTrace(evmasm::InternalInstruction::INVALID, {});
|
||||
BOOST_THROW_EXCEPTION(ExplicitlyTerminated());
|
||||
}
|
||||
else if (fun == "i64.store")
|
||||
@ -334,7 +334,7 @@ u256 EwasmBuiltinInterpreter::evalEthBuiltin(string const& _fun, vector<uint64_t
|
||||
readAddress(arg[1]);
|
||||
readU128(arg[2]);
|
||||
accessMemory(arg[3], arg[4]);
|
||||
logTrace(evmasm::Instruction::CALL, {});
|
||||
logTrace(evmasm::InternalInstruction::CALL, {});
|
||||
return arg[0] & 1;
|
||||
}
|
||||
else if (_fun == "callDataCopy")
|
||||
@ -355,21 +355,21 @@ u256 EwasmBuiltinInterpreter::evalEthBuiltin(string const& _fun, vector<uint64_t
|
||||
readAddress(arg[1]);
|
||||
readU128(arg[2]);
|
||||
accessMemory(arg[3], arg[4]);
|
||||
logTrace(evmasm::Instruction::CALLCODE, {});
|
||||
logTrace(evmasm::InternalInstruction::CALLCODE, {});
|
||||
return arg[0] & 1;
|
||||
}
|
||||
else if (_fun == "callDelegate")
|
||||
{
|
||||
readAddress(arg[1]);
|
||||
accessMemory(arg[2], arg[3]);
|
||||
logTrace(evmasm::Instruction::DELEGATECALL, {});
|
||||
logTrace(evmasm::InternalInstruction::DELEGATECALL, {});
|
||||
return arg[0] & 1;
|
||||
}
|
||||
else if (_fun == "callStatic")
|
||||
{
|
||||
readAddress(arg[1]);
|
||||
accessMemory(arg[2], arg[3]);
|
||||
logTrace(evmasm::Instruction::STATICCALL, {});
|
||||
logTrace(evmasm::InternalInstruction::STATICCALL, {});
|
||||
return arg[0] & 1;
|
||||
}
|
||||
else if (_fun == "storageStore")
|
||||
@ -412,7 +412,7 @@ u256 EwasmBuiltinInterpreter::evalEthBuiltin(string const& _fun, vector<uint64_t
|
||||
{
|
||||
readU128(arg[0]);
|
||||
accessMemory(arg[1], arg[2]);
|
||||
logTrace(evmasm::Instruction::CREATE, {});
|
||||
logTrace(evmasm::InternalInstruction::CREATE, {});
|
||||
writeAddress(arg[3], h160(0xcccccc + arg[1]));
|
||||
return 1;
|
||||
}
|
||||
@ -478,7 +478,7 @@ u256 EwasmBuiltinInterpreter::evalEthBuiltin(string const& _fun, vector<uint64_t
|
||||
bytes data;
|
||||
accessMemory(arg[0], arg[1]);
|
||||
data = readMemory(arg[0], arg[1]);
|
||||
logTrace(evmasm::Instruction::RETURN, {}, data);
|
||||
logTrace(evmasm::InternalInstruction::RETURN, {}, data);
|
||||
BOOST_THROW_EXCEPTION(ExplicitlyTerminated());
|
||||
}
|
||||
else if (_fun == "revert")
|
||||
@ -486,7 +486,7 @@ u256 EwasmBuiltinInterpreter::evalEthBuiltin(string const& _fun, vector<uint64_t
|
||||
bytes data;
|
||||
accessMemory(arg[0], arg[1]);
|
||||
data = readMemory(arg[0], arg[1]);
|
||||
logTrace(evmasm::Instruction::REVERT, {}, data);
|
||||
logTrace(evmasm::InternalInstruction::REVERT, {}, data);
|
||||
BOOST_THROW_EXCEPTION(ExplicitlyTerminated());
|
||||
}
|
||||
else if (_fun == "getReturnDataSize")
|
||||
@ -505,7 +505,7 @@ u256 EwasmBuiltinInterpreter::evalEthBuiltin(string const& _fun, vector<uint64_t
|
||||
else if (_fun == "selfDestruct")
|
||||
{
|
||||
readAddress(arg[0]);
|
||||
logTrace(evmasm::Instruction::SELFDESTRUCT, {});
|
||||
logTrace(evmasm::InternalInstruction::SELFDESTRUCT, {});
|
||||
BOOST_THROW_EXCEPTION(ExplicitlyTerminated());
|
||||
}
|
||||
else if (_fun == "getBlockTimestamp")
|
||||
@ -595,7 +595,7 @@ u256 EwasmBuiltinInterpreter::readU256(uint64_t _offset, size_t _croppedTo)
|
||||
return value;
|
||||
}
|
||||
|
||||
void EwasmBuiltinInterpreter::logTrace(evmasm::Instruction _instruction, std::vector<u256> const& _arguments, bytes const& _data)
|
||||
void EwasmBuiltinInterpreter::logTrace(evmasm::InternalInstruction _instruction, std::vector<u256> const& _arguments, bytes const& _data)
|
||||
{
|
||||
logTrace(evmasm::instructionInfo(_instruction).name, _arguments, _data);
|
||||
}
|
||||
|
@ -30,7 +30,7 @@
|
||||
|
||||
namespace solidity::evmasm
|
||||
{
|
||||
enum class Instruction: uint8_t;
|
||||
enum class InternalInstruction: uint8_t;
|
||||
}
|
||||
|
||||
namespace solidity::yul
|
||||
@ -127,7 +127,7 @@ private:
|
||||
util::h256 readBytes32(uint64_t _offset) { accessMemory(_offset, 32); return util::h256(readMemory(_offset, 32)); }
|
||||
util::h160 readAddress(uint64_t _offset) { accessMemory(_offset, 20); return util::h160(readMemory(_offset, 20)); }
|
||||
|
||||
void logTrace(evmasm::Instruction _instruction, std::vector<u256> const& _arguments = {}, bytes const& _data = {});
|
||||
void logTrace(evmasm::InternalInstruction _instruction, std::vector<u256> const& _arguments = {}, bytes const& _data = {});
|
||||
/// Appends a log to the trace representing an instruction or similar operation by string,
|
||||
/// with arguments and auxiliary data (if nonempty).
|
||||
void logTrace(std::string const& _pseudoInstruction, std::vector<u256> const& _arguments = {}, bytes const& _data = {});
|
||||
|
Loading…
Reference in New Issue
Block a user