mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Initial working version of rjumps.
This commit is contained in:
parent
d4314bb874
commit
0ccc3e3762
@ -511,7 +511,7 @@ LinkerObject const& Assembly::assemble() const
|
||||
|
||||
LinkerObject& ret = m_assembledObject;
|
||||
|
||||
bool const needsEOFContainer = m_eofVersion.has_value();
|
||||
bool const eof = m_eofVersion.has_value();
|
||||
|
||||
size_t subTagSize = 1;
|
||||
map<u256, pair<string, vector<size_t>>> immutableReferencesBySub;
|
||||
@ -575,10 +575,11 @@ LinkerObject const& Assembly::assemble() const
|
||||
std::optional<size_t> dataSectionSizeOffset;
|
||||
auto setDataSectionSize = [&](size_t _size) {
|
||||
assertThrow(dataSectionSizeOffset.has_value(), AssemblyException, "");
|
||||
assertThrow(_size <= 0xFFFF, AssemblyException, "");
|
||||
bytesRef length(ret.bytecode.data() + *dataSectionSizeOffset, 2);
|
||||
toBigEndian(_size, length);
|
||||
toBigEndian(static_cast<uint16_t>(_size), length);
|
||||
};
|
||||
if (needsEOFContainer)
|
||||
if (eof)
|
||||
{
|
||||
bool needsTypeSection = m_codeSections.size() > 1;
|
||||
// TODO: empty data is disallowed
|
||||
@ -621,14 +622,20 @@ LinkerObject const& Assembly::assemble() const
|
||||
unsigned headerSize = static_cast<unsigned>(ret.bytecode.size());
|
||||
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;
|
||||
struct TagRef
|
||||
{
|
||||
size_t subId = 0;
|
||||
size_t tagId = 0;
|
||||
bool isRelative = 0;
|
||||
};
|
||||
map<size_t, TagRef> tagRef;
|
||||
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(headerSize + bytesRequiredForCode + bytesRequiredForDataUpperBound);
|
||||
uint8_t tagPush = static_cast<uint8_t>(pushInstruction(bytesPerTag));
|
||||
|
||||
if (!needsEOFContainer)
|
||||
if (!eof)
|
||||
++bytesRequiredForCode; ///< Additional INVALID marker.
|
||||
|
||||
unsigned bytesRequiredIncludingDataAndSubsUpperBound = headerSize + bytesRequiredForCode + bytesRequiredForDataAndSubsUpperBound;
|
||||
@ -636,10 +643,6 @@ LinkerObject const& Assembly::assemble() const
|
||||
uint8_t dataRefPush = static_cast<uint8_t>(pushInstruction(bytesPerDataRef));
|
||||
ret.bytecode.reserve(bytesRequiredIncludingDataAndSubsUpperBound);
|
||||
|
||||
auto const codeStart = ret.bytecode.size();
|
||||
|
||||
|
||||
|
||||
for (auto&& [codeSectionIndex, codeSection]: m_codeSections | ranges::views::enumerate)
|
||||
{
|
||||
auto const sectionStart = ret.bytecode.size();
|
||||
@ -666,8 +669,10 @@ LinkerObject const& Assembly::assemble() const
|
||||
}
|
||||
case PushTag:
|
||||
{
|
||||
assertThrow(!eof, AssemblyException, "Push tag in EOF code");
|
||||
ret.bytecode.push_back(tagPush);
|
||||
tagRef[ret.bytecode.size()] = i.splitForeignPushTag();
|
||||
auto [subId, tagId] = i.splitForeignPushTag();
|
||||
tagRef[ret.bytecode.size()] = TagRef{subId, tagId, false};
|
||||
ret.bytecode.resize(ret.bytecode.size() + bytesPerTag);
|
||||
break;
|
||||
}
|
||||
@ -722,7 +727,7 @@ LinkerObject const& Assembly::assemble() const
|
||||
{
|
||||
// Expect 2 elements on stack (source, dest_base)
|
||||
auto const& offsets = immutableReferencesBySub[i.data()].second;
|
||||
for (size_t i = 0; i < offsets.size(); ++i)
|
||||
for (size_t i = 0u; i < offsets.size(); ++i)
|
||||
{
|
||||
if (i != offsets.size() - 1)
|
||||
{
|
||||
@ -755,12 +760,14 @@ LinkerObject const& Assembly::assemble() const
|
||||
size_t tagId = static_cast<size_t>(i.data());
|
||||
assertThrow(ret.bytecode.size() < 0xffffffffL, AssemblyException, "Tag too large.");
|
||||
assertThrow(m_tagPositionsInBytecode[tagId] == numeric_limits<size_t>::max(), AssemblyException, "Duplicate tag position.");
|
||||
m_tagPositionsInBytecode[tagId] = ret.bytecode.size() - codeStart;
|
||||
ret.bytecode.push_back(static_cast<uint8_t>(Instruction::JUMPDEST));
|
||||
m_tagPositionsInBytecode[tagId] = ret.bytecode.size();
|
||||
if (!eof)
|
||||
ret.bytecode.push_back(static_cast<uint8_t>(Instruction::JUMPDEST));
|
||||
break;
|
||||
}
|
||||
case CallF:
|
||||
{
|
||||
assertThrow(eof, AssemblyException, "Function call (CALLF) in non-EOF code");
|
||||
ret.bytecode.push_back(static_cast<uint8_t>(Instruction::CALLF));
|
||||
ret.bytecode.resize(ret.bytecode.size() + 2);
|
||||
bytesRef byr(&ret.bytecode.back() + 1 - 2, 2);
|
||||
@ -769,9 +776,21 @@ LinkerObject const& Assembly::assemble() const
|
||||
}
|
||||
case RetF:
|
||||
{
|
||||
assertThrow(eof, AssemblyException, "Function return (RETF) in non-EOF code");
|
||||
ret.bytecode.push_back(static_cast<uint8_t>(Instruction::RETF));
|
||||
break;
|
||||
}
|
||||
case RelativeJump:
|
||||
case ConditionalRelativeJump:
|
||||
{
|
||||
assertThrow(eof, AssemblyException, "Relative jump in non-EOF code");
|
||||
ret.bytecode.push_back(static_cast<uint8_t>(i.type() == RelativeJump ? Instruction::RJUMP : Instruction::RJUMPI));
|
||||
auto [subId, tagId] = i.splitForeignPushTag();
|
||||
tagRef[ret.bytecode.size()] = TagRef{subId, tagId, true};
|
||||
ret.bytecode.push_back(0x00);
|
||||
ret.bytecode.push_back(0x00);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assertThrow(false, InvalidOpcode, "Unexpected opcode while assembling.");
|
||||
}
|
||||
@ -779,7 +798,7 @@ LinkerObject const& Assembly::assemble() const
|
||||
|
||||
auto sectionEnd = ret.bytecode.size();
|
||||
|
||||
if (needsEOFContainer)
|
||||
if (eof)
|
||||
setCodeSectionSize(codeSectionIndex, sectionEnd - sectionStart);
|
||||
}
|
||||
|
||||
@ -791,7 +810,7 @@ LinkerObject const& Assembly::assemble() const
|
||||
"Some immutables were read from but never assigned, possibly because of optimization."
|
||||
);
|
||||
|
||||
if (!needsEOFContainer && (!m_subs.empty() || !m_data.empty() || !m_auxiliaryData.empty()))
|
||||
if (!eof && (!m_subs.empty() || !m_data.empty() || !m_auxiliaryData.empty()))
|
||||
// Append an INVALID here to help tests find miscompilation.
|
||||
ret.bytecode.push_back(static_cast<uint8_t>(Instruction::INVALID));
|
||||
|
||||
@ -819,11 +838,11 @@ LinkerObject const& Assembly::assemble() const
|
||||
}
|
||||
}
|
||||
|
||||
for (auto const& i: tagRef)
|
||||
for (auto const& [bytecodeOffset, ref]: tagRef)
|
||||
{
|
||||
size_t subId;
|
||||
size_t tagId;
|
||||
tie(subId, tagId) = i.second;
|
||||
size_t subId = ref.subId;
|
||||
size_t tagId = ref.tagId;
|
||||
bool relative = ref.isRelative;
|
||||
assertThrow(subId == numeric_limits<size_t>::max() || subId < m_subs.size(), AssemblyException, "Invalid sub id");
|
||||
vector<size_t> const& tagPositions =
|
||||
subId == numeric_limits<size_t>::max() ?
|
||||
@ -833,8 +852,26 @@ LinkerObject const& Assembly::assemble() const
|
||||
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 (relative)
|
||||
{
|
||||
assertThrow(m_eofVersion.has_value(), AssemblyException, "Relative jump outside EOF");
|
||||
assertThrow(subId == numeric_limits<size_t>::max(), AssemblyException, "Relative jump to sub");
|
||||
bytesRef r(ret.bytecode.data() + bytecodeOffset, 2);
|
||||
assertThrow(
|
||||
static_cast<ssize_t>(pos) - static_cast<ssize_t>(bytecodeOffset + 2u) < 0x7FFF &&
|
||||
static_cast<ssize_t>(pos) - static_cast<ssize_t>(bytecodeOffset + 2u) >= -0x8000,
|
||||
AssemblyException,
|
||||
"Relative jump too far"
|
||||
);
|
||||
uint16_t relativeOffset = static_cast<uint16_t>(pos - (bytecodeOffset + 2u));
|
||||
toBigEndian(relativeOffset, r);
|
||||
}
|
||||
else
|
||||
{
|
||||
assertThrow(!m_eofVersion.has_value(), AssemblyException, "Dynamic tag reference within EOF");
|
||||
bytesRef r(ret.bytecode.data() + bytecodeOffset, bytesPerTag);
|
||||
toBigEndian(pos, r);
|
||||
}
|
||||
}
|
||||
for (auto const& [name, tagInfo]: m_namedTags)
|
||||
{
|
||||
@ -871,7 +908,7 @@ LinkerObject const& Assembly::assemble() const
|
||||
|
||||
ret.bytecode += m_auxiliaryData;
|
||||
|
||||
if (needsEOFContainer && bytesRequiredForDataAndSubsUpperBound > 0 && ret.bytecode.size() == dataStart)
|
||||
if (eof && bytesRequiredForDataAndSubsUpperBound > 0 && ret.bytecode.size() == dataStart)
|
||||
{
|
||||
// We have commited to a data section, but not actually needed it, so create a fake one.
|
||||
ret.bytecode.push_back(0);
|
||||
@ -884,25 +921,13 @@ LinkerObject const& Assembly::assemble() const
|
||||
}
|
||||
|
||||
auto dataLength = ret.bytecode.size() - dataStart;
|
||||
if (needsEOFContainer)
|
||||
if (eof)
|
||||
{
|
||||
if (bytesRequiredForDataAndSubsUpperBound < dataLength)
|
||||
{
|
||||
std::cout << "Auxdata: " << m_auxiliaryData.size() << std::endl;
|
||||
std::cout << "m_data: " << m_data.size() << std::endl;
|
||||
std::cout << "subRef: " << subRef.size() << std::endl;
|
||||
for (auto&& [subIdPath, offset]: subRef)
|
||||
{
|
||||
(void)offset;
|
||||
std::cout << "R: " << subAssemblyById(subIdPath) << std::endl;
|
||||
}
|
||||
std::cout << "m_subs: " << m_subs.size() << std::endl;
|
||||
for (auto const& sub: m_subs)
|
||||
{
|
||||
std::cout << "sub: " << sub.get() << std::endl;
|
||||
}
|
||||
}
|
||||
assertThrow(bytesRequiredForDataAndSubsUpperBound >= dataLength, AssemblyException, "More data than expected. " + to_string(dataLength) + " > " + to_string(bytesRequiredForDataUpperBound));
|
||||
assertThrow(
|
||||
bytesRequiredForDataAndSubsUpperBound >= dataLength,
|
||||
AssemblyException,
|
||||
"More data than expected. " + to_string(dataLength) + " > " + to_string(bytesRequiredForDataUpperBound)
|
||||
);
|
||||
if (bytesRequiredForDataAndSubsUpperBound > 0)
|
||||
{
|
||||
assertThrow(0 < dataLength && dataLength <= 0xffff, AssemblyException, "Invalid data section size.");
|
||||
|
@ -59,6 +59,7 @@ public:
|
||||
|
||||
std::optional<uint8_t> eofVersion() const { return m_eofVersion; }
|
||||
bool supportsFunctions() const { return m_eofVersion.has_value(); }
|
||||
bool supportsRelativeJumps() const { return m_eofVersion.has_value(); }
|
||||
AssemblyItem newTag() { assertThrow(m_usedTags < 0xffffffff, AssemblyException, ""); return AssemblyItem(Tag, m_usedTags++); }
|
||||
AssemblyItem newPushTag() { assertThrow(m_usedTags < 0xffffffff, AssemblyException, ""); return AssemblyItem(PushTag, m_usedTags++); }
|
||||
AssemblyItem newFunctionCall(uint16_t _functionID)
|
||||
|
@ -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 == PushTag || m_type == Tag || m_type == RelativeJump || m_type == ConditionalRelativeJump, 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);
|
||||
@ -109,7 +109,7 @@ pair<string, string> AssemblyItem::nameAndData() const
|
||||
|
||||
void AssemblyItem::setPushTagSubIdAndTag(size_t _subId, size_t _tag)
|
||||
{
|
||||
assertThrow(m_type == PushTag || m_type == Tag, util::Exception, "");
|
||||
assertThrow(m_type == PushTag || m_type == Tag || m_type == RelativeJump || m_type == ConditionalRelativeJump , util::Exception, "");
|
||||
u256 data = _tag;
|
||||
if (_subId != numeric_limits<size_t>::max())
|
||||
data |= (u256(_subId) + 1) << 64;
|
||||
@ -163,6 +163,10 @@ size_t AssemblyItem::bytesRequired(size_t _addressLength, Precision _precision)
|
||||
return 3;
|
||||
case RetF:
|
||||
return 1;
|
||||
case RelativeJump:
|
||||
return 3;
|
||||
case ConditionalRelativeJump:
|
||||
return 3;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -183,9 +187,9 @@ size_t AssemblyItem::arguments() const
|
||||
return std::get<0>(*m_functionSignature);
|
||||
}
|
||||
else if (type() == RetF)
|
||||
{
|
||||
return static_cast<size_t>(data());
|
||||
}
|
||||
else if (type() == ConditionalRelativeJump)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
@ -333,6 +337,12 @@ string AssemblyItem::toAssemblyText(Assembly const& _assembly) const
|
||||
case RetF:
|
||||
text = "retf";
|
||||
break;
|
||||
case RelativeJump:
|
||||
text = "rjump(" + string("tag_") + to_string(static_cast<size_t>(data())) + ")";
|
||||
break;
|
||||
case ConditionalRelativeJump:
|
||||
text = "rjumpi(" + string("tag_") + to_string(static_cast<size_t>(data())) + ")";
|
||||
break;
|
||||
default:
|
||||
assertThrow(false, InvalidOpcode, "");
|
||||
}
|
||||
@ -374,6 +384,24 @@ ostream& solidity::evmasm::operator<<(ostream& _out, AssemblyItem const& _item)
|
||||
_out << " PushTag " << subId << ":" << _item.splitForeignPushTag().second;
|
||||
break;
|
||||
}
|
||||
case RelativeJump:
|
||||
{
|
||||
size_t subId = _item.splitForeignPushTag().first;
|
||||
if (subId == numeric_limits<size_t>::max())
|
||||
_out << " RelativeJump " << _item.splitForeignPushTag().second;
|
||||
else
|
||||
_out << " RelativeJump " << subId << ":" << _item.splitForeignPushTag().second;
|
||||
break;
|
||||
}
|
||||
case ConditionalRelativeJump:
|
||||
{
|
||||
size_t subId = _item.splitForeignPushTag().first;
|
||||
if (subId == numeric_limits<size_t>::max())
|
||||
_out << " ConditionalRelativeJump " << _item.splitForeignPushTag().second;
|
||||
else
|
||||
_out << " ConditionalRelativeJump " << subId << ":" << _item.splitForeignPushTag().second;
|
||||
break;
|
||||
}
|
||||
case Tag:
|
||||
_out << " Tag " << _item.data();
|
||||
break;
|
||||
|
@ -52,7 +52,9 @@ enum AssemblyItemType
|
||||
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.
|
||||
CallF,
|
||||
RetF
|
||||
RetF,
|
||||
RelativeJump,
|
||||
ConditionalRelativeJump
|
||||
};
|
||||
|
||||
enum class Precision { Precise , Approximate };
|
||||
@ -97,6 +99,14 @@ public:
|
||||
{
|
||||
return AssemblyItem(RetF, _rets, _location);
|
||||
}
|
||||
static AssemblyItem jumpTo(AssemblyItem _tag, langutil::SourceLocation _location = langutil::SourceLocation())
|
||||
{
|
||||
return AssemblyItem(RelativeJump, _tag.data(), _location);
|
||||
}
|
||||
static AssemblyItem conditionalJumpTo(AssemblyItem _tag, langutil::SourceLocation _location = langutil::SourceLocation())
|
||||
{
|
||||
return AssemblyItem(ConditionalRelativeJump, _tag.data(), _location);
|
||||
}
|
||||
|
||||
AssemblyItem(AssemblyItem const&) = default;
|
||||
AssemblyItem(AssemblyItem&&) = default;
|
||||
|
@ -107,7 +107,7 @@ bool BlockDeduplicator::applyTagReplacement(
|
||||
{
|
||||
bool changed = false;
|
||||
for (AssemblyItem& item: _items)
|
||||
if (item.type() == PushTag)
|
||||
if (item.type() == PushTag || item.type() == RelativeJump || item.type() == ConditionalRelativeJump)
|
||||
{
|
||||
size_t subId;
|
||||
size_t tagId;
|
||||
|
@ -93,6 +93,9 @@ 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 },
|
||||
{ "RJUMPV", Instruction::RJUMPV },
|
||||
{ "PUSH1", Instruction::PUSH1 },
|
||||
{ "PUSH2", Instruction::PUSH2 },
|
||||
{ "PUSH3", Instruction::PUSH3 },
|
||||
@ -240,6 +243,9 @@ 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::Low } },
|
||||
{ Instruction::RJUMPI, { "RJUMPI", 0, 0, 0, true, Tier::Low } },
|
||||
{ Instruction::RJUMPV, { "RJUMPV", 0, 1, 0, true, Tier::Low } },
|
||||
{ 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,9 @@ 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,
|
||||
RJUMPV,
|
||||
|
||||
PUSH1 = 0x60, ///< place 1 byte item on stack
|
||||
PUSH2, ///< place 2 byte item on stack
|
||||
|
@ -59,7 +59,7 @@ set<size_t> JumpdestRemover::referencedTags(AssemblyItems const& _items, size_t
|
||||
{
|
||||
set<size_t> ret;
|
||||
for (auto const& item: _items)
|
||||
if (item.type() == PushTag)
|
||||
if (item.type() == PushTag || item.type() == RelativeJump || item.type() == ConditionalRelativeJump)
|
||||
{
|
||||
auto subAndTag = item.splitForeignPushTag();
|
||||
if (subAndTag.first == _subId)
|
||||
|
@ -291,6 +291,29 @@ struct IsZeroIsZeroJumpI: SimplePeepholeOptimizerMethod<IsZeroIsZeroJumpI>
|
||||
}
|
||||
};
|
||||
|
||||
struct IsZeroIsZeroRJumpI: SimplePeepholeOptimizerMethod<IsZeroIsZeroJumpI>
|
||||
{
|
||||
static size_t applySimple(
|
||||
AssemblyItem const& _iszero1,
|
||||
AssemblyItem const& _iszero2,
|
||||
AssemblyItem const& _rjumpi,
|
||||
std::back_insert_iterator<AssemblyItems> _out
|
||||
)
|
||||
{
|
||||
if (
|
||||
_iszero1 == Instruction::ISZERO &&
|
||||
_iszero2 == Instruction::ISZERO &&
|
||||
_rjumpi.type() == ConditionalRelativeJump
|
||||
)
|
||||
{
|
||||
*_out = _rjumpi;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
struct EqIsZeroJumpI: SimplePeepholeOptimizerMethod<EqIsZeroJumpI>
|
||||
{
|
||||
static size_t applySimple(
|
||||
@ -318,6 +341,30 @@ struct EqIsZeroJumpI: SimplePeepholeOptimizerMethod<EqIsZeroJumpI>
|
||||
}
|
||||
};
|
||||
|
||||
struct EqIsZeroRJumpI: SimplePeepholeOptimizerMethod<EqIsZeroJumpI>
|
||||
{
|
||||
static size_t applySimple(
|
||||
AssemblyItem const& _eq,
|
||||
AssemblyItem const& _iszero,
|
||||
AssemblyItem const& _rjumpi,
|
||||
std::back_insert_iterator<AssemblyItems> _out
|
||||
)
|
||||
{
|
||||
if (
|
||||
_eq == Instruction::EQ &&
|
||||
_iszero == Instruction::ISZERO &&
|
||||
_rjumpi.type() == ConditionalRelativeJump
|
||||
)
|
||||
{
|
||||
*_out = AssemblyItem(Instruction::SUB, _eq.location());
|
||||
*_out = _rjumpi;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// push_tag_1 jumpi push_tag_2 jump tag_1: -> iszero push_tag_2 jumpi tag_1:
|
||||
struct DoubleJump: SimplePeepholeOptimizerMethod<DoubleJump>
|
||||
{
|
||||
@ -350,6 +397,33 @@ struct DoubleJump: SimplePeepholeOptimizerMethod<DoubleJump>
|
||||
}
|
||||
};
|
||||
|
||||
// rjumpi(tag_1) rjump(tag_2) tag_1: -> iszero rjumpi(tag_2) tag_1:
|
||||
struct DoubleRJump: SimplePeepholeOptimizerMethod<DoubleJump>
|
||||
{
|
||||
static size_t applySimple(
|
||||
AssemblyItem const& _rjumpi,
|
||||
AssemblyItem const& _rjump,
|
||||
AssemblyItem const& _tag1,
|
||||
std::back_insert_iterator<AssemblyItems> _out
|
||||
)
|
||||
{
|
||||
if (
|
||||
_rjumpi.type() == ConditionalRelativeJump &&
|
||||
_rjump.type() == RelativeJump &&
|
||||
_tag1.type() == Tag &&
|
||||
_rjumpi.data() == _tag1.data()
|
||||
)
|
||||
{
|
||||
*_out = AssemblyItem(Instruction::ISZERO, _rjumpi.location());
|
||||
*_out = AssemblyItem::conditionalJumpTo(_rjump.tag(), _rjump.location());
|
||||
*_out = _tag1;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
struct JumpToNext: SimplePeepholeOptimizerMethod<JumpToNext>
|
||||
{
|
||||
static size_t applySimple(
|
||||
@ -376,6 +450,30 @@ struct JumpToNext: SimplePeepholeOptimizerMethod<JumpToNext>
|
||||
}
|
||||
};
|
||||
|
||||
struct RJumpToNext: SimplePeepholeOptimizerMethod<JumpToNext>
|
||||
{
|
||||
static size_t applySimple(
|
||||
AssemblyItem const& _rjump,
|
||||
AssemblyItem const& _tag,
|
||||
std::back_insert_iterator<AssemblyItems> _out
|
||||
)
|
||||
{
|
||||
if (
|
||||
(_rjump.type() == ConditionalRelativeJump || _rjump.type() == RelativeJump) &&
|
||||
_tag.type() == Tag &&
|
||||
_rjump.data() == _tag.data()
|
||||
)
|
||||
{
|
||||
if (_rjump.type() == ConditionalRelativeJump)
|
||||
*_out = AssemblyItem(Instruction::POP, _rjump.location());
|
||||
*_out = _tag;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
struct TagConjunctions: SimplePeepholeOptimizerMethod<TagConjunctions>
|
||||
{
|
||||
static bool applySimple(
|
||||
@ -439,6 +537,7 @@ struct UnreachableCode
|
||||
return false;
|
||||
if (
|
||||
it[0] != Instruction::JUMP &&
|
||||
it[0] != Instruction::RJUMP &&
|
||||
it[0] != Instruction::RETURN &&
|
||||
it[0] != Instruction::STOP &&
|
||||
it[0] != Instruction::INVALID &&
|
||||
@ -489,8 +588,8 @@ bool PeepholeOptimiser::optimise()
|
||||
applyMethods(
|
||||
state,
|
||||
PushPop(), OpPop(), OpStop(), OpReturnRevert(), DoublePush(), DoubleSwap(), CommutativeSwap(), SwapComparison(),
|
||||
DupSwap(), IsZeroIsZeroJumpI(), EqIsZeroJumpI(), DoubleJump(), JumpToNext(), UnreachableCode(),
|
||||
TagConjunctions(), TruthyAnd(), Identity()
|
||||
DupSwap(), IsZeroIsZeroJumpI(), IsZeroIsZeroRJumpI{}, EqIsZeroJumpI(), DoubleJump(), DoubleRJump(),
|
||||
JumpToNext(), RJumpToNext(), UnreachableCode(), TagConjunctions(), TruthyAnd(), Identity()
|
||||
);
|
||||
if (m_optimisedItems.size() < m_items.size() || (
|
||||
m_optimisedItems.size() == m_items.size() && (
|
||||
|
@ -112,14 +112,31 @@ void EthAssemblyAdapter::appendJump(int _stackDiffAfter, JumpType _jumpType)
|
||||
|
||||
void EthAssemblyAdapter::appendJumpTo(LabelID _labelId, int _stackDiffAfter, JumpType _jumpType)
|
||||
{
|
||||
appendLabelReference(_labelId);
|
||||
appendJump(_stackDiffAfter, _jumpType);
|
||||
if (m_assembly.supportsRelativeJumps())
|
||||
{
|
||||
m_assembly.append(evmasm::AssemblyItem::jumpTo(evmasm::AssemblyItem(evmasm::PushTag, _labelId)));
|
||||
yulAssert(_jumpType == JumpType::Ordinary);
|
||||
m_assembly.adjustDeposit(_stackDiffAfter);
|
||||
}
|
||||
else
|
||||
{
|
||||
appendLabelReference(_labelId);
|
||||
appendJump(_stackDiffAfter, _jumpType);
|
||||
}
|
||||
}
|
||||
|
||||
void EthAssemblyAdapter::appendJumpToIf(LabelID _labelId, JumpType _jumpType)
|
||||
{
|
||||
appendLabelReference(_labelId);
|
||||
appendJumpInstruction(evmasm::Instruction::JUMPI, _jumpType);
|
||||
if (m_assembly.supportsRelativeJumps())
|
||||
{
|
||||
m_assembly.append(evmasm::AssemblyItem::conditionalJumpTo(evmasm::AssemblyItem(evmasm::PushTag, _labelId)));
|
||||
yulAssert(_jumpType == JumpType::Ordinary);
|
||||
}
|
||||
else
|
||||
{
|
||||
appendLabelReference(_labelId);
|
||||
appendJumpInstruction(evmasm::Instruction::JUMPI, _jumpType);
|
||||
}
|
||||
}
|
||||
|
||||
void EthAssemblyAdapter::appendAssemblySize()
|
||||
|
@ -267,7 +267,7 @@ BOOST_AUTO_TEST_CASE(immutables_and_its_source_maps)
|
||||
|
||||
checkCompilation(assembly);
|
||||
|
||||
string const sourceMappings = AssemblyItem::computeSourceMapping(assembly.items(), indices);
|
||||
string const sourceMappings = AssemblyItem::computeSourceMapping(assembly.codeSections().at(0).items, indices);
|
||||
auto const numberOfMappings = std::count(sourceMappings.begin(), sourceMappings.end(), ';');
|
||||
|
||||
LinkerObject const& obj = assembly.assemble();
|
||||
|
@ -1296,7 +1296,7 @@ BOOST_AUTO_TEST_CASE(jumpdest_removal_subassemblies)
|
||||
u256(8)
|
||||
};
|
||||
BOOST_CHECK_EQUAL_COLLECTIONS(
|
||||
main.items().begin(), main.items().end(),
|
||||
main.codeSections().at(0).items.begin(),main.codeSections().at(0).items.end(),
|
||||
expectationMain.begin(), expectationMain.end()
|
||||
);
|
||||
|
||||
@ -1304,7 +1304,7 @@ BOOST_AUTO_TEST_CASE(jumpdest_removal_subassemblies)
|
||||
u256(1), t1.tag(), u256(2), Instruction::JUMP, t4.tag(), u256(7), t4.pushTag(), Instruction::JUMP
|
||||
};
|
||||
BOOST_CHECK_EQUAL_COLLECTIONS(
|
||||
sub->items().begin(), sub->items().end(),
|
||||
sub->codeSections().at(0).items.begin(), sub->codeSections().at(0).items.end(),
|
||||
expectationSub.begin(), expectationSub.end()
|
||||
);
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ evmasm::AssemblyItems compileContract(std::shared_ptr<CharStream> _sourceCode)
|
||||
);
|
||||
compiler.compileContract(*contract, map<ContractDefinition const*, shared_ptr<Compiler const>>{}, bytes());
|
||||
|
||||
return compiler.runtimeAssembly().items();
|
||||
return compiler.runtimeAssembly().codeSections().at(0).items;
|
||||
}
|
||||
BOOST_FAIL("No contract found in source.");
|
||||
return AssemblyItems();
|
||||
|
@ -444,6 +444,9 @@ u256 EVMInstructionInterpreter::eval(
|
||||
case Instruction::CALLF:
|
||||
case Instruction::RETF:
|
||||
case Instruction::JUMPF:
|
||||
case Instruction::RJUMP:
|
||||
case Instruction::RJUMPI:
|
||||
case Instruction::RJUMPV:
|
||||
{
|
||||
yulAssert(false, "");
|
||||
return 0;
|
||||
|
Loading…
Reference in New Issue
Block a user