Skip to content

Commit 4f2baed

Browse files
committed
[solc] Add --import-asm-json input mode.
1 parent ebefb5d commit 4f2baed

File tree

7 files changed

+153
-53
lines changed

7 files changed

+153
-53
lines changed

libsolidity/interface/CompilerStack.cpp

Lines changed: 70 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,28 @@ void CompilerStack::importASTs(map<string, Json::Value> const& _sources)
414414
storeContractDefinitions();
415415
}
416416

417+
void CompilerStack::importEvmAssemblyJson(std::map<std::string, Json::Value> const& _sources)
418+
{
419+
solAssert(_sources.size() == 1, "");
420+
solAssert(m_sources.empty(), "");
421+
solAssert(m_sourceOrder.empty(), "");
422+
if (m_stackState != Empty)
423+
solThrow(CompilerError, "Must call importEvmAssemblyJson only before the SourcesSet state.");
424+
425+
Json::Value jsonValue = _sources.begin()->second;
426+
if (jsonValue.isMember("sourceList"))
427+
for (auto const& item: jsonValue["sourceList"])
428+
{
429+
Source source;
430+
source.charStream = std::make_shared<CharStream>(item.asString(), "");
431+
m_sources.emplace(std::make_pair(item.asString(), source));
432+
m_sourceOrder.push_back(&m_sources[item.asString()]);
433+
}
434+
m_evmAssemblyJson[_sources.begin()->first] = jsonValue;
435+
m_importedSources = true;
436+
m_stackState = SourcesSet;
437+
}
438+
417439
bool CompilerStack::analyze()
418440
{
419441
if (m_stackState != ParsedAndImported || m_stackState >= AnalysisPerformed)
@@ -600,6 +622,9 @@ bool CompilerStack::parseAndAnalyze(State _stopAfter)
600622
{
601623
m_stopAfter = _stopAfter;
602624

625+
if (!m_evmAssemblyJson.empty())
626+
return true;
627+
603628
bool success = parse();
604629
if (m_stackState >= m_stopAfter)
605630
return success;
@@ -649,55 +674,58 @@ bool CompilerStack::compile(State _stopAfter)
649674
// Only compile contracts individually which have been requested.
650675
map<ContractDefinition const*, shared_ptr<Compiler const>> otherCompilers;
651676

652-
for (Source const* source: m_sourceOrder)
653-
for (ASTPointer<ASTNode> const& node: source->ast->nodes())
654-
if (auto contract = dynamic_cast<ContractDefinition const*>(node.get()))
655-
if (isRequestedContract(*contract))
656-
{
657-
try
677+
if (!m_evmAssemblyJson.empty())
678+
{
679+
680+
}
681+
else
682+
{
683+
for (Source const* source: m_sourceOrder)
684+
for (ASTPointer<ASTNode> const& node: source->ast->nodes())
685+
if (auto contract = dynamic_cast<ContractDefinition const*>(node.get()))
686+
if (isRequestedContract(*contract))
658687
{
659-
if (m_viaIR || m_generateIR || m_generateEwasm)
660-
generateIR(*contract);
661-
if (m_generateEvmBytecode)
688+
try
662689
{
663-
if (m_viaIR)
664-
generateEVMFromIR(*contract);
665-
else
666-
compileContract(*contract, otherCompilers);
690+
if (m_viaIR || m_generateIR || m_generateEwasm)
691+
generateIR(*contract);
692+
if (m_generateEvmBytecode)
693+
{
694+
if (m_viaIR)
695+
generateEVMFromIR(*contract);
696+
else
697+
compileContract(*contract, otherCompilers);
698+
}
699+
if (m_generateEwasm)
700+
generateEwasm(*contract);
667701
}
668-
if (m_generateEwasm)
669-
generateEwasm(*contract);
670-
}
671-
catch (Error const& _error)
672-
{
673-
if (_error.type() != Error::Type::CodeGenerationError)
674-
throw;
675-
m_errorReporter.error(_error.errorId(), _error.type(), SourceLocation(), _error.what());
676-
return false;
677-
}
678-
catch (UnimplementedFeatureError const& _unimplementedError)
679-
{
680-
if (
681-
SourceLocation const* sourceLocation =
682-
boost::get_error_info<langutil::errinfo_sourceLocation>(_unimplementedError)
683-
)
702+
catch (Error const& _error)
684703
{
685-
string const* comment = _unimplementedError.comment();
686-
m_errorReporter.error(
687-
1834_error,
688-
Error::Type::CodeGenerationError,
689-
*sourceLocation,
690-
"Unimplemented feature error" +
691-
((comment && !comment->empty()) ? ": " + *comment : string{}) +
692-
" in " +
693-
_unimplementedError.lineInfo()
694-
);
704+
if (_error.type() != Error::Type::CodeGenerationError)
705+
throw;
706+
m_errorReporter.error(_error.errorId(), _error.type(), SourceLocation(), _error.what());
695707
return false;
696708
}
697-
else
698-
throw;
709+
catch (UnimplementedFeatureError const& _unimplementedError)
710+
{
711+
if (SourceLocation const* sourceLocation
712+
= boost::get_error_info<langutil::errinfo_sourceLocation>(_unimplementedError))
713+
{
714+
string const* comment = _unimplementedError.comment();
715+
m_errorReporter.error(
716+
1834_error,
717+
Error::Type::CodeGenerationError,
718+
*sourceLocation,
719+
"Unimplemented feature error"
720+
+ ((comment && !comment->empty()) ? ": " + *comment : string{}) + " in "
721+
+ _unimplementedError.lineInfo());
722+
return false;
723+
}
724+
else
725+
throw;
726+
}
699727
}
700-
}
728+
}
701729
m_stackState = CompilationSuccessful;
702730
this->link();
703731
return true;

libsolidity/interface/CompilerStack.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,10 @@ class CompilerStack: public langutil::CharStreamProvider
222222
/// Will throw errors if the import fails
223223
void importASTs(std::map<std::string, Json::Value> const& _sources);
224224

225+
/// Imports given Evm Assembly Json. Leads to the same internal state as parse().
226+
/// Will throw errors if the import fails
227+
void importEvmAssemblyJson(std::map<std::string, Json::Value> const& _sources);
228+
225229
/// Performs the analysis steps (imports, scopesetting, syntaxCheck, referenceResolving,
226230
/// typechecking, staticAnalysis) on previously parsed sources.
227231
/// @returns false on error.
@@ -499,6 +503,7 @@ class CompilerStack: public langutil::CharStreamProvider
499503
std::map<std::string const, Source> m_sources;
500504
// if imported, store AST-JSONS for each filename
501505
std::map<std::string, Json::Value> m_sourceJsons;
506+
std::map<std::string, Json::Value> m_evmAssemblyJson;
502507
std::vector<std::string> m_unhandledSMTLib2Queries;
503508
std::map<util::h256, std::string> m_smtlib2Responses;
504509
std::shared_ptr<GlobalContext> m_globalContext;

libsolidity/interface/OptimiserSettings.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,8 @@ struct OptimiserSettings
149149
/// This specifies an estimate on how often each opcode in this assembly will be executed,
150150
/// i.e. use a small value to optimise for size and a large value to optimise for runtime gas usage.
151151
size_t expectedExecutionsPerDeployment = 200;
152+
/// Flag reflecting whether optimizer is enabled.
153+
bool enabled = false;
152154
};
153155

154156
}

