Skip to content

Commit 2e4ddd9

Browse files
committed
Add support for --import-asm-json.
1 parent b8eb2a0 commit 2e4ddd9

13 files changed

+605
-138
lines changed

Changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Compiler Features:
1212
* SMTChecker: Add constraints to better correlate ``address(this).balance`` and ``msg.value``.
1313
* SMTChecker: Support the ``value`` option for external function calls.
1414
* Commandline Interface: Disallowed the ``--experimental-via-ir`` option to be used with Standard Json, Assembler and Linker modes.
15+
* Commandline Interface: Adds alternative input mode ``--import-asm-json`` to import assembly json.
1516

1617

1718
Bugfixes:

libevmasm/Assembly.cpp

Lines changed: 260 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
#include <libevmasm/ConstantOptimiser.h>
3232
#include <libevmasm/GasMeter.h>
3333

34+
#include <libsolutil/JSON.h>
35+
3436
#include <liblangutil/Exceptions.h>
3537

3638
#include <json/json.h>
@@ -227,6 +229,216 @@ string Assembly::toStringInHex(u256 _value)
227229
return hexStr.str();
228230
}
229231

232+
AssemblyItem Assembly::loadItemFromJSON(Json::Value const& _json)
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+
int source = _json["source"].isInt() ? _json["source"].asInt() : -1;
238+
std::string value = _json["value"].isString() ? _json["value"].asString() : "";
239+
std::string jumpType = _json["jumpType"].isString() ? _json["jumpType"].asString() : "";
240+
solAssert(!name.empty(), "");
241+
242+
auto updateUsedTags = [&](u256 const& data) {
243+
auto tag = static_cast<unsigned>(data);
244+
if (this->m_usedTags <= tag)
245+
this->m_usedTags = tag + 1;
246+
};
247+
248+
auto updateImmutables = [&](string const& _immutableName) -> h256 {
249+
h256 hash(util::keccak256(value));
250+
this->m_immutables[hash] = _immutableName;
251+
return hash;
252+
};
253+
254+
auto updateLibraries = [&](string const& _libraryName) -> h256 {
255+
h256 hash(util::keccak256(_libraryName));
256+
this->m_libraries[hash] = _libraryName;
257+
return hash;
258+
};
259+
260+
SourceLocation location;
261+
location.start = begin;
262+
location.end = end;
263+
location.sourceIndex = source;
264+
if (c_instructions.find(name) != c_instructions.end())
265+
{
266+
AssemblyItem item{c_instructions.at(name), location};
267+
if (!value.empty())
268+
item.setJumpType(value);
269+
return item;
270+
}
271+
else
272+
{
273+
u256 data;
274+
if (name == "PUSH")
275+
{
276+
if (!value.empty())
277+
data = u256("0x" + value);
278+
AssemblyItem item{AssemblyItemType::Push, data, location};
279+
if (!jumpType.empty())
280+
item.setJumpType(jumpType);
281+
return item;
282+
}
283+
else if (name == "PUSH tag")
284+
{
285+
if (!value.empty())
286+
data = u256("0x" + value);
287+
updateUsedTags(data);
288+
return {AssemblyItemType::PushString, data, location};
289+
}
290+
else if (name == "PUSH [ErrorTag]")
291+
return {AssemblyItemType::PushTag, data, location};
292+
else if (name == "PUSH [tag]")
293+
{
294+
if (!value.empty())
295+
data = u256(value);
296+
updateUsedTags(data);
297+
return {AssemblyItemType::PushTag, data, location};
298+
}
299+
else if (name == "PUSH [$]")
300+
{
301+
if (!value.empty())
302+
data = u256("0x" + value);
303+
return {AssemblyItemType::PushSub, data, location};
304+
}
305+
else if (name == "PUSH #[$]")
306+
{
307+
if (!value.empty())
308+
data = u256("0x" + value);
309+
return {AssemblyItemType::PushSubSize, data, location};
310+
}
311+
else if (name == "PUSHSIZE")
312+
return {AssemblyItemType::PushProgramSize, data, location};
313+
else if (name == "PUSHLIB")
314+
{
315+
h256 hash = updateLibraries(value);
316+
return {AssemblyItemType::PushLibraryAddress, hash, location};
317+
}
318+
else if (name == "PUSHDEPLOYADDRESS")
319+
return {AssemblyItemType::PushDeployTimeAddress, data, location};
320+
else if (name == "PUSHIMMUTABLE")
321+
{
322+
h256 hash = updateImmutables(value);
323+
return {AssemblyItemType::PushImmutable, hash, location};
324+
}
325+
else if (name == "ASSIGNIMMUTABLE")
326+
{
327+
h256 hash = updateImmutables(value);
328+
return {AssemblyItemType::AssignImmutable, hash, location};
329+
}
330+
else if (name == "tag")
331+
{
332+
if (!value.empty())
333+
data = u256(value);
334+
return {AssemblyItemType::Tag, data, location};
335+
}
336+
else if (name == "PUSH data")
337+
{
338+
if (!value.empty())
339+
data = u256("0x" + value);
340+
return {AssemblyItemType::PushData, data, location};
341+
}
342+
else if (name == "VERBATIM")
343+
{
344+
AssemblyItem item(fromHex(value), 0, 0);
345+
item.setLocation(location);
346+
return item;
347+
}
348+
else
349+
assertThrow(false, InvalidOpcode, "");
350+
}
351+
}
352+
353+
vector<Json::Value> Assembly::assemblyItemAsJSON(AssemblyItem const& _item, int _sourceIndex) const
354+
{
355+
vector<Json::Value> result;
356+
357+
switch (_item.type())
358+
{
359+
case Operation:
360+
result.emplace_back(createJsonValue(
361+
instructionInfo(_item.instruction()).name,
362+
_sourceIndex,
363+
_item.location().start,
364+
_item.location().end,
365+
_item.getJumpTypeAsString()));
366+
break;
367+
case Push:
368+
result.emplace_back(createJsonValue(
369+
"PUSH",
370+
_sourceIndex,
371+
_item.location().start,
372+
_item.location().end,
373+
toStringInHex(_item.data()),
374+
_item.getJumpTypeAsString()));
375+
break;
376+
case PushString:
377+
result.emplace_back(createJsonValue(
378+
"PUSH tag", _sourceIndex, _item.location().start, _item.location().end, m_strings.at(h256(_item.data()))));
379+
break;
380+
case PushTag:
381+
if (_item.data() == 0)
382+
result.emplace_back(
383+
createJsonValue("PUSH [ErrorTag]", _sourceIndex, _item.location().start, _item.location().end, ""));
384+
else
385+
result.emplace_back(createJsonValue(
386+
"PUSH [tag]", _sourceIndex, _item.location().start, _item.location().end, toString(_item.data())));
387+
break;
388+
case PushSub:
389+
result.emplace_back(createJsonValue(
390+
"PUSH [$]", _sourceIndex, _item.location().start, _item.location().end, toString(h256(_item.data()))));
391+
break;
392+
case PushSubSize:
393+
result.emplace_back(createJsonValue(
394+
"PUSH #[$]", _sourceIndex, _item.location().start, _item.location().end, toString(h256(_item.data()))));
395+
break;
396+
case PushProgramSize:
397+
result.emplace_back(createJsonValue("PUSHSIZE", _sourceIndex, _item.location().start, _item.location().end));
398+
break;
399+
case PushLibraryAddress:
400+
result.emplace_back(createJsonValue(
401+
"PUSHLIB", _sourceIndex, _item.location().start, _item.location().end, m_libraries.at(h256(_item.data()))));
402+
break;
403+
case PushDeployTimeAddress:
404+
result.emplace_back(
405+
createJsonValue("PUSHDEPLOYADDRESS", _sourceIndex, _item.location().start, _item.location().end));
406+
break;
407+
case PushImmutable:
408+
result.emplace_back(createJsonValue(
409+
"PUSHIMMUTABLE",
410+
_sourceIndex,
411+
_item.location().start,
412+
_item.location().end,
413+
m_immutables.at(h256(_item.data()))));
414+
break;
415+
case AssignImmutable:
416+
result.emplace_back(createJsonValue(
417+
"ASSIGNIMMUTABLE",
418+
_sourceIndex,
419+
_item.location().start,
420+
_item.location().end,
421+
m_immutables.at(h256(_item.data()))));
422+
break;
423+
case Tag:
424+
result.emplace_back(
425+
createJsonValue("tag", _sourceIndex, _item.location().start, _item.location().end, toString(_item.data())));
426+
result.emplace_back(createJsonValue("JUMPDEST", _sourceIndex, _item.location().start, _item.location().end));
427+
break;
428+
case PushData:
429+
result.emplace_back(createJsonValue(
430+
"PUSH data", _sourceIndex, _item.location().start, _item.location().end, toStringInHex(_item.data())));
431+
break;
432+
case VerbatimBytecode:
433+
result.emplace_back(createJsonValue(
434+
"VERBATIM", _sourceIndex, _item.location().start, _item.location().end, toHex(_item.verbatimData())));
435+
break;
436+
default:
437+
assertThrow(false, InvalidOpcode, "");
438+
}
439+
return result;
440+
}
441+
230442
Json::Value Assembly::assemblyJSON(map<string, unsigned> const& _sourceIndices) const
231443
{
232444
Json::Value root;
@@ -235,96 +447,17 @@ Json::Value Assembly::assemblyJSON(map<string, unsigned> const& _sourceIndices)
235447
for (AssemblyItem const& i: m_items)
236448
{
237449
int sourceIndex = -1;
238-
if (i.location().sourceName)
450+
if (i.location().sourceIndex.has_value())
451+
sourceIndex = i.location().sourceIndex.value();
452+
else if (i.location().sourceName)
239453
{
240454
auto iter = _sourceIndices.find(*i.location().sourceName);
241455
if (iter != _sourceIndices.end())
242456
sourceIndex = static_cast<int>(iter->second);
243457
}
244458

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-
}
459+
for (Json::Value const& item: assemblyItemAsJSON(i, sourceIndex))
460+
collection.append(item);
328461
}
329462

