31
31
#include < libevmasm/ConstantOptimiser.h>
32
32
#include < libevmasm/GasMeter.h>
33
33
34
+ #include < libsolutil/JSON.h>
35
+
34
36
#include < liblangutil/Exceptions.h>
35
37
36
38
#include < json/json.h>
@@ -227,6 +229,219 @@ string Assembly::toStringInHex(u256 _value)
227
229
return hexStr.str ();
228
230
}
229
231
232
+ AssemblyItem Assembly::assemblyItemFromJSON (Json::Value const & _json, Assembly& _assembly)
233
+ {
234
+ std::string name = _json[" name" ].isString () ? _json[" name" ].asString () : " " ;
235
+ int begin = _json[" begin" ].isInt () ? _json[" begin" ].asInt () : -1 ;
236
+ int end = _json[" end" ].isInt () ? _json[" end" ].asInt () : -1 ;
237
+ std::string value = _json[" value" ].isString () ? _json[" value" ].asString () : " " ;
238
+ std::string jumpType = _json[" jumpType" ].isString () ? _json[" jumpType" ].asString () : " " ;
239
+ solAssert (!name.empty (), " " );
240
+
241
+ auto updateUsedTags = [&](u256 const & data) {
242
+ auto tag = static_cast <unsigned >(data);
243
+ if (_assembly.m_usedTags <= tag)
244
+ _assembly.m_usedTags = tag + 1 ;
245
+ };
246
+
247
+ auto updateImmutables = [&](u256 const & data) -> h256 {
248
+ std::string value = toStringInHex (data);
249
+ h256 hash (util::keccak256 (value));
250
+ _assembly.m_immutables [hash] = value;
251
+ return hash;
252
+ };
253
+
254
+ auto updateLibraries = [&](string const & value) -> h256 {
255
+ h256 hash (util::keccak256 (value));
256
+ _assembly.m_libraries [hash] = value;
257
+ return hash;
258
+ };
259
+
260
+ SourceLocation location;
261
+ location.start = begin;
262
+ location.end = end;
263
+ if (c_instructions.find (name) != c_instructions.end ())
264
+ {
265
+ AssemblyItem item{c_instructions.at (name), location};
266
+ if (!value.empty ())
267
+ item.setJumpTypeFromString (value);
268
+ return item;
269
+ }
270
+ else
271
+ {
272
+ u256 data;
273
+ if (name == " PUSH" )
274
+ {
275
+ if (!value.empty ())
276
+ data = u256 (" 0x" + value);
277
+ AssemblyItem item{AssemblyItemType::Push, data, location};
278
+ if (!jumpType.empty ())
279
+ item.setJumpTypeFromString (jumpType);
280
+ return item;
281
+ }
282
+ else if (name == " PUSH tag" )
283
+ {
284
+ if (!value.empty ())
285
+ data = u256 (" 0x" + value);
286
+ updateUsedTags (data);
287
+ return {AssemblyItemType::PushString, data, location};
288
+ }
289
+ else if (name == " PUSH [ErrorTag]" )
290
+ return {AssemblyItemType::PushTag, data, location};
291
+ else if (name == " PUSH [tag]" )
292
+ {
293
+ if (!value.empty ())
294
+ data = u256 (value);
295
+ updateUsedTags (data);
296
+ return {AssemblyItemType::PushTag, data, location};
297
+ }
298
+ else if (name == " PUSH [$]" )
299
+ {
300
+ if (!value.empty ())
301
+ data = u256 (" 0x" + value);
302
+ return {AssemblyItemType::PushSub, data, location};
303
+ }
304
+ else if (name == " PUSH #[$]" )
305
+ {
306
+ if (!value.empty ())
307
+ data = u256 (" 0x" + value);
308
+ return {AssemblyItemType::PushSubSize, data, location};
309
+ }
310
+ else if (name == " PUSHSIZE" )
311
+ return {AssemblyItemType::PushProgramSize, data, location};
312
+ else if (name == " PUSHLIB" )
313
+ {
314
+ h256 hash = updateLibraries (value);
315
+ return {AssemblyItemType::PushLibraryAddress, hash, location};
316
+ }
317
+ else if (name == " PUSHDEPLOYADDRESS" )
318
+ return {AssemblyItemType::PushDeployTimeAddress, data, location};
319
+ else if (name == " PUSHIMMUTABLE" )
320
+ {
321
+ if (!value.empty ())
322
+ data = u256 (" 0x" + value);
323
+ h256 hash = updateImmutables (data);
324
+ return {AssemblyItemType::PushImmutable, hash, location};
325
+ }
326
+ else if (name == " ASSIGNIMMUTABLE" )
327
+ {
328
+ if (!value.empty ())
329
+ data = u256 (" 0x" + value);
330
+ h256 hash = updateImmutables (data);
331
+ return {AssemblyItemType::AssignImmutable, hash, location};
332
+ }
333
+ else if (name == " tag" )
334
+ {
335
+ if (!value.empty ())
336
+ data = u256 (value);
337
+ return {AssemblyItemType::Tag, data, location};
338
+ }
339
+ else if (name == " PUSH data" )
340
+ {
341
+ if (!value.empty ())
342
+ data = u256 (" 0x" + value);
343
+ return {AssemblyItemType::PushData, data, location};
344
+ }
345
+ else if (name == " VERBATIM" )
346
+ {
347
+ if (!value.empty ())
348
+ data = u256 (" 0x" + value);
349
+ return {AssemblyItemType::VerbatimBytecode, data, location};
350
+ }
351
+ else
352
+ assertThrow (false , InvalidOpcode, " " );
353
+ }
354
+ }
355
+
356
+ vector<Json::Value> Assembly::assemblyItemAsJSON (AssemblyItem const & _item, int _sourceIndex) const
357
+ {
358
+ vector<Json::Value> result;
359
+
360
+ switch (_item.type ())
361
+ {
362
+ case Operation:
363
+ result.emplace_back (createJsonValue (
364
+ instructionInfo (_item.instruction ()).name ,
365
+ _sourceIndex,
366
+ _item.location ().start ,
367
+ _item.location ().end ,
368
+ _item.getJumpTypeAsString ()));
369
+ break ;
370
+ case Push:
371
+ result.emplace_back (createJsonValue (
372
+ " PUSH" ,
373
+ _sourceIndex,
374
+ _item.location ().start ,
375
+ _item.location ().end ,
376
+ toStringInHex (_item.data ()),
377
+ _item.getJumpTypeAsString ()));
378
+ break ;
379
+ case PushString:
380
+ result.emplace_back (createJsonValue (
381
+ " PUSH tag" , _sourceIndex, _item.location ().start , _item.location ().end , m_strings.at (h256 (_item.data ()))));
382
+ break ;
383
+ case PushTag:
384
+ if (_item.data () == 0 )
385
+ result.emplace_back (
386
+ createJsonValue (" PUSH [ErrorTag]" , _sourceIndex, _item.location ().start , _item.location ().end , " " ));
387
+ else
388
+ result.emplace_back (createJsonValue (
389
+ " PUSH [tag]" , _sourceIndex, _item.location ().start , _item.location ().end , toString (_item.data ())));
390
+ break ;
391
+ case PushSub:
392
+ result.emplace_back (createJsonValue (
393
+ " PUSH [$]" , _sourceIndex, _item.location ().start , _item.location ().end , toString (h256 (_item.data ()))));
394
+ break ;
395
+ case PushSubSize:
396
+ result.emplace_back (createJsonValue (
397
+ " PUSH #[$]" , _sourceIndex, _item.location ().start , _item.location ().end , toString (h256 (_item.data ()))));
398
+ break ;
399
+ case PushProgramSize:
400
+ result.emplace_back (createJsonValue (" PUSHSIZE" , _sourceIndex, _item.location ().start , _item.location ().end ));
401
+ break ;
402
+ case PushLibraryAddress:
403
+ result.emplace_back (createJsonValue (
404
+ " PUSHLIB" , _sourceIndex, _item.location ().start , _item.location ().end , m_libraries.at (h256 (_item.data ()))));
405
+ break ;
406
+ case PushDeployTimeAddress:
407
+ result.emplace_back (
408
+ createJsonValue (" PUSHDEPLOYADDRESS" , _sourceIndex, _item.location ().start , _item.location ().end ));
409
+ break ;
410
+ case PushImmutable:
411
+ result.emplace_back (createJsonValue (
412
+ " PUSHIMMUTABLE" ,
413
+ _sourceIndex,
414
+ _item.location ().start ,
415
+ _item.location ().end ,
416
+ m_immutables.at (h256 (_item.data ()))));
417
+ break ;
418
+ case AssignImmutable:
419
+ result.emplace_back (createJsonValue (
420
+ " ASSIGNIMMUTABLE" ,
421
+ _sourceIndex,
422
+ _item.location ().start ,
423
+ _item.location ().end ,
424
+ m_immutables.at (h256 (_item.data ()))));
425
+ break ;
426
+ case Tag:
427
+ result.emplace_back (
428
+ createJsonValue (" tag" , _sourceIndex, _item.location ().start , _item.location ().end , toString (_item.data ())));
429
+ result.emplace_back (createJsonValue (" JUMPDEST" , _sourceIndex, _item.location ().start , _item.location ().end ));
430
+ break ;
431
+ case PushData:
432
+ result.emplace_back (createJsonValue (
433
+ " PUSH data" , _sourceIndex, _item.location ().start , _item.location ().end , toStringInHex (_item.data ())));
434
+ break ;
435
+ case VerbatimBytecode:
436
+ result.emplace_back (createJsonValue (
437
+ " VERBATIM" , _sourceIndex, _item.location ().start , _item.location ().end , toHex (_item.verbatimData ())));
438
+ break ;
439
+ default :
440
+ assertThrow (false , InvalidOpcode, " " );
441
+ }
442
+ return result;
443
+ }
444
+
230
445
Json::Value Assembly::assemblyJSON (map<string, unsigned > const & _sourceIndices) const
231
446
{
232
447
Json::Value root;
@@ -242,89 +457,8 @@ Json::Value Assembly::assemblyJSON(map<string, unsigned> const& _sourceIndices)
242
457
sourceIndex = static_cast <int >(iter->second );
243
458
}
244
459
245
- switch (i.type ())
246
- {
247
- case Operation:
248
- collection.append (
249
- createJsonValue (
250
- instructionInfo (i.instruction ()).name ,
251
- sourceIndex,
252
- i.location ().start ,
253
- i.location ().end ,
254
- i.getJumpTypeAsString ())
255
- );
256
- break ;
257
- case Push:
258
- collection.append (
259
- createJsonValue (" PUSH" , sourceIndex, i.location ().start , i.location ().end , toStringInHex (i.data ()), i.getJumpTypeAsString ()));
260
- break ;
261
- case PushString:
262
- collection.append (
263
- createJsonValue (" PUSH tag" , sourceIndex, i.location ().start , i.location ().end , m_strings.at (h256 (i.data ()))));
264
- break ;
265
- case PushTag:
266
- if (i.data () == 0 )
267
- collection.append (
268
- createJsonValue (" PUSH [ErrorTag]" , sourceIndex, i.location ().start , i.location ().end , " " ));
269
- else
270
- collection.append (
271
- createJsonValue (" PUSH [tag]" , sourceIndex, i.location ().start , i.location ().end , toString (i.data ())));
272
- break ;
273
- case PushSub:
274
- collection.append (
275
- createJsonValue (" PUSH [$]" , sourceIndex, i.location ().start , i.location ().end , toString (h256 (i.data ()))));
276
- break ;
277
- case PushSubSize:
278
- collection.append (
279
- createJsonValue (" PUSH #[$]" , sourceIndex, i.location ().start , i.location ().end , toString (h256 (i.data ()))));
280
- break ;
281
- case PushProgramSize:
282
- collection.append (
283
- createJsonValue (" PUSHSIZE" , sourceIndex, i.location ().start , i.location ().end ));
284
- break ;
285
- case PushLibraryAddress:
286
- collection.append (
287
- createJsonValue (" PUSHLIB" , sourceIndex, i.location ().start , i.location ().end , m_libraries.at (h256 (i.data ())))
288
- );
289
- break ;
290
- case PushDeployTimeAddress:
291
- collection.append (
292
- createJsonValue (" PUSHDEPLOYADDRESS" , sourceIndex, i.location ().start , i.location ().end )
293
- );
294
- break ;
295
- case PushImmutable:
296
- collection.append (createJsonValue (
297
- " PUSHIMMUTABLE" ,
298
- sourceIndex,
299
- i.location ().start ,
300
- i.location ().end ,
301
- m_immutables.at (h256 (i.data ()))
302
- ));
303
- break ;
304
- case AssignImmutable:
305
- collection.append (createJsonValue (
306
- " ASSIGNIMMUTABLE" ,
307
- sourceIndex,
308
- i.location ().start ,
309
- i.location ().end ,
310
- m_immutables.at (h256 (i.data ()))
311
- ));
312
- break ;
313
- case Tag:
314
- collection.append (
315
- createJsonValue (" tag" , sourceIndex, i.location ().start , i.location ().end , toString (i.data ())));
316
- collection.append (
317
- createJsonValue (" JUMPDEST" , sourceIndex, i.location ().start , i.location ().end ));
318
- break ;
319
- case PushData:
320
- collection.append (createJsonValue (" PUSH data" , sourceIndex, i.location ().start , i.location ().end , toStringInHex (i.data ())));
321
- break ;
322
- case VerbatimBytecode:
323
- collection.append (createJsonValue (" VERBATIM" , sourceIndex, i.location ().start , i.location ().end , toHex (i.verbatimData ())));
324
- break ;
325
- default :
326
- assertThrow (false , InvalidOpcode, " " );
327
- }
460
+ for (Json::Value const & item: assemblyItemAsJSON (i, sourceIndex))
461
+ collection.append (item);
328
462
}
329
463
330
464
if (!m_data.empty () || !m_subs.empty ())
@@ -342,12 +476,59 @@ Json::Value Assembly::assemblyJSON(map<string, unsigned> const& _sourceIndices)
342
476
}
343
477
}
344
478
345
- if (m_auxiliaryData.size () > 0 )
479
+ if (! m_auxiliaryData.empty () )
346
480
root[" .auxdata" ] = toHex (m_auxiliaryData);
347
481
348
482
return root;
349
483
}
350
484
485
+ void Assembly::forEachJSONAssemblyItem (Json::Value const & _code, Assembly& _assembly)
486
+ {
487
+ solAssert (_code.isArray (), " " );
488
+ for (auto it = _code.begin (); it != _code.end (); ++it)
489
+ {
490
+ AssemblyItem current = assemblyItemFromJSON (*it, _assembly);
491
+ _assembly.m_items .emplace_back (current);
492
+
493
+ auto nextIt = std::next (it);
494
+ if (nextIt != _code.end ())
495
+ {
496
+ AssemblyItem next = assemblyItemFromJSON (*nextIt, _assembly);
497
+ if (current.type () == AssemblyItemType::Tag &&
498
+ next.type () == AssemblyItemType::Operation && next.instruction () == Instruction::JUMPDEST)
499
+ ++it;
500
+ }
501
+ }
502
+ }
503
+
504
+ bool Assembly::loadFromAssemblyJSON (Json::Value const & _json, Assembly& _assembly)
505
+ {
506
+ solAssert (_json[" .code" ].isArray (), " " );
507
+ forEachJSONAssemblyItem (_json[" .code" ], _assembly);
508
+ Json::Value const & data = _json[" .data" ];
509
+ for (Json::ValueConstIterator itr = data.begin (); itr != data.end (); itr++)
510
+ {
511
+ solAssert (itr.key ().isString (), " " );
512
+ std::string key = itr.key ().asString ();
513
+ Json::Value const & code = data[key];
514
+ if (code.isString ())
515
+ _assembly.m_data [h256 (fromHex (key))] = fromHex (code.asString ());
516
+ else
517
+ {
518
+ shared_ptr<Assembly> subassembly = make_shared<Assembly>();
519
+ loadFromAssemblyJSON (code, *subassembly);
520
+ Json::Value const & auxdata = data[key][" .auxdata" ];
521
+ if (auxdata.isString ())
522
+ {
523
+ solAssert (subassembly->m_auxiliaryData .empty (), " " );
524
+ subassembly->m_auxiliaryData = fromHex (auxdata.asString ());
525
+ }
526
+ _assembly.m_subs .emplace_back (subassembly);
527
+ }
528
+ }
529
+ return true ;
530
+ }
531
+
351
532
AssemblyItem Assembly::namedTag (string const & _name, size_t _params, size_t _returns, optional<uint64_t > _sourceID)
352
533
{
353
534
assertThrow (!_name.empty (), AssemblyException, " Empty named tag." );
@@ -402,7 +583,6 @@ Assembly& Assembly::optimise(bool _enable, EVMVersion _evmVersion, bool _isCreat
402
583
return *this ;
403
584
}
404
585
405
-
406
586
Assembly& Assembly::optimise (OptimiserSettings const & _settings)
407
587
{
408
588
optimiseInternal (_settings, {});
0 commit comments