Skip to content

Commit 93aa5ff

Browse files
committed
Refactor legacy assemble to also use RAII instruction location construction
1 parent b7332f6 commit 93aa5ff

File tree

1 file changed

+57
-101
lines changed

1 file changed

+57
-101
lines changed

libevmasm/Assembly.cpp

Lines changed: 57 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -1331,163 +1331,119 @@ LinkerObject const& Assembly::assembleLegacy() const
13311331
uint8_t dataRefPush = static_cast<uint8_t>(pushInstruction(bytesPerDataRef));
13321332

13331333
LinkerObject::CodeSectionLocation codeSectionLocation;
1334+
codeSectionLocation.instructionLocations.reserve(items.size());
13341335
codeSectionLocation.start = 0;
1335-
size_t assemblyItemIndex = 0;
1336-
auto assembleInstruction = [&](auto&& _addInstruction) {
1337-
size_t start = ret.bytecode.size();
1338-
_addInstruction();
1339-
size_t end = ret.bytecode.size();
1340-
codeSectionLocation.instructionLocations.emplace_back(
1341-
LinkerObject::InstructionLocation{
1342-
.start = start,
1343-
.end = end,
1344-
.assemblyItemIndex = assemblyItemIndex
1345-
}
1346-
);
1347-
};
1348-
for (AssemblyItem const& item: items)
1336+
for (auto const& [assemblyItemIndex, item]: items | ranges::views::enumerate)
13491337
{
1338+
// collect instruction locations via side effects
1339+
AddInstructionLocation addInstructionLocation(codeSectionLocation.instructionLocations, ret.bytecode, assemblyItemIndex);
13501340
// store position of the invalid jump destination
13511341
if (item.type() != Tag && m_tagPositionsInBytecode[0] == std::numeric_limits<size_t>::max())
13521342
m_tagPositionsInBytecode[0] = ret.bytecode.size();
13531343

13541344
switch (item.type())
13551345
{
13561346
case Operation:
1357-
assembleInstruction([&](){
1358-
ret.bytecode += assembleOperation(item);
1359-
});
1347+
ret.bytecode += assembleOperation(item);
13601348
break;
13611349
case Push:
1362-
assembleInstruction([&](){
1363-
ret.bytecode += assemblePush(item);
1364-
});
1350+
ret.bytecode += assemblePush(item);
13651351
break;
13661352
case PushTag:
1367-
{
1368-
assembleInstruction([&](){
1369-
ret.bytecode.push_back(tagPush);
1370-
tagRefs[ret.bytecode.size()] = item.splitForeignPushTag();
1371-
ret.bytecode.resize(ret.bytecode.size() + bytesPerTag);
1372-
});
1353+
ret.bytecode.push_back(tagPush);
1354+
tagRefs[ret.bytecode.size()] = item.splitForeignPushTag();
1355+
ret.bytecode.resize(ret.bytecode.size() + bytesPerTag);
13731356
break;
1374-
}
13751357
case PushData:
1376-
assembleInstruction([&]() {
1377-
ret.bytecode.push_back(dataRefPush);
1378-
dataRefs.insert(std::make_pair(h256(item.data()), ret.bytecode.size()));
1379-
ret.bytecode.resize(ret.bytecode.size() + bytesPerDataRef);
1380-
});
1358+
ret.bytecode.push_back(dataRefPush);
1359+
dataRefs.insert(std::make_pair(h256(item.data()), ret.bytecode.size()));
1360+
ret.bytecode.resize(ret.bytecode.size() + bytesPerDataRef);
13811361
break;
13821362
case PushSub:
1383-
assembleInstruction([&]() {
1384-
assertThrow(item.data() <= std::numeric_limits<size_t>::max(), AssemblyException, "");
1385-
ret.bytecode.push_back(dataRefPush);
1386-
subRefs.insert(std::make_pair(static_cast<size_t>(item.data()), ret.bytecode.size()));
1387-
ret.bytecode.resize(ret.bytecode.size() + bytesPerDataRef);
1388-
});
1363+
assertThrow(item.data() <= std::numeric_limits<size_t>::max(), AssemblyException, "");
1364+
ret.bytecode.push_back(dataRefPush);
1365+
subRefs.insert(std::make_pair(static_cast<size_t>(item.data()), ret.bytecode.size()));
1366+
ret.bytecode.resize(ret.bytecode.size() + bytesPerDataRef);
13891367
break;
13901368
case PushSubSize:
13911369
{
1392-
assembleInstruction([&](){
1393-
assertThrow(item.data() <= std::numeric_limits<size_t>::max(), AssemblyException, "");
1394-
auto s = subAssemblyById(static_cast<size_t>(item.data()))->assemble().bytecode.size();
1395-
item.setPushedValue(u256(s));
1396-
unsigned b = std::max<unsigned>(1, numberEncodingSize(s));
1397-
ret.bytecode.push_back(static_cast<uint8_t>(pushInstruction(b)));
1398-
ret.bytecode.resize(ret.bytecode.size() + b);
1399-
bytesRef byr(&ret.bytecode.back() + 1 - b, b);
1400-
toBigEndian(s, byr);
1401-
});
1370+
assertThrow(item.data() <= std::numeric_limits<size_t>::max(), AssemblyException, "");
1371+
auto s = subAssemblyById(static_cast<size_t>(item.data()))->assemble().bytecode.size();
1372+
item.setPushedValue(u256(s));
1373+
unsigned b = std::max<unsigned>(1, numberEncodingSize(s));
1374+
ret.bytecode.push_back(static_cast<uint8_t>(pushInstruction(b)));
1375+
ret.bytecode.resize(ret.bytecode.size() + b);
1376+
bytesRef byr(&ret.bytecode.back() + 1 - b, b);
1377+
toBigEndian(s, byr);
14021378
break;
14031379
}
14041380
case PushProgramSize:
1405-
{
1406-
assembleInstruction([&](){
1407-
ret.bytecode.push_back(dataRefPush);
1408-
sizeRefs.push_back(static_cast<unsigned>(ret.bytecode.size()));
1409-
ret.bytecode.resize(ret.bytecode.size() + bytesPerDataRef);
1410-
});
1381+
ret.bytecode.push_back(dataRefPush);
1382+
sizeRefs.push_back(static_cast<unsigned>(ret.bytecode.size()));
1383+
ret.bytecode.resize(ret.bytecode.size() + bytesPerDataRef);
14111384
break;
1412-
}
14131385
case PushLibraryAddress:
14141386
{
1415-
assembleInstruction([&]() {
1416-
auto const [bytecode, linkRef] = assemblePushLibraryAddress(item, ret.bytecode.size());
1417-
ret.bytecode += bytecode;
1418-
ret.linkReferences.insert(linkRef);
1419-
});
1387+
auto const [bytecode, linkRef] = assemblePushLibraryAddress(item, ret.bytecode.size());
1388+
ret.bytecode += bytecode;
1389+
ret.linkReferences.insert(linkRef);
14201390
break;
14211391
}
14221392
case PushImmutable:
1423-
assembleInstruction([&]() {
1424-
ret.bytecode.push_back(static_cast<uint8_t>(Instruction::PUSH32));
1425-
// Maps keccak back to the "identifier" std::string of that immutable.
1426-
ret.immutableReferences[item.data()].first = m_immutables.at(item.data());
1427-
// Record the bytecode offset of the PUSH32 argument.
1428-
ret.immutableReferences[item.data()].second.emplace_back(ret.bytecode.size());
1429-
// Advance bytecode by 32 bytes (default initialized).
1430-
ret.bytecode.resize(ret.bytecode.size() + 32);
1431-
});
1393+
ret.bytecode.push_back(static_cast<uint8_t>(Instruction::PUSH32));
1394+
// Maps keccak back to the "identifier" std::string of that immutable.
1395+
ret.immutableReferences[item.data()].first = m_immutables.at(item.data());
1396+
// Record the bytecode offset of the PUSH32 argument.
1397+
ret.immutableReferences[item.data()].second.emplace_back(ret.bytecode.size());
1398+
// Advance bytecode by 32 bytes (default initialized).
1399+
ret.bytecode.resize(ret.bytecode.size() + 32);
14321400
break;
14331401
case VerbatimBytecode:
14341402
ret.bytecode += assembleVerbatimBytecode(item);
14351403
break;
14361404
case AssignImmutable:
14371405
{
1406+
// this decomposes into multiple evm instructions, so we manually call emit on `addInstructionLocation`
14381407
// Expect 2 elements on stack (source, dest_base)
14391408
auto const& offsets = immutableReferencesBySub[item.data()].second;
14401409
for (size_t i = 0; i < offsets.size(); ++i)
14411410
{
14421411
if (i != offsets.size() - 1)
14431412
{
1444-
assembleInstruction([&]() {
1445-
ret.bytecode.push_back(uint8_t(Instruction::DUP2));
1446-
});
1447-
assembleInstruction([&]() {
1448-
ret.bytecode.push_back(uint8_t(Instruction::DUP2));
1449-
});
1413+
ret.bytecode.push_back(static_cast<uint8_t>(Instruction::DUP2));
1414+
addInstructionLocation.emit();
1415+
ret.bytecode.push_back(static_cast<uint8_t>(Instruction::DUP2));
1416+
addInstructionLocation.emit();
14501417
}
1451-
assembleInstruction([&]() {
1452-
// TODO: should we make use of the constant optimizer methods for pushing the offsets?
1453-
bytes offsetBytes = toCompactBigEndian(u256(offsets[i]));
1454-
ret.bytecode.push_back(static_cast<uint8_t>(pushInstruction(static_cast<unsigned>(offsetBytes.size()))));
1455-
ret.bytecode += offsetBytes;
1456-
});
1457-
assembleInstruction([&]() {
1458-
ret.bytecode.push_back(uint8_t(Instruction::ADD));
1459-
});
1460-
assembleInstruction([&]() {
1461-
ret.bytecode.push_back(uint8_t(Instruction::MSTORE));
1462-
});
1418+
// TODO: should we make use of the constant optimizer methods for pushing the offsets?
1419+
bytes offsetBytes = toCompactBigEndian(u256(offsets[i]));
1420+
ret.bytecode.push_back(static_cast<uint8_t>(pushInstruction(static_cast<unsigned>(offsetBytes.size()))));
1421+
ret.bytecode += offsetBytes;
1422+
addInstructionLocation.emit();
1423+
ret.bytecode.push_back(static_cast<uint8_t>(Instruction::ADD));
1424+
addInstructionLocation.emit();
1425+
ret.bytecode.push_back(static_cast<uint8_t>(Instruction::MSTORE));
1426+
// no emit needed here, it's taken care of by the destructor of addInstructionLocation
14631427
}
14641428
if (offsets.empty())
14651429
{
1466-
assembleInstruction([&]() {
1467-
ret.bytecode.push_back(uint8_t(Instruction::POP));
1468-
});
1469-
assembleInstruction([&]() {
1470-
ret.bytecode.push_back(uint8_t(Instruction::POP));
1471-
});
1430+
ret.bytecode.push_back(static_cast<uint8_t>(Instruction::POP));
1431+
addInstructionLocation.emit();
1432+
ret.bytecode.push_back(static_cast<uint8_t>(Instruction::POP));
1433+
// no emit needed here, it's taken care of by the destructor of addInstructionLocation
14721434
}
14731435
immutableReferencesBySub.erase(item.data());
14741436
break;
14751437
}
14761438
case PushDeployTimeAddress:
1477-
assembleInstruction([&]() {
1478-
ret.bytecode += assemblePushDeployTimeAddress();
1479-
});
1439+
ret.bytecode += assemblePushDeployTimeAddress();
14801440
break;
14811441
case Tag:
1482-
assembleInstruction([&](){
1483-
ret.bytecode += assembleTag(item, ret.bytecode.size(), true);
1484-
});
1442+
ret.bytecode += assembleTag(item, ret.bytecode.size(), true);
14851443
break;
14861444
default:
14871445
solAssert(false, "Unexpected opcode while assembling.");
14881446
}
1489-
1490-
++assemblyItemIndex;
14911447
}
14921448

14931449
codeSectionLocation.end = ret.bytecode.size();

0 commit comments

Comments
 (0)