solc/CommandLineInterface.cpp

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,25 @@ map<string, Json::Value> CommandLineInterface::parseAstFromInput()
555555
return sourceJsons;
556556
}
557557

558+
map<string, Json::Value> CommandLineInterface::parseEvmAssemblyJsonFromInput()
559+
{
560+
solAssert(m_options.input.mode == InputMode::CompilerWithEvmAssemblyJsonImport, "");
561+
solAssert(m_fileReader.sourceUnits().size() == 1, "");
562+
563+
map<string, Json::Value> sourceJsons;
564+
565+
for (auto const& iter: m_fileReader.sourceUnits())
566+
{
567+
Json::Value evmAsmJson;
568+
astAssert(jsonParseStrict(iter.second, evmAsmJson), "Input file could not be parsed to JSON");
569+
astAssert(evmAsmJson.isMember(".code"), "Invalid Format for assembly-JSON: Must have '.code'-object");
570+
astAssert(evmAsmJson.isMember(".data"), "Invalid Format for assembly-JSON: Must have '.data'-object");
571+
sourceJsons[iter.first] = evmAsmJson;
572+
}
573+
574+
return sourceJsons;
575+
}
576+
558577
void CommandLineInterface::createFile(string const& _fileName, string const& _data)
559578
{
560579
namespace fs = boost::filesystem;
@@ -658,6 +677,7 @@ void CommandLineInterface::processInput()
658677
break;
659678
case InputMode::Compiler:
660679
case InputMode::CompilerWithASTImport:
680+
case InputMode::CompilerWithEvmAssemblyJsonImport:
661681
compile();
662682
outputCompilationResults();
663683
}
@@ -678,7 +698,11 @@ void CommandLineInterface::printLicense()
678698