330463
if (!m_data.empty() || !m_subs.empty())
@@ -342,12 +475,54 @@ Json::Value Assembly::assemblyJSON(map<string, unsigned> const& _sourceIndices)
342475
}
343476
}
344477

345-
if (m_auxiliaryData.size() > 0)
478+
if (!m_auxiliaryData.empty())
346479
root[".auxdata"] = toHex(m_auxiliaryData);
347480

348481
return root;
349482
}
350483

484+
void Assembly::addAssemblyItemsFromJSON(Json::Value const& _code)
485+
{
486+
solAssert(_code.isArray(), "");
487+
for (auto const& it: _code)
488+
this->m_items.emplace_back(loadItemFromJSON(it));
489+
490+
for (auto current = this->m_items.begin(); current != this->m_items.end(); ++current)
491+
{
492+
auto const next = std::next(current);
493+
if (
494+
current->type() == AssemblyItemType::Tag &&
495+
next->type() == AssemblyItemType::Operation &&
496+
next->instruction() == Instruction::JUMPDEST
497+
)
498+
this->m_items.erase(next);
499+
}
500+
}
501+
502+
bool Assembly::loadFromAssemblyJSON(Json::Value const& _json)
503+
{
504+
solAssert(_json[".code"].isArray(), "");
505+
addAssemblyItemsFromJSON(_json[".code"]);
506+
if (_json[".auxdata"].isString())
507+
this->m_auxiliaryData = fromHex(_json[".auxdata"].asString());
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+
this->m_data[h256(fromHex(key))] = fromHex(code.asString());
516+
else
517+
{
518+
shared_ptr<Assembly> subassembly = make_shared<Assembly>();
519+
subassembly->loadFromAssemblyJSON(code);
520+
this->m_subs.emplace_back(subassembly);
521+
}
522+
}
523+
return true;
524+
}
525+
351526
AssemblyItem Assembly::namedTag(string const& _name, size_t _params, size_t _returns, optional<uint64_t> _sourceID)
352527
{
353528
assertThrow(!_name.empty(), AssemblyException, "Empty named tag.");
@@ -402,7 +577,6 @@ Assembly& Assembly::optimise(bool _enable, EVMVersion _evmVersion, bool _isCreat
402577
return *this;
403578
}
404579

405-
406580
Assembly& Assembly::optimise(OptimiserSettings const& _settings)
407581
{
408582
optimiseInternal(_settings, {});

0 commit comments

Comments
 (0)