mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
initial attempt
This commit is contained in:
parent
056c4593e3
commit
a467bdcb3c
@ -558,6 +558,26 @@ LinkerObject const& Assembly::assemble() const
|
|||||||
case Operation:
|
case Operation:
|
||||||
ret.bytecode.push_back(static_cast<uint8_t>(i.instruction()));
|
ret.bytecode.push_back(static_cast<uint8_t>(i.instruction()));
|
||||||
break;
|
break;
|
||||||
|
case Swap:
|
||||||
|
assertThrow(i.data() > 0 && i.data() <= maxSwap(), AssemblyException, "Invalid swap.");
|
||||||
|
if (i.data() <= 16)
|
||||||
|
ret.bytecode.push_back(static_cast<uint8_t>(evmasm::Instruction::SWAP1 + (i.data() - 1)));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret.bytecode.push_back(static_cast<uint8_t>(evmasm::Instruction::SWAP_N));
|
||||||
|
ret.bytecode.push_back(static_cast<uint8_t>(i.data() - 1));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Dup:
|
||||||
|
assertThrow(i.data() > 0 && i.data() <= maxDup(), AssemblyException, "Invalid dup.");
|
||||||
|
if (i.data() <= 16)
|
||||||
|
ret.bytecode.push_back(static_cast<uint8_t>(evmasm::Instruction::DUP1 + (i.data() - 1)));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret.bytecode.push_back(static_cast<uint8_t>(evmasm::Instruction::DUP_N));
|
||||||
|
ret.bytecode.push_back(static_cast<uint8_t>(i.data() - 1));
|
||||||
|
}
|
||||||
|
break;
|
||||||
case Push:
|
case Push:
|
||||||
{
|
{
|
||||||
unsigned b = max<unsigned>(1, numberEncodingSize(i.data()));
|
unsigned b = max<unsigned>(1, numberEncodingSize(i.data()));
|
||||||
|
@ -83,6 +83,23 @@ public:
|
|||||||
append(AssemblyItem(std::move(_data), _arguments, _returnVariables));
|
append(AssemblyItem(std::move(_data), _arguments, _returnVariables));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void appendSwap(unsigned _height)
|
||||||
|
{
|
||||||
|
append(AssemblyItem(AssemblyItemType::Swap, _height));
|
||||||
|
}
|
||||||
|
void appendDup(unsigned _height)
|
||||||
|
{
|
||||||
|
append(AssemblyItem(AssemblyItemType::Dup, _height));
|
||||||
|
}
|
||||||
|
unsigned maxDup() const
|
||||||
|
{
|
||||||
|
return 16;
|
||||||
|
}
|
||||||
|
unsigned maxSwap() const
|
||||||
|
{
|
||||||
|
return 16;
|
||||||
|
}
|
||||||
|
|
||||||
AssemblyItem appendJump() { auto ret = append(newPushTag()); append(Instruction::JUMP); return ret; }
|
AssemblyItem appendJump() { auto ret = append(newPushTag()); append(Instruction::JUMP); return ret; }
|
||||||
AssemblyItem appendJumpI() { auto ret = append(newPushTag()); append(Instruction::JUMPI); return ret; }
|
AssemblyItem appendJumpI() { auto ret = append(newPushTag()); append(Instruction::JUMPI); return ret; }
|
||||||
AssemblyItem appendJump(AssemblyItem const& _tag) { auto ret = append(_tag.pushTag()); append(Instruction::JUMP); return ret; }
|
AssemblyItem appendJump(AssemblyItem const& _tag) { auto ret = append(_tag.pushTag()); append(Instruction::JUMP); return ret; }
|
||||||
|
@ -123,6 +123,12 @@ size_t AssemblyItem::bytesRequired(size_t _addressLength, Precision _precision)
|
|||||||
case Operation:
|
case Operation:
|
||||||
case Tag: // 1 byte for the JUMPDEST
|
case Tag: // 1 byte for the JUMPDEST
|
||||||
return 1;
|
return 1;
|
||||||
|
case Swap:
|
||||||
|
case Dup:
|
||||||
|
if (data() <= 16)
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
return 2;
|
||||||
case Push:
|
case Push:
|
||||||
return 1 + max<size_t>(1, numberEncodingSize(data()));
|
return 1 + max<size_t>(1, numberEncodingSize(data()));
|
||||||
case PushSubSize:
|
case PushSubSize:
|
||||||
@ -173,6 +179,10 @@ size_t AssemblyItem::arguments() const
|
|||||||
return get<0>(*m_verbatimBytecode);
|
return get<0>(*m_verbatimBytecode);
|
||||||
else if (type() == AssignImmutable)
|
else if (type() == AssignImmutable)
|
||||||
return 2;
|
return 2;
|
||||||
|
else if (type() == Swap)
|
||||||
|
return static_cast<size_t>(data());
|
||||||
|
else if (type() == Dup)
|
||||||
|
return static_cast<size_t>(data());
|
||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -183,6 +193,10 @@ size_t AssemblyItem::returnValues() const
|
|||||||
{
|
{
|
||||||
case Operation:
|
case Operation:
|
||||||
return static_cast<size_t>(instructionInfo(instruction()).ret);
|
return static_cast<size_t>(instructionInfo(instruction()).ret);
|
||||||
|
case Swap:
|
||||||
|
return static_cast<size_t>(data());
|
||||||
|
case Dup:
|
||||||
|
return static_cast<size_t>(data()) + 1;
|
||||||
case Push:
|
case Push:
|
||||||
case PushTag:
|
case PushTag:
|
||||||
case PushData:
|
case PushData:
|
||||||
@ -210,7 +224,11 @@ bool AssemblyItem::canBeFunctional() const
|
|||||||
switch (m_type)
|
switch (m_type)
|
||||||
{
|
{
|
||||||
case Operation:
|
case Operation:
|
||||||
return !isDupInstruction(instruction()) && !isSwapInstruction(instruction());
|
return !(m_instruction >= Instruction::SWAP1 && m_instruction <= Instruction::SWAP16) &&
|
||||||
|
!(m_instruction >= Instruction::DUP1 && m_instruction <= Instruction::DUP16) &&
|
||||||
|
m_instruction != Instruction::SWAP_N &&
|
||||||
|
m_instruction != Instruction::DUP_N
|
||||||
|
;
|
||||||
case Push:
|
case Push:
|
||||||
case PushTag:
|
case PushTag:
|
||||||
case PushData:
|
case PushData:
|
||||||
@ -254,6 +272,16 @@ string AssemblyItem::toAssemblyText(Assembly const& _assembly) const
|
|||||||
text = util::toLower(instructionInfo(instruction()).name);
|
text = util::toLower(instructionInfo(instruction()).name);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case Swap:
|
||||||
|
{
|
||||||
|
text = "swap" + to_string(data());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Dup:
|
||||||
|
{
|
||||||
|
text = "dup" + to_string(data());
|
||||||
|
break;
|
||||||
|
}
|
||||||
case Push:
|
case Push:
|
||||||
text = toHex(toCompactBigEndian(data(), 1), util::HexPrefix::Add);
|
text = toHex(toCompactBigEndian(data(), 1), util::HexPrefix::Add);
|
||||||
break;
|
break;
|
||||||
@ -332,6 +360,12 @@ ostream& solidity::evmasm::operator<<(ostream& _out, AssemblyItem const& _item)
|
|||||||
if (_item.instruction() == Instruction::JUMP || _item.instruction() == Instruction::JUMPI)
|
if (_item.instruction() == Instruction::JUMP || _item.instruction() == Instruction::JUMPI)
|
||||||
_out << "\t" << _item.getJumpTypeAsString();
|
_out << "\t" << _item.getJumpTypeAsString();
|
||||||
break;
|
break;
|
||||||
|
case Swap:
|
||||||
|
_out << "SWAP" << dec << _item.data();
|
||||||
|
break;
|
||||||
|
case Dup:
|
||||||
|
_out << "DUP" << dec << _item.data();
|
||||||
|
break;
|
||||||
case Push:
|
case Push:
|
||||||
_out << " PUSH " << hex << _item.data() << dec;
|
_out << " PUSH " << hex << _item.data() << dec;
|
||||||
break;
|
break;
|
||||||
|
@ -39,6 +39,8 @@ enum AssemblyItemType
|
|||||||
{
|
{
|
||||||
UndefinedItem,
|
UndefinedItem,
|
||||||
Operation,
|
Operation,
|
||||||
|
Swap,
|
||||||
|
Dup,
|
||||||
Push,
|
Push,
|
||||||
PushTag,
|
PushTag,
|
||||||
PushSub,
|
PushSub,
|
||||||
@ -70,7 +72,21 @@ public:
|
|||||||
m_type(Operation),
|
m_type(Operation),
|
||||||
m_instruction(_i),
|
m_instruction(_i),
|
||||||
m_location(std::move(_location))
|
m_location(std::move(_location))
|
||||||
{}
|
{
|
||||||
|
// TODO: avoid this on call sites instead
|
||||||
|
if (_i >= Instruction::SWAP1 && _i <= Instruction::SWAP16)
|
||||||
|
{
|
||||||
|
m_type = Swap;
|
||||||
|
m_data = std::make_shared<u256>(static_cast<unsigned>(_i) - static_cast<unsigned>(Instruction::SWAP1) + 1);
|
||||||
|
m_instruction = {};
|
||||||
|
}
|
||||||
|
else if (_i >= Instruction::DUP1 && _i <= Instruction::DUP16)
|
||||||
|
{
|
||||||
|
m_type = Dup;
|
||||||
|
m_data = std::make_shared<u256>(static_cast<unsigned>(_i) - static_cast<unsigned>(Instruction::DUP1) + 1);
|
||||||
|
m_instruction = {};
|
||||||
|
}
|
||||||
|
}
|
||||||
AssemblyItem(AssemblyItemType _type, u256 _data = 0, langutil::SourceLocation _location = langutil::SourceLocation()):
|
AssemblyItem(AssemblyItemType _type, u256 _data = 0, langutil::SourceLocation _location = langutil::SourceLocation()):
|
||||||
m_type(_type),
|
m_type(_type),
|
||||||
m_location(std::move(_location))
|
m_location(std::move(_location))
|
||||||
@ -144,10 +160,9 @@ public:
|
|||||||
return data() < _other.data();
|
return data() < _other.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Shortcut that avoids constructing an AssemblyItem just to perform the comparison.
|
|
||||||
bool operator==(Instruction _instr) const
|
bool operator==(Instruction _instr) const
|
||||||
{
|
{
|
||||||
return type() == Operation && instruction() == _instr;
|
return (*this) == AssemblyItem(_instr);
|
||||||
}
|
}
|
||||||
bool operator!=(Instruction _instr) const { return !operator==(_instr); }
|
bool operator!=(Instruction _instr) const { return !operator==(_instr); }
|
||||||
|
|
||||||
|
@ -95,7 +95,7 @@ void CommonSubexpressionEliminator::optimizeBreakingItem()
|
|||||||
Id condition = m_state.stackElement(m_state.stackHeight() - 1, itemLocation);
|
Id condition = m_state.stackElement(m_state.stackHeight() - 1, itemLocation);
|
||||||
if (classes.knownNonZero(condition))
|
if (classes.knownNonZero(condition))
|
||||||
{
|
{
|
||||||
feedItem(AssemblyItem(Instruction::SWAP1, itemLocation), true);
|
feedItem(AssemblyItem(AssemblyItemType::Swap, 1, itemLocation), true);
|
||||||
feedItem(AssemblyItem(Instruction::POP, itemLocation), true);
|
feedItem(AssemblyItem(Instruction::POP, itemLocation), true);
|
||||||
|
|
||||||
AssemblyItem item(Instruction::JUMP, itemLocation);
|
AssemblyItem item(Instruction::JUMP, itemLocation);
|
||||||
@ -397,7 +397,7 @@ void CSECodeGenerator::generateClassElement(Id _c, bool _allowSequenced)
|
|||||||
|
|
||||||
while (SemanticInformation::isCommutativeOperation(*expr.item) &&
|
while (SemanticInformation::isCommutativeOperation(*expr.item) &&
|
||||||
!m_generatedItems.empty() &&
|
!m_generatedItems.empty() &&
|
||||||
m_generatedItems.back() == AssemblyItem(Instruction::SWAP1))
|
m_generatedItems.back() == AssemblyItem(AssemblyItemType::Swap, 1))
|
||||||
// this will not append a swap but remove the one that is already there
|
// this will not append a swap but remove the one that is already there
|
||||||
appendOrRemoveSwap(m_stackHeight - 1, itemLocation);
|
appendOrRemoveSwap(m_stackHeight - 1, itemLocation);
|
||||||
for (size_t i = 0; i < arguments.size(); ++i)
|
for (size_t i = 0; i < arguments.size(); ++i)
|
||||||
@ -474,7 +474,7 @@ void CSECodeGenerator::appendDup(int _fromPosition, SourceLocation const& _locat
|
|||||||
int instructionNum = 1 + m_stackHeight - _fromPosition;
|
int instructionNum = 1 + m_stackHeight - _fromPosition;
|
||||||
assertThrow(instructionNum <= 16, StackTooDeepException, util::stackTooDeepString);
|
assertThrow(instructionNum <= 16, StackTooDeepException, util::stackTooDeepString);
|
||||||
assertThrow(1 <= instructionNum, OptimizerException, "Invalid stack access.");
|
assertThrow(1 <= instructionNum, OptimizerException, "Invalid stack access.");
|
||||||
appendItem(AssemblyItem(dupInstruction(static_cast<unsigned>(instructionNum)), _location));
|
appendItem(AssemblyItem(AssemblyItemType::Dup, instructionNum, _location));
|
||||||
m_stack[m_stackHeight] = m_stack[_fromPosition];
|
m_stack[m_stackHeight] = m_stack[_fromPosition];
|
||||||
m_classPositions[m_stack[m_stackHeight]].insert(m_stackHeight);
|
m_classPositions[m_stack[m_stackHeight]].insert(m_stackHeight);
|
||||||
}
|
}
|
||||||
@ -487,7 +487,7 @@ void CSECodeGenerator::appendOrRemoveSwap(int _fromPosition, SourceLocation cons
|
|||||||
int instructionNum = m_stackHeight - _fromPosition;
|
int instructionNum = m_stackHeight - _fromPosition;
|
||||||
assertThrow(instructionNum <= 16, StackTooDeepException, util::stackTooDeepString);
|
assertThrow(instructionNum <= 16, StackTooDeepException, util::stackTooDeepString);
|
||||||
assertThrow(1 <= instructionNum, OptimizerException, "Invalid stack access.");
|
assertThrow(1 <= instructionNum, OptimizerException, "Invalid stack access.");
|
||||||
appendItem(AssemblyItem(swapInstruction(static_cast<unsigned>(instructionNum)), _location));
|
appendItem(AssemblyItem(AssemblyItemType::Swap, instructionNum, _location));
|
||||||
|
|
||||||
if (m_stack[m_stackHeight] != m_stack[_fromPosition])
|
if (m_stack[m_stackHeight] != m_stack[_fromPosition])
|
||||||
{
|
{
|
||||||
|
@ -85,6 +85,12 @@ bigint ConstantOptimisationMethod::simpleRunGas(AssemblyItems const& _items)
|
|||||||
for (AssemblyItem const& item: _items)
|
for (AssemblyItem const& item: _items)
|
||||||
if (item.type() == Push)
|
if (item.type() == Push)
|
||||||
gas += GasMeter::runGas(Instruction::PUSH1);
|
gas += GasMeter::runGas(Instruction::PUSH1);
|
||||||
|
else if (item.type() == Swap)
|
||||||
|
// TODO
|
||||||
|
gas += GasMeter::runGas(Instruction::SWAP1);
|
||||||
|
else if (item.type() == Dup)
|
||||||
|
// TODO
|
||||||
|
gas += GasMeter::runGas(Instruction::DUP1);
|
||||||
else if (item.type() == Operation)
|
else if (item.type() == Operation)
|
||||||
{
|
{
|
||||||
if (item.instruction() == Instruction::EXP)
|
if (item.instruction() == Instruction::EXP)
|
||||||
@ -167,21 +173,21 @@ AssemblyItems const& CodeCopyMethod::copyRoutine()
|
|||||||
|
|
||||||
// back up memory
|
// back up memory
|
||||||
// mload(0)
|
// mload(0)
|
||||||
Instruction::DUP1,
|
AssemblyItem(Dup, 1),
|
||||||
Instruction::MLOAD,
|
Instruction::MLOAD,
|
||||||
|
|
||||||
// codecopy(0, <offset>, 32)
|
// codecopy(0, <offset>, 32)
|
||||||
u256(32),
|
u256(32),
|
||||||
AssemblyItem(PushData, u256(1) << 16), // replaced above in actualCopyRoutine[4]
|
AssemblyItem(PushData, u256(1) << 16), // replaced above in actualCopyRoutine[4]
|
||||||
Instruction::DUP4,
|
AssemblyItem(Dup, 4),
|
||||||
Instruction::CODECOPY,
|
Instruction::CODECOPY,
|
||||||
|
|
||||||
// mload(0)
|
// mload(0)
|
||||||
Instruction::DUP2,
|
AssemblyItem(Dup, 2),
|
||||||
Instruction::MLOAD,
|
Instruction::MLOAD,
|
||||||
|
|
||||||
// restore original memory
|
// restore original memory
|
||||||
Instruction::SWAP2,
|
AssemblyItem(Swap, 2),
|
||||||
Instruction::MSTORE
|
Instruction::MSTORE
|
||||||
};
|
};
|
||||||
return copyRoutine;
|
return copyRoutine;
|
||||||
|
@ -175,6 +175,9 @@ enum class Instruction: uint8_t
|
|||||||
LOG3, ///< Makes a log entry; 3 topics.
|
LOG3, ///< Makes a log entry; 3 topics.
|
||||||
LOG4, ///< Makes a log entry; 4 topics.
|
LOG4, ///< Makes a log entry; 4 topics.
|
||||||
|
|
||||||
|
SWAP_N = 0xB0,
|
||||||
|
DUP_N,
|
||||||
|
|
||||||
CREATE = 0xf0, ///< create a new account with associated code
|
CREATE = 0xf0, ///< create a new account with associated code
|
||||||
CALL, ///< message-call into an account
|
CALL, ///< message-call into an account
|
||||||
CALLCODE, ///< message-call with another account's code only
|
CALLCODE, ///< message-call with another account's code only
|
||||||
@ -209,36 +212,12 @@ inline bool isPushInstruction(Instruction _inst)
|
|||||||
return Instruction::PUSH1 <= _inst && _inst <= Instruction::PUSH32;
|
return Instruction::PUSH1 <= _inst && _inst <= Instruction::PUSH32;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @returns true if the instruction is a DUP
|
|
||||||
inline bool isDupInstruction(Instruction _inst)
|
|
||||||
{
|
|
||||||
return Instruction::DUP1 <= _inst && _inst <= Instruction::DUP16;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @returns true if the instruction is a SWAP
|
|
||||||
inline bool isSwapInstruction(Instruction _inst)
|
|
||||||
{
|
|
||||||
return Instruction::SWAP1 <= _inst && _inst <= Instruction::SWAP16;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @returns true if the instruction is a LOG
|
/// @returns true if the instruction is a LOG
|
||||||
inline bool isLogInstruction(Instruction _inst)
|
inline bool isLogInstruction(Instruction _inst)
|
||||||
{
|
{
|
||||||
return Instruction::LOG0 <= _inst && _inst <= Instruction::LOG4;
|
return Instruction::LOG0 <= _inst && _inst <= Instruction::LOG4;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @returns the number of PUSH Instruction _inst
|
|
||||||
inline unsigned getPushNumber(Instruction _inst)
|
|
||||||
{
|
|
||||||
return static_cast<uint8_t>(_inst) - unsigned(Instruction::PUSH1) + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @returns the number of DUP Instruction _inst
|
|
||||||
inline unsigned getDupNumber(Instruction _inst)
|
|
||||||
{
|
|
||||||
return static_cast<uint8_t>(_inst) - unsigned(Instruction::DUP1) + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @returns the number of SWAP Instruction _inst
|
/// @returns the number of SWAP Instruction _inst
|
||||||
inline unsigned getSwapNumber(Instruction _inst)
|
inline unsigned getSwapNumber(Instruction _inst)
|
||||||
{
|
{
|
||||||
@ -258,20 +237,6 @@ inline Instruction pushInstruction(unsigned _number)
|
|||||||
return Instruction(unsigned(Instruction::PUSH1) + _number - 1);
|
return Instruction(unsigned(Instruction::PUSH1) + _number - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @returns the DUP<_number> instruction
|
|
||||||
inline Instruction dupInstruction(unsigned _number)
|
|
||||||
{
|
|
||||||
assertThrow(1 <= _number && _number <= 16, InvalidOpcode, std::string("Invalid DUP instruction requested (") + std::to_string(_number) + ").");
|
|
||||||
return Instruction(unsigned(Instruction::DUP1) + _number - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @returns the SWAP<_number> instruction
|
|
||||||
inline Instruction swapInstruction(unsigned _number)
|
|
||||||
{
|
|
||||||
assertThrow(1 <= _number && _number <= 16, InvalidOpcode, std::string("Invalid SWAP instruction requested (") + std::to_string(_number) + ").");
|
|
||||||
return Instruction(unsigned(Instruction::SWAP1) + _number - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @returns the LOG<_number> instruction
|
/// @returns the LOG<_number> instruction
|
||||||
inline Instruction logInstruction(unsigned _number)
|
inline Instruction logInstruction(unsigned _number)
|
||||||
{
|
{
|
||||||
|
@ -118,6 +118,27 @@ KnownState::StoreOperation KnownState::feedItem(AssemblyItem const& _item, bool
|
|||||||
m_expressionClasses->newClass(_item.location())
|
m_expressionClasses->newClass(_item.location())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
else if (_item.type() == Dup)
|
||||||
|
{
|
||||||
|
// TODO: check
|
||||||
|
setStackElement(
|
||||||
|
m_stackHeight + 1,
|
||||||
|
stackElement(
|
||||||
|
m_stackHeight - static_cast<int>(_item.data() - 1),
|
||||||
|
_item.location()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
m_stackHeight++;
|
||||||
|
}
|
||||||
|
else if (_item.type() == Swap)
|
||||||
|
{
|
||||||
|
// TODO: check
|
||||||
|
swapStackElements(
|
||||||
|
m_stackHeight,
|
||||||
|
m_stackHeight - 1 - static_cast<int>(_item.data() - 1),
|
||||||
|
_item.location()
|
||||||
|
);
|
||||||
|
}
|
||||||
else if (_item.type() != Operation)
|
else if (_item.type() != Operation)
|
||||||
{
|
{
|
||||||
assertThrow(_item.deposit() == 1, InvalidDeposit, "");
|
assertThrow(_item.deposit() == 1, InvalidDeposit, "");
|
||||||
|
@ -159,11 +159,13 @@ struct OpReturnRevert: SimplePeepholeOptimizerMethod<OpReturnRevert>
|
|||||||
if (
|
if (
|
||||||
(_returnRevert == Instruction::RETURN || _returnRevert == Instruction::REVERT) &&
|
(_returnRevert == Instruction::RETURN || _returnRevert == Instruction::REVERT) &&
|
||||||
_push.type() == Push &&
|
_push.type() == Push &&
|
||||||
(_pushOrDup.type() == Push || _pushOrDup == dupInstruction(1))
|
(_pushOrDup.type() == Push || ((_pushOrDup.type() == Dup && _pushOrDup.data() == 1) || _pushOrDup == Instruction::DUP1))
|
||||||
)
|
)
|
||||||
if (
|
if (
|
||||||
(_op.type() == Operation && !instructionInfo(_op.instruction()).sideEffects) ||
|
(_op.type() == Operation && !instructionInfo(_op.instruction()).sideEffects) ||
|
||||||
_op.type() == Push
|
_op.type() == Push ||
|
||||||
|
_op.type() == Swap ||
|
||||||
|
_op.type() == Dup
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
*_out = _push;
|
*_out = _push;
|
||||||
@ -190,7 +192,7 @@ struct DoublePush: SimplePeepholeOptimizerMethod<DoublePush>
|
|||||||
if (_push1.type() == Push && _push2.type() == Push && _push1.data() == _push2.data())
|
if (_push1.type() == Push && _push2.type() == Push && _push1.data() == _push2.data())
|
||||||
{
|
{
|
||||||
*_out = _push1;
|
*_out = _push1;
|
||||||
*_out = {Instruction::DUP1, _push2.location()};
|
*_out = AssemblyItem(Dup, 1, _push2.location());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -204,7 +206,10 @@ struct CommutativeSwap: SimplePeepholeOptimizerMethod<CommutativeSwap>
|
|||||||
{
|
{
|
||||||
// Remove SWAP1 if following instruction is commutative
|
// Remove SWAP1 if following instruction is commutative
|
||||||
if (
|
if (
|
||||||
_swap == Instruction::SWAP1 &&
|
(
|
||||||
|
_swap == Instruction::SWAP1 ||
|
||||||
|
_swap == AssemblyItem(Swap, 1)
|
||||||
|
) &&
|
||||||
SemanticInformation::isCommutativeOperation(_op)
|
SemanticInformation::isCommutativeOperation(_op)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
@ -228,7 +233,10 @@ struct SwapComparison: SimplePeepholeOptimizerMethod<SwapComparison>
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (
|
if (
|
||||||
_swap == Instruction::SWAP1 &&
|
(
|
||||||
|
_swap == Instruction::SWAP1 ||
|
||||||
|
_swap == AssemblyItem(Swap, 1)
|
||||||
|
) &&
|
||||||
_op.type() == Operation &&
|
_op.type() == Operation &&
|
||||||
swappableOps.count(_op.instruction())
|
swappableOps.count(_op.instruction())
|
||||||
)
|
)
|
||||||
@ -250,10 +258,33 @@ struct DupSwap: SimplePeepholeOptimizerMethod<DupSwap>
|
|||||||
std::back_insert_iterator<AssemblyItems> _out
|
std::back_insert_iterator<AssemblyItems> _out
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
auto dupNum = [](AssemblyItem const& _item) -> std::optional<unsigned> {
|
||||||
|
if (_item.type() == AssemblyItemType::Dup)
|
||||||
|
return static_cast<unsigned>(_item.data());
|
||||||
|
else if (
|
||||||
|
_item.type() == AssemblyItemType::Operation &&
|
||||||
|
_item.instruction() >= Instruction::DUP1 &&
|
||||||
|
_item.instruction() <= Instruction::DUP16
|
||||||
|
)
|
||||||
|
return static_cast<unsigned>(_item.instruction()) - static_cast<unsigned>(Instruction::DUP1) + 1;
|
||||||
|
return nullopt;
|
||||||
|
};
|
||||||
|
auto swapNum = [](AssemblyItem const& _item) -> std::optional<unsigned> {
|
||||||
|
if (_item.type() == AssemblyItemType::Swap)
|
||||||
|
return static_cast<unsigned>(_item.data());
|
||||||
|
else if (
|
||||||
|
_item.type() == AssemblyItemType::Operation &&
|
||||||
|
_item.instruction() >= Instruction::SWAP1 &&
|
||||||
|
_item.instruction() <= Instruction::SWAP16
|
||||||
|
)
|
||||||
|
return static_cast<unsigned>(_item.instruction()) - static_cast<unsigned>(Instruction::SWAP1) + 1;
|
||||||
|
return nullopt;
|
||||||
|
};
|
||||||
if (
|
if (
|
||||||
SemanticInformation::isDupInstruction(_dupN) &&
|
dupNum(_dupN).has_value() && swapNum(_swapN).has_value() && dupNum(_dupN) == swapNum(_swapN)
|
||||||
SemanticInformation::isSwapInstruction(_swapN) &&
|
/* _dupN.type() == AssemblyItemType::Dup &&
|
||||||
getDupNumber(_dupN.instruction()) == getSwapNumber(_swapN.instruction())
|
_swapN.type() == AssemblyItemType::Swap &&
|
||||||
|
_dupN.data() == _swapN.data()*/
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
*_out = _dupN;
|
*_out = _dupN;
|
||||||
|
@ -169,6 +169,8 @@ bool SemanticInformation::breaksCSEAnalysisBlock(AssemblyItem const& _item, bool
|
|||||||
case PushData:
|
case PushData:
|
||||||
case PushLibraryAddress:
|
case PushLibraryAddress:
|
||||||
case PushImmutable:
|
case PushImmutable:
|
||||||
|
case Swap:
|
||||||
|
case Dup:
|
||||||
return false;
|
return false;
|
||||||
case evmasm::Operation:
|
case evmasm::Operation:
|
||||||
{
|
{
|
||||||
@ -218,16 +220,27 @@ bool SemanticInformation::isCommutativeOperation(AssemblyItem const& _item)
|
|||||||
|
|
||||||
bool SemanticInformation::isDupInstruction(AssemblyItem const& _item)
|
bool SemanticInformation::isDupInstruction(AssemblyItem const& _item)
|
||||||
{
|
{
|
||||||
if (_item.type() != evmasm::Operation)
|
return _item.type() == evmasm::Dup ||
|
||||||
return false;
|
(_item.type() == evmasm::Operation &&
|
||||||
return evmasm::isDupInstruction(_item.instruction());
|
(
|
||||||
|
(_item.instruction() >= Instruction::DUP1 && _item.instruction() <= Instruction::DUP16) ||
|
||||||
|
(_item.instruction() == Instruction::DUP_N)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SemanticInformation::isSwapInstruction(AssemblyItem const& _item)
|
bool SemanticInformation::isSwapInstruction(AssemblyItem const& _item)
|
||||||
{
|
{
|
||||||
if (_item.type() != evmasm::Operation)
|
return _item.type() == evmasm::Swap ||
|
||||||
return false;
|
(_item.type() == evmasm::Operation &&
|
||||||
return evmasm::isSwapInstruction(_item.instruction());
|
(
|
||||||
|
(_item.instruction() >= Instruction::SWAP1 && _item.instruction() <= Instruction::SWAP16) ||
|
||||||
|
(_item.instruction() == Instruction::SWAP_N)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SemanticInformation::isJumpInstruction(AssemblyItem const& _item)
|
bool SemanticInformation::isJumpInstruction(AssemblyItem const& _item)
|
||||||
|
@ -65,7 +65,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
|
|||||||
// stack: source_ref [source_length] target_ref
|
// stack: source_ref [source_length] target_ref
|
||||||
// store target_ref
|
// store target_ref
|
||||||
for (unsigned i = _sourceType.sizeOnStack(); i > 0; --i)
|
for (unsigned i = _sourceType.sizeOnStack(); i > 0; --i)
|
||||||
m_context << swapInstruction(i);
|
m_context << AssemblyItem(AssemblyItemType::Swap, i);
|
||||||
// stack: target_ref source_ref [source_length]
|
// stack: target_ref source_ref [source_length]
|
||||||
|
|
||||||
if (_targetType.isByteArrayOrString())
|
if (_targetType.isByteArrayOrString())
|
||||||
@ -177,7 +177,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
|
|||||||
_context << copyLoopStart;
|
_context << copyLoopStart;
|
||||||
// check for loop condition
|
// check for loop condition
|
||||||
_context
|
_context
|
||||||
<< dupInstruction(3 + byteOffsetSize) << dupInstruction(2 + byteOffsetSize)
|
<< AssemblyItem(AssemblyItemType::Dup, 3 + byteOffsetSize) << AssemblyItem(AssemblyItemType::Dup, 2 + byteOffsetSize)
|
||||||
<< Instruction::GT << Instruction::ISZERO;
|
<< Instruction::GT << Instruction::ISZERO;
|
||||||
evmasm::AssemblyItem copyLoopEnd = _context.appendConditionalJump();
|
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]
|
// stack: target_ref target_data_end source_data_pos target_data_pos source_data_end [target_byte_offset] [source_byte_offset]
|
||||||
@ -213,7 +213,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
|
|||||||
// We might copy too much if there is padding at the last element, but this way end
|
// We might copy too much if there is padding at the last element, but this way end
|
||||||
// checking is easier.
|
// checking is easier.
|
||||||
// stack: target_ref target_data_end source_data_pos target_data_pos source_data_end [target_byte_offset] [source_byte_offset]
|
// stack: target_ref target_data_end source_data_pos target_data_pos source_data_end [target_byte_offset] [source_byte_offset]
|
||||||
_context << dupInstruction(3 + byteOffsetSize);
|
_context << AssemblyItem(AssemblyItemType::Dup, 3 + byteOffsetSize);
|
||||||
if (_sourceType.location() == DataLocation::Storage)
|
if (_sourceType.location() == DataLocation::Storage)
|
||||||
{
|
{
|
||||||
if (haveByteOffsetSource)
|
if (haveByteOffsetSource)
|
||||||
@ -233,9 +233,9 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
|
|||||||
util::stackTooDeepString
|
util::stackTooDeepString
|
||||||
);
|
);
|
||||||
// fetch target storage reference
|
// fetch target storage reference
|
||||||
_context << dupInstruction(2 + byteOffsetSize + sourceBaseType->sizeOnStack());
|
_context << AssemblyItem(AssemblyItemType::Dup, 2 + byteOffsetSize + sourceBaseType->sizeOnStack());
|
||||||
if (haveByteOffsetTarget)
|
if (haveByteOffsetTarget)
|
||||||
_context << dupInstruction(1 + byteOffsetSize + sourceBaseType->sizeOnStack());
|
_context << AssemblyItem(AssemblyItemType::Dup, 1 + byteOffsetSize + sourceBaseType->sizeOnStack());
|
||||||
else
|
else
|
||||||
_context << u256(0);
|
_context << u256(0);
|
||||||
StorageItem(_context, *targetBaseType).storeValue(*sourceBaseType, SourceLocation(), true);
|
StorageItem(_context, *targetBaseType).storeValue(*sourceBaseType, SourceLocation(), true);
|
||||||
@ -246,7 +246,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
|
|||||||
utils.incrementByteOffset(sourceBaseType->storageBytes(), 1, haveByteOffsetTarget ? 5 : 4);
|
utils.incrementByteOffset(sourceBaseType->storageBytes(), 1, haveByteOffsetTarget ? 5 : 4);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_context << swapInstruction(2 + byteOffsetSize);
|
_context << AssemblyItem(AssemblyItemType::Swap, 2 + byteOffsetSize);
|
||||||
if (sourceIsStorage)
|
if (sourceIsStorage)
|
||||||
_context << sourceBaseType->storageSize();
|
_context << sourceBaseType->storageSize();
|
||||||
else if (_sourceType.location() == DataLocation::Memory)
|
else if (_sourceType.location() == DataLocation::Memory)
|
||||||
@ -255,26 +255,26 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
|
|||||||
_context << sourceBaseType->calldataHeadSize();
|
_context << sourceBaseType->calldataHeadSize();
|
||||||
_context
|
_context
|
||||||
<< Instruction::ADD
|
<< Instruction::ADD
|
||||||
<< swapInstruction(2 + byteOffsetSize);
|
<< AssemblyItem(AssemblyItemType::Swap, 2 + byteOffsetSize);
|
||||||
}
|
}
|
||||||
// increment target
|
// increment target
|
||||||
if (haveByteOffsetTarget)
|
if (haveByteOffsetTarget)
|
||||||
utils.incrementByteOffset(targetBaseType->storageBytes(), byteOffsetSize, byteOffsetSize + 2);
|
utils.incrementByteOffset(targetBaseType->storageBytes(), byteOffsetSize, byteOffsetSize + 2);
|
||||||
else
|
else
|
||||||
_context
|
_context
|
||||||
<< swapInstruction(1 + byteOffsetSize)
|
<< AssemblyItem(AssemblyItemType::Swap, 1 + byteOffsetSize)
|
||||||
<< targetBaseType->storageSize()
|
<< targetBaseType->storageSize()
|
||||||
<< Instruction::ADD
|
<< Instruction::ADD
|
||||||
<< swapInstruction(1 + byteOffsetSize);
|
<< AssemblyItem(AssemblyItemType::Swap, 1 + byteOffsetSize);
|
||||||
_context.appendJumpTo(copyLoopStart);
|
_context.appendJumpTo(copyLoopStart);
|
||||||
_context << copyLoopEnd;
|
_context << copyLoopEnd;
|
||||||
if (haveByteOffsetTarget)
|
if (haveByteOffsetTarget)
|
||||||
{
|
{
|
||||||
// clear elements that might be left over in the current slot in target
|
// 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]
|
// 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 << AssemblyItem(AssemblyItemType::Dup, byteOffsetSize) << Instruction::ISZERO;
|
||||||
evmasm::AssemblyItem copyCleanupLoopEnd = _context.appendConditionalJump();
|
evmasm::AssemblyItem copyCleanupLoopEnd = _context.appendConditionalJump();
|
||||||
_context << dupInstruction(2 + byteOffsetSize) << dupInstruction(1 + byteOffsetSize);
|
_context << AssemblyItem(AssemblyItemType::Dup, 2 + byteOffsetSize) << AssemblyItem(AssemblyItemType::Dup, 1 + byteOffsetSize);
|
||||||
StorageItem(_context, *targetBaseType).setToZero(SourceLocation(), true);
|
StorageItem(_context, *targetBaseType).setToZero(SourceLocation(), true);
|
||||||
utils.incrementByteOffset(targetBaseType->storageBytes(), byteOffsetSize, byteOffsetSize + 2);
|
utils.incrementByteOffset(targetBaseType->storageBytes(), byteOffsetSize, byteOffsetSize + 2);
|
||||||
_context.appendJumpTo(copyLoopEnd);
|
_context.appendJumpTo(copyLoopEnd);
|
||||||
@ -510,7 +510,7 @@ void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWord
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// check for loop condition
|
// check for loop condition
|
||||||
m_context << Instruction::DUP1 << dupInstruction(haveByteOffset ? 5 : 4);
|
m_context << Instruction::DUP1 << AssemblyItem(AssemblyItemType::Dup, haveByteOffset ? 5 : 4);
|
||||||
m_context << Instruction::GT;
|
m_context << Instruction::GT;
|
||||||
m_context.appendConditionalJumpTo(loopStart);
|
m_context.appendConditionalJumpTo(loopStart);
|
||||||
// stack here: memory_end_offset storage_data_offset [storage_byte_offset] memory_offset
|
// stack here: memory_end_offset storage_data_offset [storage_byte_offset] memory_offset
|
||||||
@ -1008,7 +1008,7 @@ void ArrayUtils::retrieveLength(ArrayType const& _arrayType, unsigned _stackDept
|
|||||||
m_context << _arrayType.length();
|
m_context << _arrayType.length();
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_context << dupInstruction(1 + _stackDepth);
|
m_context << AssemblyItem(AssemblyItemType::Dup, 1 + _stackDepth);
|
||||||
switch (_arrayType.location())
|
switch (_arrayType.location())
|
||||||
{
|
{
|
||||||
case DataLocation::CallData:
|
case DataLocation::CallData:
|
||||||
@ -1178,19 +1178,19 @@ void ArrayUtils::incrementByteOffset(unsigned _byteSize, unsigned _byteOffsetPos
|
|||||||
// byteOffset = 0;
|
// byteOffset = 0;
|
||||||
// }
|
// }
|
||||||
if (_byteOffsetPosition > 1)
|
if (_byteOffsetPosition > 1)
|
||||||
m_context << swapInstruction(_byteOffsetPosition - 1);
|
m_context << AssemblyItem(AssemblyItemType::Swap, _byteOffsetPosition - 1);
|
||||||
m_context << u256(_byteSize) << Instruction::ADD;
|
m_context << u256(_byteSize) << Instruction::ADD;
|
||||||
if (_byteOffsetPosition > 1)
|
if (_byteOffsetPosition > 1)
|
||||||
m_context << swapInstruction(_byteOffsetPosition - 1);
|
m_context << AssemblyItem(AssemblyItemType::Swap, _byteOffsetPosition - 1);
|
||||||
// compute, X := (byteOffset + byteSize - 1) / 32, should be 1 iff byteOffset + bytesize > 32
|
// compute, X := (byteOffset + byteSize - 1) / 32, should be 1 iff byteOffset + bytesize > 32
|
||||||
m_context
|
m_context
|
||||||
<< u256(32) << dupInstruction(1 + _byteOffsetPosition) << u256(_byteSize - 1)
|
<< u256(32) << AssemblyItem(AssemblyItemType::Dup, 1 + _byteOffsetPosition) << u256(_byteSize - 1)
|
||||||
<< Instruction::ADD << Instruction::DIV;
|
<< Instruction::ADD << Instruction::DIV;
|
||||||
// increment storage offset if X == 1 (just add X to it)
|
// increment storage offset if X == 1 (just add X to it)
|
||||||
// stack: X
|
// stack: X
|
||||||
m_context
|
m_context
|
||||||
<< swapInstruction(_storageOffsetPosition) << dupInstruction(_storageOffsetPosition + 1)
|
<< AssemblyItem(AssemblyItemType::Swap, _storageOffsetPosition) << AssemblyItem(AssemblyItemType::Dup, _storageOffsetPosition + 1)
|
||||||
<< Instruction::ADD << swapInstruction(_storageOffsetPosition);
|
<< Instruction::ADD << AssemblyItem(AssemblyItemType::Swap, _storageOffsetPosition);
|
||||||
// stack: X
|
// stack: X
|
||||||
// set source_byte_offset to zero if X == 1 (using source_byte_offset *= 1 - 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) << Instruction::SUB;
|
||||||
@ -1199,6 +1199,6 @@ void ArrayUtils::incrementByteOffset(unsigned _byteSize, unsigned _byteOffsetPos
|
|||||||
m_context << Instruction::MUL;
|
m_context << Instruction::MUL;
|
||||||
else
|
else
|
||||||
m_context
|
m_context
|
||||||
<< dupInstruction(_byteOffsetPosition + 1) << Instruction::MUL
|
<< AssemblyItem(AssemblyItemType::Dup, _byteOffsetPosition + 1) << Instruction::MUL
|
||||||
<< swapInstruction(_byteOffsetPosition) << Instruction::POP;
|
<< AssemblyItem(AssemblyItemType::Swap, _byteOffsetPosition) << Instruction::POP;
|
||||||
}
|
}
|
||||||
|
@ -419,17 +419,17 @@ void CompilerContext::appendInlineAssembly(
|
|||||||
size_t stackDiff = static_cast<size_t>(_assembly.stackHeight()) - startStackHeight + stackDepth;
|
size_t stackDiff = static_cast<size_t>(_assembly.stackHeight()) - startStackHeight + stackDepth;
|
||||||
if (_context == yul::IdentifierContext::LValue)
|
if (_context == yul::IdentifierContext::LValue)
|
||||||
stackDiff -= 1;
|
stackDiff -= 1;
|
||||||
if (stackDiff < 1 || stackDiff > 16)
|
if (stackDiff < 1 || stackDiff > _assembly.maxDup() || stackDiff > _assembly.maxSwap())
|
||||||
BOOST_THROW_EXCEPTION(
|
BOOST_THROW_EXCEPTION(
|
||||||
StackTooDeepError() <<
|
StackTooDeepError() <<
|
||||||
errinfo_sourceLocation(nativeLocationOf(_identifier)) <<
|
errinfo_sourceLocation(nativeLocationOf(_identifier)) <<
|
||||||
util::errinfo_comment(util::stackTooDeepString)
|
util::errinfo_comment(util::stackTooDeepString)
|
||||||
);
|
);
|
||||||
if (_context == yul::IdentifierContext::RValue)
|
if (_context == yul::IdentifierContext::RValue)
|
||||||
_assembly.appendInstruction(dupInstruction(static_cast<unsigned>(stackDiff)));
|
_assembly.appendDup(static_cast<unsigned>(stackDiff));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_assembly.appendInstruction(swapInstruction(static_cast<unsigned>(stackDiff)));
|
_assembly.appendSwap(static_cast<unsigned>(stackDiff));
|
||||||
_assembly.appendInstruction(Instruction::POP);
|
_assembly.appendInstruction(Instruction::POP);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -251,7 +251,15 @@ public:
|
|||||||
|
|
||||||
/// Append elements to the current instruction list and adjust @a m_stackOffset.
|
/// 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::AssemblyItem const& _item) { m_asm->append(_item); return *this; }
|
||||||
CompilerContext& operator<<(evmasm::Instruction _instruction) { m_asm->append(_instruction); return *this; }
|
CompilerContext& operator<<(evmasm::Instruction _instruction) {
|
||||||
|
if (_instruction >= evmasm::Instruction::SWAP1 && _instruction <= evmasm::Instruction::SWAP16)
|
||||||
|
m_asm->append(evmasm::AssemblyItem(evmasm::Swap, static_cast<unsigned>(_instruction) - static_cast<unsigned>(evmasm::Instruction::SWAP1) + 1));
|
||||||
|
else if (_instruction >= evmasm::Instruction::DUP1 && _instruction <= evmasm::Instruction::DUP16)
|
||||||
|
m_asm->append(evmasm::AssemblyItem(evmasm::Dup, static_cast<unsigned>(_instruction) - static_cast<unsigned>(evmasm::Instruction::DUP1) + 1));
|
||||||
|
else
|
||||||
|
m_asm->append(_instruction);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
CompilerContext& operator<<(u256 const& _value) { m_asm->append(_value); return *this; }
|
CompilerContext& operator<<(u256 const& _value) { m_asm->append(_value); return *this; }
|
||||||
CompilerContext& operator<<(bytes const& _data) { m_asm->append(_data); return *this; }
|
CompilerContext& operator<<(bytes const& _data) { m_asm->append(_data); return *this; }
|
||||||
|
|
||||||
|
@ -540,9 +540,9 @@ void CompilerUtils::encodeToMemory(
|
|||||||
StackTooDeepError,
|
StackTooDeepError,
|
||||||
util::stackTooDeepString
|
util::stackTooDeepString
|
||||||
);
|
);
|
||||||
m_context << dupInstruction(2 + dynPointers) << Instruction::DUP2;
|
m_context << AssemblyItem(AssemblyItemType::Dup, 2 + dynPointers) << Instruction::DUP2;
|
||||||
m_context << Instruction::SUB;
|
m_context << Instruction::SUB;
|
||||||
m_context << dupInstruction(2 + dynPointers - thisDynPointer);
|
m_context << AssemblyItem(AssemblyItemType::Dup, 2 + dynPointers - thisDynPointer);
|
||||||
m_context << Instruction::MSTORE;
|
m_context << Instruction::MSTORE;
|
||||||
// stack: ... <end_of_mem>
|
// stack: ... <end_of_mem>
|
||||||
if (_givenTypes[i]->category() == Type::Category::StringLiteral)
|
if (_givenTypes[i]->category() == Type::Category::StringLiteral)
|
||||||
@ -583,13 +583,13 @@ void CompilerUtils::encodeToMemory(
|
|||||||
copyToStackTop(argSize - stackPos + dynPointers + 2, arrayType->sizeOnStack());
|
copyToStackTop(argSize - stackPos + dynPointers + 2, arrayType->sizeOnStack());
|
||||||
// stack: ... <end_of_mem> <value...>
|
// stack: ... <end_of_mem> <value...>
|
||||||
// copy length to memory
|
// copy length to memory
|
||||||
m_context << dupInstruction(1 + arrayType->sizeOnStack());
|
m_context << AssemblyItem(AssemblyItemType::Dup, 1 + arrayType->sizeOnStack());
|
||||||
ArrayUtils(m_context).retrieveLength(*arrayType, 1);
|
ArrayUtils(m_context).retrieveLength(*arrayType, 1);
|
||||||
// stack: ... <end_of_mem> <value...> <end_of_mem'> <length>
|
// stack: ... <end_of_mem> <value...> <end_of_mem'> <length>
|
||||||
storeInMemoryDynamic(*TypeProvider::uint256(), true);
|
storeInMemoryDynamic(*TypeProvider::uint256(), true);
|
||||||
// stack: ... <end_of_mem> <value...> <end_of_mem''>
|
// stack: ... <end_of_mem> <value...> <end_of_mem''>
|
||||||
// copy the new memory pointer
|
// copy the new memory pointer
|
||||||
m_context << swapInstruction(arrayType->sizeOnStack() + 1) << Instruction::POP;
|
m_context << AssemblyItem(AssemblyItemType::Swap, arrayType->sizeOnStack() + 1) << Instruction::POP;
|
||||||
// stack: ... <end_of_mem''> <value...>
|
// stack: ... <end_of_mem''> <value...>
|
||||||
// copy data part
|
// copy data part
|
||||||
ArrayUtils(m_context).copyArrayToMemory(*arrayType, _padToWordBoundaries);
|
ArrayUtils(m_context).copyArrayToMemory(*arrayType, _padToWordBoundaries);
|
||||||
@ -602,7 +602,7 @@ void CompilerUtils::encodeToMemory(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// remove unneeded stack elements (and retain memory pointer)
|
// remove unneeded stack elements (and retain memory pointer)
|
||||||
m_context << swapInstruction(argSize + dynPointers + 1);
|
m_context << AssemblyItem(AssemblyItemType::Swap, argSize + dynPointers + 1);
|
||||||
popStackSlots(argSize + dynPointers + 1);
|
popStackSlots(argSize + dynPointers + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1270,7 +1270,7 @@ void CompilerUtils::convertType(
|
|||||||
// Move it back into its place.
|
// Move it back into its place.
|
||||||
for (unsigned j = 0; j < min(sourceSize, targetSize); ++j)
|
for (unsigned j = 0; j < min(sourceSize, targetSize); ++j)
|
||||||
m_context <<
|
m_context <<
|
||||||
swapInstruction(depth + targetSize - sourceSize) <<
|
AssemblyItem(AssemblyItemType::Swap, depth + targetSize - sourceSize) <<
|
||||||
Instruction::POP;
|
Instruction::POP;
|
||||||
// Value shrank
|
// Value shrank
|
||||||
for (unsigned j = targetSize; j < sourceSize; ++j)
|
for (unsigned j = targetSize; j < sourceSize; ++j)
|
||||||
@ -1422,7 +1422,7 @@ void CompilerUtils::moveToStackVariable(VariableDeclaration const& _variable)
|
|||||||
util::errinfo_comment(util::stackTooDeepString)
|
util::errinfo_comment(util::stackTooDeepString)
|
||||||
);
|
);
|
||||||
for (unsigned i = 0; i < size; ++i)
|
for (unsigned i = 0; i < size; ++i)
|
||||||
m_context << swapInstruction(stackPosition - size + 1) << Instruction::POP;
|
m_context << AssemblyItem(AssemblyItemType::Swap, stackPosition - size + 1) << Instruction::POP;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompilerUtils::copyToStackTop(unsigned _stackDepth, unsigned _itemSize)
|
void CompilerUtils::copyToStackTop(unsigned _stackDepth, unsigned _itemSize)
|
||||||
@ -1433,7 +1433,7 @@ void CompilerUtils::copyToStackTop(unsigned _stackDepth, unsigned _itemSize)
|
|||||||
util::stackTooDeepString
|
util::stackTooDeepString
|
||||||
);
|
);
|
||||||
for (unsigned i = 0; i < _itemSize; ++i)
|
for (unsigned i = 0; i < _itemSize; ++i)
|
||||||
m_context << dupInstruction(_stackDepth);
|
m_context << AssemblyItem(AssemblyItemType::Dup, _stackDepth);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompilerUtils::moveToStackTop(unsigned _stackDepth, unsigned _itemSize)
|
void CompilerUtils::moveToStackTop(unsigned _stackDepth, unsigned _itemSize)
|
||||||
@ -1459,7 +1459,7 @@ void CompilerUtils::rotateStackUp(unsigned _items)
|
|||||||
util::stackTooDeepString
|
util::stackTooDeepString
|
||||||
);
|
);
|
||||||
for (unsigned i = 1; i < _items; ++i)
|
for (unsigned i = 1; i < _items; ++i)
|
||||||
m_context << swapInstruction(_items - i);
|
m_context << AssemblyItem(AssemblyItemType::Swap, _items - i);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompilerUtils::rotateStackDown(unsigned _items)
|
void CompilerUtils::rotateStackDown(unsigned _items)
|
||||||
@ -1470,7 +1470,7 @@ void CompilerUtils::rotateStackDown(unsigned _items)
|
|||||||
util::stackTooDeepString
|
util::stackTooDeepString
|
||||||
);
|
);
|
||||||
for (unsigned i = 1; i < _items; ++i)
|
for (unsigned i = 1; i < _items; ++i)
|
||||||
m_context << swapInstruction(i);
|
m_context << AssemblyItem(AssemblyItemType::Swap, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompilerUtils::popStackElement(Type const& _type)
|
void CompilerUtils::popStackElement(Type const& _type)
|
||||||
|
@ -366,7 +366,7 @@ void ContractCompiler::appendInternalSelector(
|
|||||||
{
|
{
|
||||||
size_t pivotIndex = _ids.size() / 2;
|
size_t pivotIndex = _ids.size() / 2;
|
||||||
FixedHash<4> pivot{_ids.at(pivotIndex)};
|
FixedHash<4> pivot{_ids.at(pivotIndex)};
|
||||||
m_context << dupInstruction(1) << u256(FixedHash<4>::Arith(pivot)) << Instruction::GT;
|
m_context << AssemblyItem(AssemblyItemType::Dup, 1) << u256(FixedHash<4>::Arith(pivot)) << Instruction::GT;
|
||||||
evmasm::AssemblyItem lessTag{m_context.appendConditionalJump()};
|
evmasm::AssemblyItem lessTag{m_context.appendConditionalJump()};
|
||||||
// Here, we have funid >= pivot
|
// Here, we have funid >= pivot
|
||||||
vector<FixedHash<4>> larger{_ids.begin() + static_cast<ptrdiff_t>(pivotIndex), _ids.end()};
|
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)
|
for (auto const& id: _ids)
|
||||||
{
|
{
|
||||||
m_context << dupInstruction(1) << u256(FixedHash<4>::Arith(id)) << Instruction::EQ;
|
m_context << AssemblyItem(AssemblyItemType::Dup, 1) << u256(FixedHash<4>::Arith(id)) << Instruction::EQ;
|
||||||
m_context.appendConditionalJumpTo(_entryPoints.at(id));
|
m_context.appendConditionalJumpTo(_entryPoints.at(id));
|
||||||
}
|
}
|
||||||
m_context.appendJumpTo(_notFoundTag);
|
m_context.appendJumpTo(_notFoundTag);
|
||||||
@ -519,7 +519,7 @@ void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contrac
|
|||||||
{
|
{
|
||||||
// If the function is not a view function and is called without DELEGATECALL,
|
// If the function is not a view function and is called without DELEGATECALL,
|
||||||
// we revert.
|
// we revert.
|
||||||
m_context << dupInstruction(2);
|
m_context << AssemblyItem(AssemblyItemType::Dup, 2);
|
||||||
m_context.appendConditionalRevert(false, "Non-view function of library called without DELEGATECALL");
|
m_context.appendConditionalRevert(false, "Non-view function of library called without DELEGATECALL");
|
||||||
}
|
}
|
||||||
m_context.setStackOffset(0);
|
m_context.setStackOffset(0);
|
||||||
@ -669,7 +669,7 @@ bool ContractCompiler::visit(FunctionDefinition const& _function)
|
|||||||
for (size_t i = 0; i < c_returnValuesSize; ++i)
|
for (size_t i = 0; i < c_returnValuesSize; ++i)
|
||||||
stackLayout.push_back(static_cast<int>(i));
|
stackLayout.push_back(static_cast<int>(i));
|
||||||
|
|
||||||
if (stackLayout.size() > 17)
|
if (stackLayout.size() > m_context.assembly().maxSwap() + 1)
|
||||||
BOOST_THROW_EXCEPTION(
|
BOOST_THROW_EXCEPTION(
|
||||||
StackTooDeepError() <<
|
StackTooDeepError() <<
|
||||||
errinfo_sourceLocation(_function.location()) <<
|
errinfo_sourceLocation(_function.location()) <<
|
||||||
@ -683,7 +683,7 @@ bool ContractCompiler::visit(FunctionDefinition const& _function)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_context << swapInstruction(static_cast<unsigned>(stackLayout.size()) - static_cast<unsigned>(stackLayout.back()) - 1u);
|
m_context << AssemblyItem(AssemblyItemType::Swap, static_cast<unsigned>(stackLayout.size()) - static_cast<unsigned>(stackLayout.back()) - 1u);
|
||||||
swap(stackLayout[static_cast<size_t>(stackLayout.back())], stackLayout.back());
|
swap(stackLayout[static_cast<size_t>(stackLayout.back())], stackLayout.back());
|
||||||
}
|
}
|
||||||
for (size_t i = 0; i < stackLayout.size(); ++i)
|
for (size_t i = 0; i < stackLayout.size(); ++i)
|
||||||
@ -839,13 +839,13 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
solAssert(variable->type()->sizeOnStack() == 1, "");
|
solAssert(variable->type()->sizeOnStack() == 1, "");
|
||||||
if (stackDiff < 1 || stackDiff > 16)
|
if (stackDiff < 1 || stackDiff > _assembly.maxDup())
|
||||||
BOOST_THROW_EXCEPTION(
|
BOOST_THROW_EXCEPTION(
|
||||||
StackTooDeepError() <<
|
StackTooDeepError() <<
|
||||||
errinfo_sourceLocation(_inlineAssembly.location()) <<
|
errinfo_sourceLocation(_inlineAssembly.location()) <<
|
||||||
util::errinfo_comment(util::stackTooDeepString)
|
util::errinfo_comment(util::stackTooDeepString)
|
||||||
);
|
);
|
||||||
_assembly.appendInstruction(dupInstruction(stackDiff));
|
_assembly.appendDup(stackDiff);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
solAssert(false, "");
|
solAssert(false, "");
|
||||||
@ -913,13 +913,13 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
|
|||||||
else
|
else
|
||||||
solAssert(suffix.empty(), "");
|
solAssert(suffix.empty(), "");
|
||||||
|
|
||||||
if (stackDiff > 16 || stackDiff < 1)
|
if (stackDiff > _assembly.maxSwap() || stackDiff < 1)
|
||||||
BOOST_THROW_EXCEPTION(
|
BOOST_THROW_EXCEPTION(
|
||||||
StackTooDeepError() <<
|
StackTooDeepError() <<
|
||||||
errinfo_sourceLocation(_inlineAssembly.location()) <<
|
errinfo_sourceLocation(_inlineAssembly.location()) <<
|
||||||
util::errinfo_comment(util::stackTooDeepString)
|
util::errinfo_comment(util::stackTooDeepString)
|
||||||
);
|
);
|
||||||
_assembly.appendInstruction(swapInstruction(stackDiff));
|
_assembly.appendSwap(stackDiff);
|
||||||
_assembly.appendInstruction(Instruction::POP);
|
_assembly.appendInstruction(Instruction::POP);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -118,7 +118,7 @@ void ExpressionCompiler::appendConstStateVariableAccessor(VariableDeclaration co
|
|||||||
acceptAndConvert(*_varDecl.value(), *_varDecl.annotation().type);
|
acceptAndConvert(*_varDecl.value(), *_varDecl.annotation().type);
|
||||||
|
|
||||||
// append return
|
// append return
|
||||||
m_context << dupInstruction(_varDecl.annotation().type->sizeOnStack() + 1);
|
m_context << AssemblyItem(AssemblyItemType::Dup, _varDecl.annotation().type->sizeOnStack() + 1);
|
||||||
m_context.appendJump(evmasm::AssemblyItem::JumpType::OutOfFunction);
|
m_context.appendJump(evmasm::AssemblyItem::JumpType::OutOfFunction);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,9 +220,9 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
|
|||||||
m_context << Instruction::SWAP2 << Instruction::POP << Instruction::SWAP1;
|
m_context << Instruction::SWAP2 << Instruction::POP << Instruction::SWAP1;
|
||||||
else if (paramTypes.size() >= 2)
|
else if (paramTypes.size() >= 2)
|
||||||
{
|
{
|
||||||
m_context << swapInstruction(static_cast<unsigned>(paramTypes.size()));
|
m_context << AssemblyItem(AssemblyItemType::Swap, static_cast<unsigned>(paramTypes.size()));
|
||||||
m_context << Instruction::POP;
|
m_context << Instruction::POP;
|
||||||
m_context << swapInstruction(static_cast<unsigned>(paramTypes.size()));
|
m_context << AssemblyItem(AssemblyItemType::Swap, static_cast<unsigned>(paramTypes.size()));
|
||||||
utils().popStackSlots(paramTypes.size() - 1);
|
utils().popStackSlots(paramTypes.size() - 1);
|
||||||
}
|
}
|
||||||
unsigned retSizeOnStack = 0;
|
unsigned retSizeOnStack = 0;
|
||||||
@ -265,13 +265,13 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
|
|||||||
retSizeOnStack = returnTypes.front()->sizeOnStack();
|
retSizeOnStack = returnTypes.front()->sizeOnStack();
|
||||||
}
|
}
|
||||||
solAssert(retSizeOnStack == utils().sizeOnStack(returnTypes), "");
|
solAssert(retSizeOnStack == utils().sizeOnStack(returnTypes), "");
|
||||||
if (retSizeOnStack > 15)
|
if (retSizeOnStack + 1 > m_context.assembly().maxDup())
|
||||||
BOOST_THROW_EXCEPTION(
|
BOOST_THROW_EXCEPTION(
|
||||||
StackTooDeepError() <<
|
StackTooDeepError() <<
|
||||||
errinfo_sourceLocation(_varDecl.location()) <<
|
errinfo_sourceLocation(_varDecl.location()) <<
|
||||||
util::errinfo_comment(util::stackTooDeepString)
|
util::errinfo_comment(util::stackTooDeepString)
|
||||||
);
|
);
|
||||||
m_context << dupInstruction(retSizeOnStack + 1);
|
m_context << AssemblyItem(AssemblyItemType::Dup, retSizeOnStack + 1);
|
||||||
m_context.appendJump(evmasm::AssemblyItem::JumpType::OutOfFunction);
|
m_context.appendJump(evmasm::AssemblyItem::JumpType::OutOfFunction);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -347,7 +347,7 @@ bool ExpressionCompiler::visit(Assignment const& _assignment)
|
|||||||
}
|
}
|
||||||
if (lvalueSize > 0)
|
if (lvalueSize > 0)
|
||||||
{
|
{
|
||||||
if (itemSize + lvalueSize > 16)
|
if (itemSize + lvalueSize > m_context.assembly().maxSwap())
|
||||||
BOOST_THROW_EXCEPTION(
|
BOOST_THROW_EXCEPTION(
|
||||||
StackTooDeepError() <<
|
StackTooDeepError() <<
|
||||||
errinfo_sourceLocation(_assignment.location()) <<
|
errinfo_sourceLocation(_assignment.location()) <<
|
||||||
@ -355,7 +355,7 @@ bool ExpressionCompiler::visit(Assignment const& _assignment)
|
|||||||
);
|
);
|
||||||
// value [lvalue_ref] updated_value
|
// value [lvalue_ref] updated_value
|
||||||
for (unsigned i = 0; i < itemSize; ++i)
|
for (unsigned i = 0; i < itemSize; ++i)
|
||||||
m_context << swapInstruction(itemSize + lvalueSize) << Instruction::POP;
|
m_context << AssemblyItem(AssemblyItemType::Swap, itemSize + lvalueSize) << Instruction::POP;
|
||||||
}
|
}
|
||||||
m_currentLValue->storeValue(*_assignment.annotation().type, _assignment.location());
|
m_currentLValue->storeValue(*_assignment.annotation().type, _assignment.location());
|
||||||
}
|
}
|
||||||
@ -447,7 +447,7 @@ bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation)
|
|||||||
m_context << Instruction::DUP1;
|
m_context << Instruction::DUP1;
|
||||||
if (m_currentLValue->sizeOnStack() > 0)
|
if (m_currentLValue->sizeOnStack() > 0)
|
||||||
for (unsigned i = 1 + m_currentLValue->sizeOnStack(); i > 0; --i)
|
for (unsigned i = 1 + m_currentLValue->sizeOnStack(); i > 0; --i)
|
||||||
m_context << swapInstruction(i);
|
m_context << AssemblyItem(AssemblyItemType::Swap, i);
|
||||||
}
|
}
|
||||||
if (_unaryOperation.getOperator() == Token::Inc)
|
if (_unaryOperation.getOperator() == Token::Inc)
|
||||||
{
|
{
|
||||||
@ -472,7 +472,7 @@ bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation)
|
|||||||
// Stack for prefix: [ref...] (*ref)+-1
|
// Stack for prefix: [ref...] (*ref)+-1
|
||||||
// Stack for postfix: *ref [ref...] (*ref)+-1
|
// Stack for postfix: *ref [ref...] (*ref)+-1
|
||||||
for (unsigned i = m_currentLValue->sizeOnStack(); i > 0; --i)
|
for (unsigned i = m_currentLValue->sizeOnStack(); i > 0; --i)
|
||||||
m_context << swapInstruction(i);
|
m_context << AssemblyItem(AssemblyItemType::Swap, i);
|
||||||
m_currentLValue->storeValue(
|
m_currentLValue->storeValue(
|
||||||
*_unaryOperation.annotation().type, _unaryOperation.location(),
|
*_unaryOperation.annotation().type, _unaryOperation.location(),
|
||||||
!_unaryOperation.isPrefixOperation());
|
!_unaryOperation.isPrefixOperation());
|
||||||
@ -715,7 +715,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
|
|
||||||
if (function.saltSet())
|
if (function.saltSet())
|
||||||
{
|
{
|
||||||
m_context << dupInstruction(2 + (function.valueSet() ? 1 : 0));
|
m_context << AssemblyItem(AssemblyItemType::Dup, 2 + (function.valueSet() ? 1 : 0));
|
||||||
m_context << Instruction::SWAP1;
|
m_context << Instruction::SWAP1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -724,7 +724,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
|
|
||||||
// now: [salt], [value], [salt], size, offset
|
// now: [salt], [value], [salt], size, offset
|
||||||
if (function.valueSet())
|
if (function.valueSet())
|
||||||
m_context << dupInstruction(3 + (function.saltSet() ? 1 : 0));
|
m_context << AssemblyItem(AssemblyItemType::Dup, 3 + (function.saltSet() ? 1 : 0));
|
||||||
else
|
else
|
||||||
m_context << u256(0);
|
m_context << u256(0);
|
||||||
|
|
||||||
@ -737,9 +737,9 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
// now: [salt], [value], address
|
// now: [salt], [value], address
|
||||||
|
|
||||||
if (function.valueSet())
|
if (function.valueSet())
|
||||||
m_context << swapInstruction(1) << Instruction::POP;
|
m_context << AssemblyItem(AssemblyItemType::Swap, 1) << Instruction::POP;
|
||||||
if (function.saltSet())
|
if (function.saltSet())
|
||||||
m_context << swapInstruction(1) << Instruction::POP;
|
m_context << AssemblyItem(AssemblyItemType::Swap, 1) << Instruction::POP;
|
||||||
|
|
||||||
// Check if zero (reverted)
|
// Check if zero (reverted)
|
||||||
m_context << Instruction::DUP1 << Instruction::ISZERO;
|
m_context << Instruction::DUP1 << Instruction::ISZERO;
|
||||||
@ -765,7 +765,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
// Its values of gasSet and valueSet is equal to the original function's though.
|
// Its values of gasSet and valueSet is equal to the original function's though.
|
||||||
unsigned stackDepth = (function.gasSet() ? 1u : 0u) + (function.valueSet() ? 1u : 0u);
|
unsigned stackDepth = (function.gasSet() ? 1u : 0u) + (function.valueSet() ? 1u : 0u);
|
||||||
if (stackDepth > 0)
|
if (stackDepth > 0)
|
||||||
m_context << swapInstruction(stackDepth);
|
m_context << AssemblyItem(AssemblyItemType::Swap, stackDepth);
|
||||||
if (function.gasSet())
|
if (function.gasSet())
|
||||||
m_context << Instruction::POP;
|
m_context << Instruction::POP;
|
||||||
break;
|
break;
|
||||||
@ -1022,7 +1022,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
};
|
};
|
||||||
m_context << contractAddresses.at(function.kind());
|
m_context << contractAddresses.at(function.kind());
|
||||||
for (unsigned i = function.sizeOnStack(); i > 0; --i)
|
for (unsigned i = function.sizeOnStack(); i > 0; --i)
|
||||||
m_context << swapInstruction(i);
|
m_context << AssemblyItem(AssemblyItemType::Swap, i);
|
||||||
solAssert(!_functionCall.annotation().tryCall, "");
|
solAssert(!_functionCall.annotation().tryCall, "");
|
||||||
appendExternalFunctionCall(function, arguments, false);
|
appendExternalFunctionCall(function, arguments, false);
|
||||||
break;
|
break;
|
||||||
@ -2648,7 +2648,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
|
|||||||
utils().fetchFreeMemoryPointer();
|
utils().fetchFreeMemoryPointer();
|
||||||
if (!_functionType.isBareCall())
|
if (!_functionType.isBareCall())
|
||||||
{
|
{
|
||||||
m_context << dupInstruction(2 + gasValueSize + CompilerUtils::sizeOnStack(argumentTypes));
|
m_context << AssemblyItem(AssemblyItemType::Dup, 2 + gasValueSize + CompilerUtils::sizeOnStack(argumentTypes));
|
||||||
utils().storeInMemoryDynamic(IntegerType(8 * CompilerUtils::dataStartOffset), false);
|
utils().storeInMemoryDynamic(IntegerType(8 * CompilerUtils::dataStartOffset), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2703,10 +2703,10 @@ void ExpressionCompiler::appendExternalFunctionCall(
|
|||||||
else if (useStaticCall)
|
else if (useStaticCall)
|
||||||
solAssert(!_functionType.valueSet(), "Value set for staticcall");
|
solAssert(!_functionType.valueSet(), "Value set for staticcall");
|
||||||
else if (_functionType.valueSet())
|
else if (_functionType.valueSet())
|
||||||
m_context << dupInstruction(m_context.baseToCurrentStackOffset(valueStackPos));
|
m_context << AssemblyItem(AssemblyItemType::Dup, m_context.baseToCurrentStackOffset(valueStackPos));
|
||||||
else
|
else
|
||||||
m_context << u256(0);
|
m_context << u256(0);
|
||||||
m_context << dupInstruction(m_context.baseToCurrentStackOffset(contractStackPos));
|
m_context << AssemblyItem(AssemblyItemType::Dup, m_context.baseToCurrentStackOffset(contractStackPos));
|
||||||
|
|
||||||
bool existenceChecked = false;
|
bool existenceChecked = false;
|
||||||
// Check the target contract exists (has code) for non-low-level calls.
|
// Check the target contract exists (has code) for non-low-level calls.
|
||||||
@ -2730,7 +2730,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (_functionType.gasSet())
|
if (_functionType.gasSet())
|
||||||
m_context << dupInstruction(m_context.baseToCurrentStackOffset(gasStackPos));
|
m_context << AssemblyItem(AssemblyItemType::Dup, m_context.baseToCurrentStackOffset(gasStackPos));
|
||||||
else if (m_context.evmVersion().canOverchargeGasForCall())
|
else if (m_context.evmVersion().canOverchargeGasForCall())
|
||||||
// Send all gas (requires tangerine whistle EVM)
|
// Send all gas (requires tangerine whistle EVM)
|
||||||
m_context << Instruction::GAS;
|
m_context << Instruction::GAS;
|
||||||
@ -2768,7 +2768,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
|
|||||||
m_context.appendConditionalRevert(true);
|
m_context.appendConditionalRevert(true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
m_context << swapInstruction(remainsSize);
|
m_context << AssemblyItem(AssemblyItemType::Swap, remainsSize);
|
||||||
utils().popStackSlots(remainsSize);
|
utils().popStackSlots(remainsSize);
|
||||||
|
|
||||||
// Only success flag is remaining on stack.
|
// Only success flag is remaining on stack.
|
||||||
|
@ -56,7 +56,7 @@ void StackVariable::retrieveValue(SourceLocation const& _location, bool) const
|
|||||||
);
|
);
|
||||||
solAssert(stackPos + 1 >= m_size, "Size and stack pos mismatch.");
|
solAssert(stackPos + 1 >= m_size, "Size and stack pos mismatch.");
|
||||||
for (unsigned i = 0; i < m_size; ++i)
|
for (unsigned i = 0; i < m_size; ++i)
|
||||||
m_context << dupInstruction(stackPos + 1);
|
m_context << AssemblyItem(AssemblyItemType::Dup, stackPos + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void StackVariable::storeValue(Type const&, SourceLocation const& _location, bool _move) const
|
void StackVariable::storeValue(Type const&, SourceLocation const& _location, bool _move) const
|
||||||
@ -70,7 +70,7 @@ void StackVariable::storeValue(Type const&, SourceLocation const& _location, boo
|
|||||||
);
|
);
|
||||||
else if (stackDiff > 0)
|
else if (stackDiff > 0)
|
||||||
for (unsigned i = 0; i < m_size; ++i)
|
for (unsigned i = 0; i < m_size; ++i)
|
||||||
m_context << swapInstruction(stackDiff) << Instruction::POP;
|
m_context << AssemblyItem(AssemblyItemType::Swap, stackDiff) << Instruction::POP;
|
||||||
if (!_move)
|
if (!_move)
|
||||||
retrieveValue(_location);
|
retrieveValue(_location);
|
||||||
}
|
}
|
||||||
@ -421,7 +421,7 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc
|
|||||||
}
|
}
|
||||||
unsigned stackSize = sourceMemberType->sizeOnStack();
|
unsigned stackSize = sourceMemberType->sizeOnStack();
|
||||||
pair<u256, unsigned> const& offsets = structType.storageOffsetsOfMember(member.name);
|
pair<u256, unsigned> const& offsets = structType.storageOffsetsOfMember(member.name);
|
||||||
m_context << dupInstruction(1 + stackSize) << offsets.first << Instruction::ADD;
|
m_context << AssemblyItem(AssemblyItemType::Dup, 1 + stackSize) << offsets.first << Instruction::ADD;
|
||||||
m_context << u256(offsets.second);
|
m_context << u256(offsets.second);
|
||||||
// stack: source_ref target_ref target_off source_value... target_member_ref target_member_byte_off
|
// stack: source_ref target_ref target_off source_value... target_member_ref target_member_byte_off
|
||||||
StorageItem(m_context, *memberType).storeValue(*sourceMemberType, _location, true);
|
StorageItem(m_context, *memberType).storeValue(*sourceMemberType, _location, true);
|
||||||
|
@ -99,7 +99,7 @@ GasEstimator::GasConsumption GasEstimator::functionalEstimation(
|
|||||||
AssemblyItem invalidTag(PushTag, u256(-0x10));
|
AssemblyItem invalidTag(PushTag, u256(-0x10));
|
||||||
state->feedItem(invalidTag, true);
|
state->feedItem(invalidTag, true);
|
||||||
if (parametersSize > 0)
|
if (parametersSize > 0)
|
||||||
state->feedItem(swapInstruction(parametersSize));
|
state->feedItem(AssemblyItem(AssemblyItemType::Swap, parametersSize));
|
||||||
|
|
||||||
return PathGasMeter::estimateMax(_items, m_evmVersion, _offset, state);
|
return PathGasMeter::estimateMax(_items, m_evmVersion, _offset, state);
|
||||||
}
|
}
|
||||||
|
@ -67,6 +67,13 @@ public:
|
|||||||
virtual void setStackHeight(int height) = 0;
|
virtual void setStackHeight(int height) = 0;
|
||||||
/// Append an EVM instruction.
|
/// Append an EVM instruction.
|
||||||
virtual void appendInstruction(evmasm::Instruction _instruction) = 0;
|
virtual void appendInstruction(evmasm::Instruction _instruction) = 0;
|
||||||
|
/// Append a swap.
|
||||||
|
virtual void appendSwap(unsigned _height) = 0;
|
||||||
|
/// Append a dup.
|
||||||
|
virtual void appendDup(unsigned _height) = 0;
|
||||||
|
|
||||||
|
virtual unsigned maxSwap() const = 0;
|
||||||
|
virtual unsigned maxDup() const = 0;
|
||||||
/// Append a constant.
|
/// Append a constant.
|
||||||
virtual void appendConstant(u256 const& _constant) = 0;
|
virtual void appendConstant(u256 const& _constant) = 0;
|
||||||
/// Append a label.
|
/// Append a label.
|
||||||
|
@ -187,7 +187,7 @@ void CodeTransform::operator()(VariableDeclaration const& _varDecl)
|
|||||||
m_unusedStackSlots.erase(it);
|
m_unusedStackSlots.erase(it);
|
||||||
m_context->variableStackHeights[&var] = slot;
|
m_context->variableStackHeights[&var] = slot;
|
||||||
if (size_t heightDiff = variableHeightDiff(var, varName, true))
|
if (size_t heightDiff = variableHeightDiff(var, varName, true))
|
||||||
m_assembly.appendInstruction(evmasm::swapInstruction(static_cast<unsigned>(heightDiff - 1)));
|
m_assembly.appendSwap(static_cast<unsigned>(heightDiff - 1));
|
||||||
m_assembly.appendInstruction(evmasm::Instruction::POP);
|
m_assembly.appendInstruction(evmasm::Instruction::POP);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -274,7 +274,7 @@ void CodeTransform::operator()(Identifier const& _identifier)
|
|||||||
// TODO: opportunity for optimization: Do not DUP if this is the last reference
|
// TODO: opportunity for optimization: Do not DUP if this is the last reference
|
||||||
// to the top most element of the stack
|
// to the top most element of the stack
|
||||||
if (size_t heightDiff = variableHeightDiff(_var, _identifier.name, false))
|
if (size_t heightDiff = variableHeightDiff(_var, _identifier.name, false))
|
||||||
m_assembly.appendInstruction(evmasm::dupInstruction(static_cast<unsigned>(heightDiff)));
|
m_assembly.appendDup(static_cast<unsigned>(heightDiff));
|
||||||
else
|
else
|
||||||
// Store something to balance the stack
|
// Store something to balance the stack
|
||||||
m_assembly.appendConstant(u256(0));
|
m_assembly.appendConstant(u256(0));
|
||||||
@ -328,7 +328,7 @@ void CodeTransform::operator()(Switch const& _switch)
|
|||||||
AbstractAssembly::LabelID bodyLabel = m_assembly.newLabelId();
|
AbstractAssembly::LabelID bodyLabel = m_assembly.newLabelId();
|
||||||
caseBodies[&c] = bodyLabel;
|
caseBodies[&c] = bodyLabel;
|
||||||
yulAssert(m_assembly.stackHeight() == expressionHeight + 1, "");
|
yulAssert(m_assembly.stackHeight() == expressionHeight + 1, "");
|
||||||
m_assembly.appendInstruction(evmasm::dupInstruction(2));
|
m_assembly.appendDup(2);
|
||||||
m_assembly.appendInstruction(evmasm::Instruction::EQ);
|
m_assembly.appendInstruction(evmasm::Instruction::EQ);
|
||||||
m_assembly.appendJumpToIf(bodyLabel);
|
m_assembly.appendJumpToIf(bodyLabel);
|
||||||
}
|
}
|
||||||
@ -478,7 +478,7 @@ void CodeTransform::operator()(FunctionDefinition const& _function)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_assembly.appendInstruction(evmasm::swapInstruction(static_cast<unsigned>(stackLayout.size()) - static_cast<unsigned>(stackLayout.back()) - 1u));
|
m_assembly.appendSwap(static_cast<unsigned>(stackLayout.size()) - static_cast<unsigned>(stackLayout.back()) - 1u);
|
||||||
swap(stackLayout[static_cast<size_t>(stackLayout.back())], stackLayout.back());
|
swap(stackLayout[static_cast<size_t>(stackLayout.back())], stackLayout.back());
|
||||||
}
|
}
|
||||||
for (size_t i = 0; i < stackLayout.size(); ++i)
|
for (size_t i = 0; i < stackLayout.size(); ++i)
|
||||||
@ -758,7 +758,7 @@ void CodeTransform::generateAssignment(Identifier const& _variableName)
|
|||||||
{
|
{
|
||||||
Scope::Variable const& _var = std::get<Scope::Variable>(*var);
|
Scope::Variable const& _var = std::get<Scope::Variable>(*var);
|
||||||
if (size_t heightDiff = variableHeightDiff(_var, _variableName.name, true))
|
if (size_t heightDiff = variableHeightDiff(_var, _variableName.name, true))
|
||||||
m_assembly.appendInstruction(evmasm::swapInstruction(static_cast<unsigned>(heightDiff - 1)));
|
m_assembly.appendSwap(static_cast<unsigned>(heightDiff - 1));
|
||||||
m_assembly.appendInstruction(evmasm::Instruction::POP);
|
m_assembly.appendInstruction(evmasm::Instruction::POP);
|
||||||
decreaseReference(_variableName.name, _var);
|
decreaseReference(_variableName.name, _var);
|
||||||
}
|
}
|
||||||
|
@ -145,9 +145,16 @@ map<YulString, BuiltinFunctionForEVM> createBuiltins(langutil::EVMVersion _evmVe
|
|||||||
string name = toLower(instr.first);
|
string name = toLower(instr.first);
|
||||||
auto const opcode = instr.second;
|
auto const opcode = instr.second;
|
||||||
|
|
||||||
|
auto isSwapInstruction = [](auto i) {
|
||||||
|
return (i >= evmasm::Instruction::SWAP1 && i <= evmasm::Instruction::SWAP16) || i == evmasm::Instruction::SWAP_N;
|
||||||
|
};
|
||||||
|
auto isDupInstruction = [](auto i) {
|
||||||
|
return (i >= evmasm::Instruction::DUP1 && i <= evmasm::Instruction::DUP16) || i == evmasm::Instruction::DUP_N;
|
||||||
|
};
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!evmasm::isDupInstruction(opcode) &&
|
!isDupInstruction(opcode) &&
|
||||||
!evmasm::isSwapInstruction(opcode) &&
|
!isSwapInstruction(opcode) &&
|
||||||
!evmasm::isPushInstruction(opcode) &&
|
!evmasm::isPushInstruction(opcode) &&
|
||||||
opcode != evmasm::Instruction::JUMP &&
|
opcode != evmasm::Instruction::JUMP &&
|
||||||
opcode != evmasm::Instruction::JUMPI &&
|
opcode != evmasm::Instruction::JUMPI &&
|
||||||
|
@ -64,6 +64,28 @@ void EthAssemblyAdapter::appendInstruction(evmasm::Instruction _instruction)
|
|||||||
m_assembly.append(_instruction);
|
m_assembly.append(_instruction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void EthAssemblyAdapter::appendSwap(unsigned _height)
|
||||||
|
{
|
||||||
|
m_assembly.append(evmasm::AssemblyItem(evmasm::AssemblyItemType::Swap, _height));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void EthAssemblyAdapter::appendDup(unsigned _height)
|
||||||
|
{
|
||||||
|
m_assembly.append(evmasm::AssemblyItem(evmasm::AssemblyItemType::Dup, _height));
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned EthAssemblyAdapter::maxDup() const
|
||||||
|
{
|
||||||
|
return m_assembly.maxDup();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned EthAssemblyAdapter::maxSwap() const
|
||||||
|
{
|
||||||
|
return m_assembly.maxSwap();
|
||||||
|
}
|
||||||
|
|
||||||
void EthAssemblyAdapter::appendConstant(u256 const& _constant)
|
void EthAssemblyAdapter::appendConstant(u256 const& _constant)
|
||||||
{
|
{
|
||||||
m_assembly.append(_constant);
|
m_assembly.append(_constant);
|
||||||
|
@ -44,6 +44,10 @@ public:
|
|||||||
int stackHeight() const override;
|
int stackHeight() const override;
|
||||||
void setStackHeight(int height) override;
|
void setStackHeight(int height) override;
|
||||||
void appendInstruction(evmasm::Instruction _instruction) override;
|
void appendInstruction(evmasm::Instruction _instruction) override;
|
||||||
|
void appendDup(unsigned _height) override;
|
||||||
|
void appendSwap(unsigned _height) override;
|
||||||
|
unsigned maxDup() const override;
|
||||||
|
unsigned maxSwap() const override;
|
||||||
void appendConstant(u256 const& _constant) override;
|
void appendConstant(u256 const& _constant) override;
|
||||||
void appendLabel(LabelID _labelId) override;
|
void appendLabel(LabelID _labelId) override;
|
||||||
void appendLabelReference(LabelID _labelId) override;
|
void appendLabelReference(LabelID _labelId) override;
|
||||||
|
@ -40,6 +40,22 @@ void NoOutputAssembly::appendInstruction(evmasm::Instruction _instr)
|
|||||||
m_stackHeight += instructionInfo(_instr).ret - instructionInfo(_instr).args;
|
m_stackHeight += instructionInfo(_instr).ret - instructionInfo(_instr).args;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NoOutputAssembly::appendSwap(unsigned)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void NoOutputAssembly::appendDup(unsigned)
|
||||||
|
{
|
||||||
|
m_stackHeight++;
|
||||||
|
}
|
||||||
|
unsigned NoOutputAssembly::maxDup() const
|
||||||
|
{
|
||||||
|
return 16;
|
||||||
|
}
|
||||||
|
unsigned NoOutputAssembly::maxSwap() const
|
||||||
|
{
|
||||||
|
return 16;
|
||||||
|
}
|
||||||
void NoOutputAssembly::appendConstant(u256 const&)
|
void NoOutputAssembly::appendConstant(u256 const&)
|
||||||
{
|
{
|
||||||
appendInstruction(evmasm::pushInstruction(1));
|
appendInstruction(evmasm::pushInstruction(1));
|
||||||
|
@ -52,6 +52,10 @@ public:
|
|||||||
int stackHeight() const override { return m_stackHeight; }
|
int stackHeight() const override { return m_stackHeight; }
|
||||||
void setStackHeight(int height) override { m_stackHeight = height; }
|
void setStackHeight(int height) override { m_stackHeight = height; }
|
||||||
void appendInstruction(evmasm::Instruction _instruction) override;
|
void appendInstruction(evmasm::Instruction _instruction) override;
|
||||||
|
void appendSwap(unsigned _height) override;
|
||||||
|
void appendDup(unsigned _height) override;
|
||||||
|
unsigned maxDup() const override;
|
||||||
|
unsigned maxSwap() const override;
|
||||||
void appendConstant(u256 const& _constant) override;
|
void appendConstant(u256 const& _constant) override;
|
||||||
void appendLabel(LabelID _labelId) override;
|
void appendLabel(LabelID _labelId) override;
|
||||||
void appendLabelReference(LabelID _labelId) override;
|
void appendLabelReference(LabelID _labelId) override;
|
||||||
|
@ -259,11 +259,11 @@ void OptimizedEVMCodeTransform::createStackLayout(std::shared_ptr<DebugData cons
|
|||||||
{
|
{
|
||||||
yulAssert(static_cast<int>(m_stack.size()) == m_assembly.stackHeight(), "");
|
yulAssert(static_cast<int>(m_stack.size()) == m_assembly.stackHeight(), "");
|
||||||
yulAssert(_i > 0 && _i < m_stack.size(), "");
|
yulAssert(_i > 0 && _i < m_stack.size(), "");
|
||||||
if (_i <= 16)
|
if (_i <= m_assembly.maxSwap())
|
||||||
m_assembly.appendInstruction(evmasm::swapInstruction(_i));
|
m_assembly.appendSwap(_i);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int deficit = static_cast<int>(_i) - 16;
|
int deficit = static_cast<int>(_i) - static_cast<int>(m_assembly.maxSwap());
|
||||||
StackSlot const& deepSlot = m_stack.at(m_stack.size() - _i - 1);
|
StackSlot const& deepSlot = m_stack.at(m_stack.size() - _i - 1);
|
||||||
YulString varNameDeep = slotVariableName(deepSlot);
|
YulString varNameDeep = slotVariableName(deepSlot);
|
||||||
YulString varNameTop = slotVariableName(m_stack.back());
|
YulString varNameTop = slotVariableName(m_stack.back());
|
||||||
@ -288,18 +288,18 @@ void OptimizedEVMCodeTransform::createStackLayout(std::shared_ptr<DebugData cons
|
|||||||
// Dup the slot, if already on stack and reachable.
|
// Dup the slot, if already on stack and reachable.
|
||||||
if (auto depth = util::findOffset(m_stack | ranges::views::reverse, _slot))
|
if (auto depth = util::findOffset(m_stack | ranges::views::reverse, _slot))
|
||||||
{
|
{
|
||||||
if (*depth < 16)
|
if (*depth < m_assembly.maxDup())
|
||||||
{
|
{
|
||||||
m_assembly.appendInstruction(evmasm::dupInstruction(static_cast<unsigned>(*depth + 1)));
|
m_assembly.appendDup(static_cast<unsigned>(*depth + 1));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (!canBeFreelyGenerated(_slot))
|
else if (!canBeFreelyGenerated(_slot))
|
||||||
{
|
{
|
||||||
int deficit = static_cast<int>(*depth - 15);
|
int deficit = static_cast<int>(*depth) - static_cast<int>(m_assembly.maxDup() - 1);
|
||||||
YulString varName = slotVariableName(_slot);
|
YulString varName = slotVariableName(_slot);
|
||||||
string msg =
|
string msg =
|
||||||
(varName.empty() ? "Slot " + stackSlotToString(_slot) : "Variable " + varName.str())
|
(varName.empty() ? "Slot " + stackSlotToString(_slot) : "Variable " + varName.str())
|
||||||
+ " is " + to_string(*depth - 15) + " too deep in the stack " + stackToString(m_stack);
|
+ " is " + to_string(*depth - (m_assembly.maxDup() - 1)) + " too deep in the stack " + stackToString(m_stack);
|
||||||
m_stackErrors.emplace_back(StackTooDeepError(
|
m_stackErrors.emplace_back(StackTooDeepError(
|
||||||
m_currentFunctionInfo ? m_currentFunctionInfo->function.name : YulString{},
|
m_currentFunctionInfo ? m_currentFunctionInfo->function.name : YulString{},
|
||||||
varName,
|
varName,
|
||||||
|
@ -740,14 +740,15 @@ void StackLayoutGenerator::fillInJunk(CFG::BasicBlock const& _block, CFG::Functi
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
/// @returns the number of operations required to transform @a _source to @a _target.
|
/// @returns the number of operations required to transform @a _source to @a _target.
|
||||||
auto evaluateTransform = [](Stack _source, Stack const& _target) -> size_t {
|
auto evaluateTransform = [&](Stack _source, Stack const& _target) -> size_t {
|
||||||
size_t opGas = 0;
|
size_t opGas = 0;
|
||||||
auto swap = [&](unsigned _swapDepth)
|
auto swap = [&](unsigned _swapDepth)
|
||||||
{
|
{
|
||||||
if (_swapDepth > 16)
|
if (_swapDepth > maxSwap())
|
||||||
opGas += 1000;
|
opGas += 1000;
|
||||||
else
|
else
|
||||||
opGas += evmasm::GasMeter::runGas(evmasm::swapInstruction(_swapDepth));
|
// TODO
|
||||||
|
opGas += evmasm::GasMeter::runGas(evmasm::Instruction::SWAP1);
|
||||||
};
|
};
|
||||||
auto dupOrPush = [&](StackSlot const& _slot)
|
auto dupOrPush = [&](StackSlot const& _slot)
|
||||||
{
|
{
|
||||||
@ -757,8 +758,9 @@ void StackLayoutGenerator::fillInJunk(CFG::BasicBlock const& _block, CFG::Functi
|
|||||||
{
|
{
|
||||||
auto depth = util::findOffset(_source | ranges::views::reverse, _slot);
|
auto depth = util::findOffset(_source | ranges::views::reverse, _slot);
|
||||||
yulAssert(depth);
|
yulAssert(depth);
|
||||||
if (*depth < 16)
|
if (*depth < maxDup())
|
||||||
opGas += evmasm::GasMeter::runGas(evmasm::dupInstruction(static_cast<unsigned>(*depth + 1)));
|
// TODO
|
||||||
|
opGas += evmasm::GasMeter::runGas(evmasm::Instruction::DUP1);
|
||||||
else
|
else
|
||||||
opGas += 1000;
|
opGas += 1000;
|
||||||
}
|
}
|
||||||
|
@ -115,6 +115,10 @@ private:
|
|||||||
void fillInJunk(CFG::BasicBlock const& _block, CFG::FunctionInfo const* _functionInfo = nullptr);
|
void fillInJunk(CFG::BasicBlock const& _block, CFG::FunctionInfo const* _functionInfo = nullptr);
|
||||||
|
|
||||||
StackLayout& m_layout;
|
StackLayout& m_layout;
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
unsigned maxSwap() const { return 16; }
|
||||||
|
unsigned maxDup() const { return 16; }
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -425,6 +425,7 @@ u256 EVMInstructionInterpreter::eval(
|
|||||||
case Instruction::DUP14:
|
case Instruction::DUP14:
|
||||||
case Instruction::DUP15:
|
case Instruction::DUP15:
|
||||||
case Instruction::DUP16:
|
case Instruction::DUP16:
|
||||||
|
case Instruction::DUP_N:
|
||||||
case Instruction::SWAP1:
|
case Instruction::SWAP1:
|
||||||
case Instruction::SWAP2:
|
case Instruction::SWAP2:
|
||||||
case Instruction::SWAP3:
|
case Instruction::SWAP3:
|
||||||
@ -441,6 +442,7 @@ u256 EVMInstructionInterpreter::eval(
|
|||||||
case Instruction::SWAP14:
|
case Instruction::SWAP14:
|
||||||
case Instruction::SWAP15:
|
case Instruction::SWAP15:
|
||||||
case Instruction::SWAP16:
|
case Instruction::SWAP16:
|
||||||
|
case Instruction::SWAP_N:
|
||||||
{
|
{
|
||||||
yulAssert(false, "");
|
yulAssert(false, "");
|
||||||
return 0;
|
return 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user