@@ -1341,163 +1341,119 @@ LinkerObject const& Assembly::assembleLegacy() const
1341
1341
uint8_t dataRefPush = static_cast <uint8_t >(pushInstruction (bytesPerDataRef));
1342
1342
1343
1343
LinkerObject::CodeSectionLocation codeSectionLocation;
1344
+ codeSectionLocation.instructionLocations .reserve (items.size ());
1344
1345
codeSectionLocation.start = 0 ;
1345
- size_t assemblyItemIndex = 0 ;
1346
- auto assembleInstruction = [&](auto && _addInstruction) {
1347
- size_t start = ret.bytecode .size ();
1348
- _addInstruction ();
1349
- size_t end = ret.bytecode .size ();
1350
- codeSectionLocation.instructionLocations .emplace_back (
1351
- LinkerObject::InstructionLocation{
1352
- .start = start,
1353
- .end = end,
1354
- .assemblyItemIndex = assemblyItemIndex
1355
- }
1356
- );
1357
- };
1358
- for (AssemblyItem const & item: items)
1346
+ for (auto const & [assemblyItemIndex, item]: items | ranges::views::enumerate)
1359
1347
{
1348
+ // collect instruction locations via side effects
1349
+ AddInstructionLocation addInstructionLocation (codeSectionLocation.instructionLocations , ret.bytecode , assemblyItemIndex);
1360
1350
// store position of the invalid jump destination
1361
1351
if (item.type () != Tag && m_tagPositionsInBytecode[0 ] == std::numeric_limits<size_t >::max ())
1362
1352
m_tagPositionsInBytecode[0 ] = ret.bytecode .size ();
1363
1353
1364
1354
switch (item.type ())
1365
1355
{
1366
1356
case Operation:
1367
- assembleInstruction ([&](){
1368
- ret.bytecode += assembleOperation (item);
1369
- });
1357
+ ret.bytecode += assembleOperation (item);
1370
1358
break ;
1371
1359
case Push:
1372
- assembleInstruction ([&](){
1373
- ret.bytecode += assemblePush (item);
1374
- });
1360
+ ret.bytecode += assemblePush (item);
1375
1361
break ;
1376
1362
case PushTag:
1377
- {
1378
- assembleInstruction ([&](){
1379
- ret.bytecode .push_back (tagPush);
1380
- tagRefs[ret.bytecode .size ()] = item.splitForeignPushTag ();
1381
- ret.bytecode .resize (ret.bytecode .size () + bytesPerTag);
1382
- });
1363
+ ret.bytecode .push_back (tagPush);
1364
+ tagRefs[ret.bytecode .size ()] = item.splitForeignPushTag ();
1365
+ ret.bytecode .resize (ret.bytecode .size () + bytesPerTag);
1383
1366
break ;
1384
- }
1385
1367
case PushData:
1386
- assembleInstruction ([&]() {
1387
- ret.bytecode .push_back (dataRefPush);
1388
- dataRefs.insert (std::make_pair (h256 (item.data ()), ret.bytecode .size ()));
1389
- ret.bytecode .resize (ret.bytecode .size () + bytesPerDataRef);
1390
- });
1368
+ ret.bytecode .push_back (dataRefPush);
1369
+ dataRefs.insert (std::make_pair (h256 (item.data ()), ret.bytecode .size ()));
1370
+ ret.bytecode .resize (ret.bytecode .size () + bytesPerDataRef);
1391
1371
break ;
1392
1372
case PushSub:
1393
- assembleInstruction ([&]() {
1394
- assertThrow (item.data () <= std::numeric_limits<size_t >::max (), AssemblyException, " " );
1395
- ret.bytecode .push_back (dataRefPush);
1396
- subRefs.insert (std::make_pair (static_cast <size_t >(item.data ()), ret.bytecode .size ()));
1397
- ret.bytecode .resize (ret.bytecode .size () + bytesPerDataRef);
1398
- });
1373
+ assertThrow (item.data () <= std::numeric_limits<size_t >::max (), AssemblyException, " " );
1374
+ ret.bytecode .push_back (dataRefPush);
1375
+ subRefs.insert (std::make_pair (static_cast <size_t >(item.data ()), ret.bytecode .size ()));
1376
+ ret.bytecode .resize (ret.bytecode .size () + bytesPerDataRef);
1399
1377
break ;
1400
1378
case PushSubSize:
1401
1379
{
1402
- assembleInstruction ([&](){
1403
- assertThrow (item.data () <= std::numeric_limits<size_t >::max (), AssemblyException, " " );
1404
- auto s = subAssemblyById (static_cast <size_t >(item.data ()))->assemble ().bytecode .size ();
1405
- item.setPushedValue (u256 (s));
1406
- unsigned b = std::max<unsigned >(1 , numberEncodingSize (s));
1407
- ret.bytecode .push_back (static_cast <uint8_t >(pushInstruction (b)));
1408
- ret.bytecode .resize (ret.bytecode .size () + b);
1409
- bytesRef byr (&ret.bytecode .back () + 1 - b, b);
1410
- toBigEndian (s, byr);
1411
- });
1380
+ assertThrow (item.data () <= std::numeric_limits<size_t >::max (), AssemblyException, " " );
1381
+ auto s = subAssemblyById (static_cast <size_t >(item.data ()))->assemble ().bytecode .size ();
1382
+ item.setPushedValue (u256 (s));
1383
+ unsigned b = std::max<unsigned >(1 , numberEncodingSize (s));
1384
+ ret.bytecode .push_back (static_cast <uint8_t >(pushInstruction (b)));
1385
+ ret.bytecode .resize (ret.bytecode .size () + b);
1386
+ bytesRef byr (&ret.bytecode .back () + 1 - b, b);
1387
+ toBigEndian (s, byr);
1412
1388
break ;
1413
1389
}
1414
1390
case PushProgramSize:
1415
- {
1416
- assembleInstruction ([&](){
1417
- ret.bytecode .push_back (dataRefPush);
1418
- sizeRefs.push_back (static_cast <unsigned >(ret.bytecode .size ()));
1419
- ret.bytecode .resize (ret.bytecode .size () + bytesPerDataRef);
1420
- });
1391
+ ret.bytecode .push_back (dataRefPush);
1392
+ sizeRefs.push_back (static_cast <unsigned >(ret.bytecode .size ()));
1393
+ ret.bytecode .resize (ret.bytecode .size () + bytesPerDataRef);
1421
1394
break ;
1422
- }
1423
1395
case PushLibraryAddress:
1424
1396
{
1425
- assembleInstruction ([&]() {
1426
- auto const [bytecode, linkRef] = assemblePushLibraryAddress (item, ret.bytecode .size ());
1427
- ret.bytecode += bytecode;
1428
- ret.linkReferences .insert (linkRef);
1429
- });
1397
+ auto const [bytecode, linkRef] = assemblePushLibraryAddress (item, ret.bytecode .size ());
1398
+ ret.bytecode += bytecode;
1399
+ ret.linkReferences .insert (linkRef);
1430
1400
break ;
1431
1401
}
1432
1402
case PushImmutable:
1433
- assembleInstruction ([&]() {
1434
- ret.bytecode .push_back (static_cast <uint8_t >(Instruction::PUSH32));
1435
- // Maps keccak back to the "identifier" std::string of that immutable.
1436
- ret.immutableReferences [item.data ()].first = m_immutables.at (item.data ());
1437
- // Record the bytecode offset of the PUSH32 argument.
1438
- ret.immutableReferences [item.data ()].second .emplace_back (ret.bytecode .size ());
1439
- // Advance bytecode by 32 bytes (default initialized).
1440
- ret.bytecode .resize (ret.bytecode .size () + 32 );
1441
- });
1403
+ ret.bytecode .push_back (static_cast <uint8_t >(Instruction::PUSH32));
1404
+ // Maps keccak back to the "identifier" std::string of that immutable.
1405
+ ret.immutableReferences [item.data ()].first = m_immutables.at (item.data ());
1406
+ // Record the bytecode offset of the PUSH32 argument.
1407
+ ret.immutableReferences [item.data ()].second .emplace_back (ret.bytecode .size ());
1408
+ // Advance bytecode by 32 bytes (default initialized).
1409
+ ret.bytecode .resize (ret.bytecode .size () + 32 );
1442
1410
break ;
1443
1411
case VerbatimBytecode:
1444
1412
ret.bytecode += assembleVerbatimBytecode (item);
1445
1413
break ;
1446
1414
case AssignImmutable:
1447
1415
{
1416
+ // this decomposes into multiple evm instructions, so we manually call emit on `addInstructionLocation`
1448
1417
// Expect 2 elements on stack (source, dest_base)
1449
1418
auto const & offsets = immutableReferencesBySub[item.data ()].second ;
1450
1419
for (size_t i = 0 ; i < offsets.size (); ++i)
1451
1420
{
1452
1421
if (i != offsets.size () - 1 )
1453
1422
{
1454
- assembleInstruction ([&]() {
1455
- ret.bytecode .push_back (uint8_t (Instruction::DUP2));
1456
- });
1457
- assembleInstruction ([&]() {
1458
- ret.bytecode .push_back (uint8_t (Instruction::DUP2));
1459
- });
1423
+ ret.bytecode .push_back (static_cast <uint8_t >(Instruction::DUP2));
1424
+ addInstructionLocation.emit ();
1425
+ ret.bytecode .push_back (static_cast <uint8_t >(Instruction::DUP2));
1426
+ addInstructionLocation.emit ();
1460
1427
}
1461
- assembleInstruction ([&]() {
1462
- // TODO: should we make use of the constant optimizer methods for pushing the offsets?
1463
- bytes offsetBytes = toCompactBigEndian (u256 (offsets[i]));
1464
- ret.bytecode .push_back (static_cast <uint8_t >(pushInstruction (static_cast <unsigned >(offsetBytes.size ()))));
1465
- ret.bytecode += offsetBytes;
1466
- });
1467
- assembleInstruction ([&]() {
1468
- ret.bytecode .push_back (uint8_t (Instruction::ADD));
1469
- });
1470
- assembleInstruction ([&]() {
1471
- ret.bytecode .push_back (uint8_t (Instruction::MSTORE));
1472
- });
1428
+ // TODO: should we make use of the constant optimizer methods for pushing the offsets?
1429
+ bytes offsetBytes = toCompactBigEndian (u256 (offsets[i]));
1430
+ ret.bytecode .push_back (static_cast <uint8_t >(pushInstruction (static_cast <unsigned >(offsetBytes.size ()))));
1431
+ ret.bytecode += offsetBytes;
1432
+ addInstructionLocation.emit ();
1433
+ ret.bytecode .push_back (static_cast <uint8_t >(Instruction::ADD));
1434
+ addInstructionLocation.emit ();
1435
+ ret.bytecode .push_back (static_cast <uint8_t >(Instruction::MSTORE));
1436
+ // no emit needed here, it's taken care of by the destructor of addInstructionLocation
1473
1437
}
1474
1438
if (offsets.empty ())
1475
1439
{
1476
- assembleInstruction ([&]() {
1477
- ret.bytecode .push_back (uint8_t (Instruction::POP));
1478
- });
1479
- assembleInstruction ([&]() {
1480
- ret.bytecode .push_back (uint8_t (Instruction::POP));
1481
- });
1440
+ ret.bytecode .push_back (static_cast <uint8_t >(Instruction::POP));
1441
+ addInstructionLocation.emit ();
1442
+ ret.bytecode .push_back (static_cast <uint8_t >(Instruction::POP));
1443
+ // no emit needed here, it's taken care of by the destructor of addInstructionLocation
1482
1444
}
1483
1445
immutableReferencesBySub.erase (item.data ());
1484
1446
break ;
1485
1447
}
1486
1448
case PushDeployTimeAddress:
1487
- assembleInstruction ([&]() {
1488
- ret.bytecode += assemblePushDeployTimeAddress ();
1489
- });
1449
+ ret.bytecode += assemblePushDeployTimeAddress ();
1490
1450
break ;
1491
1451
case Tag:
1492
- assembleInstruction ([&](){
1493
- ret.bytecode += assembleTag (item, ret.bytecode .size (), true );
1494
- });
1452
+ ret.bytecode += assembleTag (item, ret.bytecode .size (), true );
1495
1453
break ;
1496
1454
default :
1497
1455
solAssert (false , " Unexpected opcode while assembling." );
1498
1456
}
1499
-
1500
- ++assemblyItemIndex;
1501
1457
}
1502
1458
1503
1459
codeSectionLocation.end = ret.bytecode .size ();
0 commit comments