mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Add RJUMP
This commit is contained in:
parent
591df04211
commit
4d4dfbc456
@ -533,11 +533,13 @@ LinkerObject const& Assembly::assemble() const
|
||||
unsigned bytesRequiredForCode = codeSize(static_cast<unsigned>(subTagSize));
|
||||
m_tagPositionsInBytecode = vector<size_t>(m_usedTags, numeric_limits<size_t>::max());
|
||||
map<size_t, pair<size_t, size_t>> tagRef;
|
||||
set<size_t> isStaticTagRef;
|
||||
multimap<h256, unsigned> dataRef;
|
||||
multimap<size_t, size_t> subRef;
|
||||
vector<unsigned> sizeRef; ///< Pointers to code locations where the size of the program is inserted
|
||||
unsigned bytesPerTag = numberEncodingSize(bytesRequiredForCode);
|
||||
uint8_t tagPush = static_cast<uint8_t>(pushInstruction(bytesPerTag));
|
||||
constexpr unsigned bytesPerStaticTag = 2;
|
||||
|
||||
unsigned bytesRequiredIncludingData = bytesRequiredForCode + 1 + static_cast<unsigned>(m_auxiliaryData.size());
|
||||
for (auto const& sub: m_subs)
|
||||
@ -574,6 +576,16 @@ LinkerObject const& Assembly::assemble() const
|
||||
ret.bytecode.resize(ret.bytecode.size() + bytesPerTag);
|
||||
break;
|
||||
}
|
||||
case StaticJump:
|
||||
case StaticJumpI:
|
||||
{
|
||||
ret.bytecode.push_back(static_cast<uint8_t>((i.type() == StaticJump) ? Instruction::RJUMP : Instruction::RJUMPI));
|
||||
ret.bytecode.push_back(tagPush);
|
||||
tagRef[ret.bytecode.size()] = i.splitForeignPushTag();
|
||||
isStaticTagRef.insert(ret.bytecode.size());
|
||||
ret.bytecode.resize(ret.bytecode.size() + bytesPerStaticTag);
|
||||
break;
|
||||
}
|
||||
case PushData:
|
||||
ret.bytecode.push_back(dataRefPush);
|
||||
dataRef.insert(make_pair(h256(i.data()), ret.bytecode.size()));
|
||||
@ -699,9 +711,17 @@ LinkerObject const& Assembly::assemble() const
|
||||
assertThrow(tagId < tagPositions.size(), AssemblyException, "Reference to non-existing tag.");
|
||||
size_t pos = tagPositions[tagId];
|
||||
assertThrow(pos != numeric_limits<size_t>::max(), AssemblyException, "Reference to tag without position.");
|
||||
assertThrow(numberEncodingSize(pos) <= bytesPerTag, AssemblyException, "Tag too large for reserved space.");
|
||||
bytesRef r(ret.bytecode.data() + i.first, bytesPerTag);
|
||||
toBigEndian(pos, r);
|
||||
if (isStaticTagRef.count(i.first)) {
|
||||
pos = pos - (i.first + bytesPerStaticTag); // TODO: do properly
|
||||
assertThrow(numberEncodingSize(pos) <= bytesPerStaticTag, AssemblyException, "Tag too large for reserved space.");
|
||||
//pos = static_cast<uint16_t>(spos);
|
||||
bytesRef r(ret.bytecode.data() + i.first, bytesPerStaticTag);
|
||||
toBigEndian(pos, r);
|
||||
} else {
|
||||
assertThrow(numberEncodingSize(pos) <= bytesPerTag, AssemblyException, "Tag too large for reserved space.");
|
||||
bytesRef r(ret.bytecode.data() + i.first, bytesPerTag);
|
||||
toBigEndian(pos, r);
|
||||
}
|
||||
}
|
||||
for (auto const& [name, tagInfo]: m_namedTags)
|
||||
{
|
||||
|
@ -83,8 +83,14 @@ public:
|
||||
append(AssemblyItem(std::move(_data), _arguments, _returnVariables));
|
||||
}
|
||||
|
||||
AssemblyItem appendStaticJump() { assertThrow(m_usedTags < 0xffffffff, AssemblyException, ""); return AssemblyItem(StaticJump, m_usedTags++); }
|
||||
AssemblyItem appendStaticJumpI() { assertThrow(m_usedTags < 0xffffffff, AssemblyException, ""); return AssemblyItem(StaticJumpI, m_usedTags++); }
|
||||
// AssemblyItem appendJump() { assertThrow(m_usedTags < 0xffffffff, AssemblyException, ""); return AssemblyItem(StaticJump, m_usedTags++); }
|
||||
// AssemblyItem appendJumpI() { assertThrow(m_usedTags < 0xffffffff, AssemblyException, ""); return AssemblyItem(StaticJumpI, m_usedTags++); }
|
||||
AssemblyItem appendJump() { auto ret = append(newPushTag()); append(Instruction::JUMP); return ret; }
|
||||
AssemblyItem appendJumpI() { auto ret = append(newPushTag()); append(Instruction::JUMPI); return ret; }
|
||||
AssemblyItem appendStaticJump(AssemblyItem const& _tag) { /*force typecheck*/_tag.pushTag(); return AssemblyItem(StaticJump, _tag.data()); }
|
||||
AssemblyItem appendStaticJumpI(AssemblyItem const& _tag) { /*force typecheck*/_tag.pushTag(); return AssemblyItem(StaticJumpI, _tag.data()); }
|
||||
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; }
|
||||
|
||||
|
@ -62,7 +62,7 @@ AssemblyItem AssemblyItem::toSubAssemblyTag(size_t _subId) const
|
||||
|
||||
pair<size_t, size_t> AssemblyItem::splitForeignPushTag() const
|
||||
{
|
||||
assertThrow(m_type == PushTag || m_type == Tag, util::Exception, "");
|
||||
assertThrow(m_type == StaticJump || m_type == StaticJumpI || m_type == PushTag || m_type == Tag, util::Exception, "");
|
||||
u256 combined = u256(data());
|
||||
size_t subId = static_cast<size_t>((combined >> 64) - 1);
|
||||
size_t tag = static_cast<size_t>(combined & 0xffffffffffffffffULL);
|
||||
@ -159,6 +159,9 @@ size_t AssemblyItem::bytesRequired(size_t _addressLength, Precision _precision)
|
||||
}
|
||||
case VerbatimBytecode:
|
||||
return std::get<2>(*m_verbatimBytecode).size();
|
||||
case StaticJump:
|
||||
case StaticJumpI:
|
||||
return 3;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -50,7 +50,9 @@ enum AssemblyItemType
|
||||
PushDeployTimeAddress, ///< Push an address to be filled at deploy time. Should not be touched by the optimizer.
|
||||
PushImmutable, ///< Push the currently unknown value of an immutable variable. The actual value will be filled in by the constructor.
|
||||
AssignImmutable, ///< Assigns the current value on the stack to an immutable variable. Only valid during creation code.
|
||||
VerbatimBytecode ///< Contains data that is inserted into the bytecode code section without modification.
|
||||
VerbatimBytecode, ///< Contains data that is inserted into the bytecode code section without modification.
|
||||
StaticJump,
|
||||
StaticJumpI
|
||||
};
|
||||
|
||||
enum class Precision { Precise , Approximate };
|
||||
@ -91,8 +93,8 @@ public:
|
||||
AssemblyItem& operator=(AssemblyItem const&) = default;
|
||||
AssemblyItem& operator=(AssemblyItem&&) = default;
|
||||
|
||||
AssemblyItem tag() const { assertThrow(m_type == PushTag || m_type == Tag, util::Exception, ""); return AssemblyItem(Tag, data()); }
|
||||
AssemblyItem pushTag() const { assertThrow(m_type == PushTag || m_type == Tag, util::Exception, ""); return AssemblyItem(PushTag, data()); }
|
||||
AssemblyItem tag() const { assertThrow(m_type == StaticJump || m_type == StaticJumpI || m_type == PushTag || m_type == Tag, util::Exception, ""); return AssemblyItem(Tag, data()); }
|
||||
AssemblyItem pushTag() const { assertThrow(m_type == StaticJump || m_type == StaticJumpI || m_type == PushTag || m_type == Tag, util::Exception, ""); return AssemblyItem(PushTag, data()); }
|
||||
/// Converts the tag to a subassembly tag. This has to be called in order to move a tag across assemblies.
|
||||
/// @param _subId the identifier of the subassembly the tag is taken from.
|
||||
AssemblyItem toSubAssemblyTag(size_t _subId) const;
|
||||
|
@ -93,6 +93,8 @@ std::map<std::string, Instruction> const solidity::evmasm::c_instructions =
|
||||
{ "MSIZE", Instruction::MSIZE },
|
||||
{ "GAS", Instruction::GAS },
|
||||
{ "JUMPDEST", Instruction::JUMPDEST },
|
||||
{ "RJUMP", Instruction::RJUMP },
|
||||
{ "RJUMPI", Instruction::RJUMPI },
|
||||
{ "PUSH1", Instruction::PUSH1 },
|
||||
{ "PUSH2", Instruction::PUSH2 },
|
||||
{ "PUSH3", Instruction::PUSH3 },
|
||||
@ -240,6 +242,8 @@ static std::map<Instruction, InstructionInfo> const c_instructionInfo =
|
||||
{ Instruction::MSIZE, { "MSIZE", 0, 0, 1, false, Tier::Base } },
|
||||
{ Instruction::GAS, { "GAS", 0, 0, 1, false, Tier::Base } },
|
||||
{ Instruction::JUMPDEST, { "JUMPDEST", 0, 0, 0, true, Tier::Special } },
|
||||
{ Instruction::RJUMP, { "RJUMP", 0, 0, 0, true, Tier::Mid } },
|
||||
{ Instruction::RJUMPI, { "RJUMPI", 0, 1, 0, true, Tier::High } },
|
||||
{ Instruction::PUSH1, { "PUSH1", 1, 0, 1, false, Tier::VeryLow } },
|
||||
{ Instruction::PUSH2, { "PUSH2", 2, 0, 1, false, Tier::VeryLow } },
|
||||
{ Instruction::PUSH3, { "PUSH3", 3, 0, 1, false, Tier::VeryLow } },
|
||||
|
@ -101,6 +101,8 @@ enum class Instruction: uint8_t
|
||||
MSIZE, ///< get the size of active memory
|
||||
GAS, ///< get the amount of available gas
|
||||
JUMPDEST, ///< set a potential jump destination
|
||||
RJUMP,
|
||||
RJUMPI,
|
||||
|
||||
PUSH1 = 0x60, ///< place 1 byte item on stack
|
||||
PUSH2, ///< place 2 byte item on stack
|
||||
|
Loading…
Reference in New Issue
Block a user