@@ -1331,163 +1331,119 @@ LinkerObject const& Assembly::assembleLegacy() const
1331
1331
uint8_t dataRefPush = static_cast <uint8_t >(pushInstruction (bytesPerDataRef));
1332
1332
1333
1333
LinkerObject::CodeSectionLocation codeSectionLocation;
1334
+ codeSectionLocation.instructionLocations .reserve (items.size ());
1334
1335
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)
1349
1337
{
1338
+ // collect instruction locations via side effects
1339
+ AddInstructionLocation addInstructionLocation (codeSectionLocation.instructionLocations , ret.bytecode , assemblyItemIndex);
1350
1340
// store position of the invalid jump destination
1351
1341
if (item.type () != Tag && m_tagPositionsInBytecode[0 ] == std::numeric_limits<size_t >::max ())
1352
1342
m_tagPositionsInBytecode[0 ] = ret.bytecode .size ();
1353
1343
1354
1344
switch (item.type ())
1355
1345
{
1356
1346
case Operation:
1357
- assembleInstruction ([&](){
1358
- ret.bytecode += assembleOperation (item);
1359
- });
1347
+ ret.bytecode += assembleOperation (item);
1360
1348
break ;
1361
1349
case Push:
1362
- assembleInstruction ([&](){
1363
- ret.bytecode += assemblePush (item);
1364
- });
1350
+ ret.bytecode += assemblePush (item);
1365
1351
break ;
1366
1352
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);
1373
1356
break ;
1374
- }
1375
1357
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);
1381
1361
break ;
1382
1362
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);
1389
1367
break ;
1390
1368
case PushSubSize:
1391
1369
{
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);
1402
1378
break ;
1403
1379
}
1404
1380
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);
1411
1384
break ;
1412
- }
1413
1385
case PushLibraryAddress:
1414
1386
{
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);
1420
1390
break ;
1421
1391
}
1422
1392
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 );
1432
1400
break ;
1433
1401
case VerbatimBytecode:
1434
1402
ret.bytecode += assembleVerbatimBytecode (item);
1435
1403
break ;
1436
1404
case AssignImmutable:
1437
1405
{
1406
+ // this decomposes into multiple evm instructions, so we manually call emit on `addInstructionLocation`
1438
1407
// Expect 2 elements on stack (source, dest_base)
1439
1408
auto const & offsets = immutableReferencesBySub[item.data ()].second ;
1440
1409
for (size_t i = 0 ; i < offsets.size (); ++i)
1441
1410
{
1442
1411
if (i != offsets.size () - 1 )
1443
1412
{
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 ();
1450
1417
}
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
1463
1427
}
1464
1428
if (offsets.empty ())
1465
1429
{
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
1472
1434
}
1473
1435
immutableReferencesBySub.erase (item.data ());
1474
1436
break ;
1475
1437
}
1476
1438
case PushDeployTimeAddress:
1477
- assembleInstruction ([&]() {
1478
- ret.bytecode += assemblePushDeployTimeAddress ();
1479
- });
1439
+ ret.bytecode += assemblePushDeployTimeAddress ();
1480
1440
break ;
1481
1441
case Tag:
1482
- assembleInstruction ([&](){
1483
- ret.bytecode += assembleTag (item, ret.bytecode .size (), true );
1484
- });
1442
+ ret.bytecode += assembleTag (item, ret.bytecode .size (), true );
1485
1443
break ;
1486
1444
default :
1487
1445
solAssert (false , " Unexpected opcode while assembling." );
1488
1446
}
1489
-
1490
- ++assemblyItemIndex;
1491
1447
}
1492
1448
1493
1449
codeSectionLocation.end = ret.bytecode .size ();
0 commit comments