679699
void CommandLineInterface::compile()
680700
{
681-
solAssert(m_options.input.mode == InputMode::Compiler || m_options.input.mode == InputMode::CompilerWithASTImport, "");
701+
solAssert(
702+
m_options.input.mode == InputMode::Compiler ||
703+
m_options.input.mode == InputMode::CompilerWithASTImport ||
704+
m_options.input.mode == InputMode::CompilerWithEvmAssemblyJsonImport, ""
705+
);
682706

683707
m_compiler = make_unique<CompilerStack>(m_fileReader.reader());
684708

@@ -725,7 +749,18 @@ void CommandLineInterface::compile()
725749

726750
m_compiler->setOptimiserSettings(m_options.optimiserSettings());
727751

728-
if (m_options.input.mode == InputMode::CompilerWithASTImport)
752+
if (m_options.input.mode == InputMode::CompilerWithEvmAssemblyJsonImport)
753+
{
754+
try
755+
{
756+
m_compiler->importEvmAssemblyJson(parseEvmAssemblyJsonFromInput());
757+
}
758+
catch (Exception const& _exc)
759+
{
760+
solThrow(CommandLineExecutionError, "Failed to import Evm Assembly JSON: "s + _exc.what());
761+
}
762+
}
763+
else if (m_options.input.mode == InputMode::CompilerWithASTImport)
729764
{
730765
try
731766
{
@@ -785,7 +820,11 @@ void CommandLineInterface::compile()
785820

786821
void CommandLineInterface::handleCombinedJSON()
787822
{
788-
solAssert(m_options.input.mode == InputMode::Compiler || m_options.input.mode == InputMode::CompilerWithASTImport, "");
823+
solAssert(
824+
m_options.input.mode == InputMode::Compiler ||
825+
m_options.input.mode == InputMode::CompilerWithASTImport ||
826+
m_options.input.mode == InputMode::CompilerWithEvmAssemblyJsonImport, ""
827+
);
789828

790829
if (!m_options.compiler.combinedJsonRequests.has_value())
791830
return;
@@ -877,7 +916,11 @@ void CommandLineInterface::handleCombinedJSON()
877916

878917
void CommandLineInterface::handleAst()
879918
{
880-
solAssert(m_options.input.mode == InputMode::Compiler || m_options.input.mode == InputMode::CompilerWithASTImport, "");
919+
solAssert(
920+
m_options.input.mode == InputMode::Compiler ||
921+
m_options.input.mode == InputMode::CompilerWithASTImport ||
922+
m_options.input.mode == InputMode::CompilerWithEvmAssemblyJsonImport, ""
923+
);
881924

882925
if (!m_options.compiler.outputs.astCompactJson)
883926
return;
@@ -1121,7 +1164,11 @@ void CommandLineInterface::assemble(yul::AssemblyStack::Language _language, yul:
11211164

11221165
void CommandLineInterface::outputCompilationResults()
11231166
{
1124-
solAssert(m_options.input.mode == InputMode::Compiler || m_options.input.mode == InputMode::CompilerWithASTImport, "");
1167+
solAssert(
1168+
m_options.input.mode == InputMode::Compiler ||
1169+
m_options.input.mode == InputMode::CompilerWithASTImport ||
1170+
m_options.input.mode == InputMode::CompilerWithEvmAssemblyJsonImport, ""
1171+
);
11251172

11261173
handleCombinedJSON();
11271174

solc/CommandLineInterface.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,8 @@ class CommandLineInterface
115115
/// or standard-json output
116116
std::map<std::string, Json::Value> parseAstFromInput();
117117

118+
std::map<std::string, Json::Value> parseEvmAssemblyJsonFromInput();
119+
118120
/// Create a file in the given directory
119121
/// @arg _fileName the name of the file
120122
/// @arg _data to be written

solc/CommandLineParser.cpp

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ static string const g_strExperimentalViaIR = "experimental-via-ir";
5151
static string const g_strGas = "gas";
5252
static string const g_strHelp = "help";
5353
static string const g_strImportAst = "import-ast";
54+
static string const g_strImportEvmAssemblerJson = "import-asm-json";
5455
static string const g_strInputFile = "input-file";
5556
static string const g_strYul = "yul";
5657
static string const g_strYulDialect = "yul-dialect";
@@ -137,6 +138,7 @@ static map<InputMode, string> const g_inputModeName = {
137138
{InputMode::StandardJson, "standard JSON"},
138139
{InputMode::Linker, "linker"},
139140
{InputMode::LanguageServer, "language server (LSP)"},
141+
{InputMode::CompilerWithEvmAssemblyJsonImport, "assembler (EVM ASM JSON import)"}
140142
};
141143

142144
void CommandLineParser::checkMutuallyExclusive(vector<string> const& _optionNames)
@@ -267,6 +269,8 @@ OptimiserSettings CommandLineOptions::optimiserSettings() const
267269
if (optimizer.yulSteps.has_value())
268270
settings.yulOptimiserSteps = optimizer.yulSteps.value();
269271

272+
settings.enabled = optimizer.enabled;
273+
270274
return settings;
271275
}
272276

@@ -316,20 +320,20 @@ void CommandLineParser::parseInputPathsAndRemappings()
316320
m_options.input.paths.insert(positionalArg);
317321
}
318322

319-
if (m_options.input.mode == InputMode::StandardJson)
323+
if (m_options.input.mode == InputMode::StandardJson || m_options.input.mode == InputMode::CompilerWithEvmAssemblyJsonImport)
320324
{
321325
if (m_options.input.paths.size() > 1 || (m_options.input.paths.size() == 1 && m_options.input.addStdin))
322326
solThrow(
323327
CommandLineValidationError,
324-
"Too many input files for --" + g_strStandardJSON + ".\n"
328+
"Too many input files for --" + (m_options.input.mode == InputMode::StandardJson ? g_strStandardJSON : g_strImportEvmAssemblerJson) + ".\n"
325329
"Please either specify a single file name or provide its content on standard input."
326330
);
327-
else if (m_options.input.paths.size() == 0)
331+
else if (m_options.input.paths.empty())
328332
// Standard JSON mode input used to be handled separately and zero files meant "read from stdin".
329333
// Keep it working that way for backwards-compatibility.
330334
m_options.input.addStdin = true;
331335
}
332-
else if (m_options.input.paths.size() == 0 && !m_options.input.addStdin)
336+
else if (m_options.input.paths.empty() && !m_options.input.addStdin)
333337
solThrow(
334338
CommandLineValidationError,
335339
"No input files given. If you wish to use the standard input please specify \"-\" explicitly."
@@ -461,6 +465,7 @@ void CommandLineParser::parseOutputSelection()
461465
solAssert(false);
462466
case InputMode::Compiler:
463467
case InputMode::CompilerWithASTImport:
468+
case InputMode::CompilerWithEvmAssemblyJsonImport:
464469
return contains(compilerModeOutputs, _outputName);
465470
case InputMode::Assembler:
466471
return contains(assemblerModeOutputs, _outputName);
@@ -636,6 +641,10 @@ General Information)").c_str(),
636641
"Supported Inputs is the output of the --" + g_strStandardJSON + " or the one produced by "
637642
"--" + g_strCombinedJson + " " + CombinedJsonRequests::componentName(&CombinedJsonRequests::ast)).c_str()
638643
)
644+
(
645+
g_strImportEvmAssemblerJson.c_str(),
646+
"Import evm assembler json, assumes input holds the evm assembly in JSON format."
647+
)
639648
(
640649
g_strLSP.c_str(),
641650
"Switch to language server mode (\"LSP\"). Allows the compiler to be used as an analysis backend "
@@ -892,6 +901,8 @@ void CommandLineParser::processArgs()
892901
m_options.input.mode = InputMode::Linker;
893902
else if (m_args.count(g_strImportAst) > 0)
894903
m_options.input.mode = InputMode::CompilerWithASTImport;
904+
else if (m_args.count(g_strImportEvmAssemblerJson) > 0)
905+
m_options.input.mode = InputMode::CompilerWithEvmAssemblyJsonImport;
895906
else
896907
m_options.input.mode = InputMode::Compiler;
897908

@@ -1260,7 +1271,11 @@ void CommandLineParser::processArgs()
12601271
if (m_options.input.mode == InputMode::Compiler)
12611272
m_options.input.errorRecovery = (m_args.count(g_strErrorRecovery) > 0);
12621273

1263-
solAssert(m_options.input.mode == InputMode::Compiler || m_options.input.mode == InputMode::CompilerWithASTImport);
1274+
solAssert(
1275+
m_options.input.mode == InputMode::Compiler ||
1276+
m_options.input.mode == InputMode::CompilerWithASTImport ||
1277+
m_options.input.mode == InputMode::CompilerWithEvmAssemblyJsonImport
1278+
);
12641279
}
12651280

12661281
void CommandLineParser::parseCombinedJsonOption()

solc/CommandLineParser.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ enum class InputMode
5656
StandardJson,
5757
Linker,
5858
Assembler,
59-
LanguageServer
59+
LanguageServer,
60+
CompilerWithEvmAssemblyJsonImport
6061
};
6162

6263
struct CompilerOutputs

0 commit comments

Comments
 (0)