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