Skip to content

Commit 3f317cd

Browse files
committed
[libsolidity] Add support to import evm assembly json.
1 parent f23e0e9 commit 3f317cd

File tree

3 files changed

+106
-45
lines changed

3 files changed

+106
-45
lines changed

libsolidity/interface/CompilerStack.cpp

Lines changed: 97 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,7 @@ void CompilerStack::setLibraries(std::map<std::string, util::h160> const& _libra
242242
void CompilerStack::setOptimiserSettings(bool _optimize, size_t _runs)
243243
{
244244
OptimiserSettings settings = _optimize ? OptimiserSettings::standard() : OptimiserSettings::minimal();
245+
settings.enabled = _optimize;
245246
settings.expectedExecutionsPerDeployment = _runs;
246247
setOptimiserSettings(std::move(settings));
247248
}
@@ -416,6 +417,29 @@ void CompilerStack::importASTs(map<string, Json::Value> const& _sources)
416417
storeContractDefinitions();
417418
}
418419

420+
void CompilerStack::importEvmAssemblyJson(std::map<std::string, Json::Value> const& _sources)
421+
{
422+
solAssert(_sources.size() == 1, "");
423+
solAssert(m_sourceJsons.empty(), "");
424+
solAssert(m_sourceOrder.empty(), "");
425+
if (m_stackState != Empty)
426+
solThrow(CompilerError, "Must call importEvmAssemblyJson only before the SourcesSet state.");
427+
428+
m_sourceJsons = _sources;
429+
Json::Value jsonValue = _sources.begin()->second;
430+
if (jsonValue.isMember("sourceList"))
431+
for (auto const& item: jsonValue["sourceList"])
432+
{
433+
Source source;
434+
source.charStream = std::make_shared<CharStream>(item.asString(), "");
435+
m_sources.emplace(std::make_pair(item.asString(), source));
436+
m_sourceOrder.push_back(&m_sources[item.asString()]);
437+
}
438+
m_sourceJsons[_sources.begin()->first] = std::move(jsonValue);
439+
m_compilationSourceType = CompilationSourceType::EvmAssemblyJson;
440+
m_stackState = SourcesSet;
441+
}
442+
419443
bool CompilerStack::analyze()
420444
{
421445
if (m_stackState != ParsedAndImported || m_stackState >= AnalysisPerformed)
@@ -605,6 +629,9 @@ bool CompilerStack::parseAndAnalyze(State _stopAfter)
605629
{
606630
m_stopAfter = _stopAfter;
607631

632+
if (m_compilationSourceType == CompilationSourceType::EvmAssemblyJson)
633+
return true;
634+
608635
bool success = parse();
609636
if (m_stackState >= m_stopAfter)
610637
return success;
@@ -654,53 +681,73 @@ bool CompilerStack::compile(State _stopAfter)
654681
// Only compile contracts individually which have been requested.
655682
map<ContractDefinition const*, shared_ptr<Compiler const>> otherCompilers;
656683

657-
for (Source const* source: m_sourceOrder)
658-
for (ASTPointer<ASTNode> const& node: source->ast->nodes())
659-
if (auto contract = dynamic_cast<ContractDefinition const*>(node.get()))
660-
if (isRequestedContract(*contract))
661-
{
662-
try
684+
if (m_compilationSourceType == CompilationSourceType::EvmAssemblyJson)
685+
{
686+
solAssert(m_sourceJsons.size() == 1);
687+
688+
string const evmSourceName = m_sourceJsons.begin()->first;
689+
Json::Value const evmJson = m_sourceJsons.begin()->second;
690+
691+
evmasm::Assembly::OptimiserSettings optimiserSettings =
692+
evmasm::Assembly::OptimiserSettings::translateSettings(m_optimiserSettings, m_evmVersion);
693+
694+
m_contracts[evmSourceName].evmAssembly = evmasm::Assembly::loadFromAssemblyJSON(m_sourceJsons[evmSourceName]);
695+
if (m_optimiserSettings.enabled)
696+
m_contracts[evmSourceName].evmAssembly->optimise(optimiserSettings);
697+
m_contracts[evmSourceName].object = m_contracts[evmSourceName].evmAssembly->assemble();
698+
699+
m_contracts[evmSourceName].evmRuntimeAssembly = std::make_shared<evmasm::Assembly>(m_contracts[evmSourceName].evmAssembly->sub(0));
700+
solAssert(m_contracts[evmSourceName].evmRuntimeAssembly->isCreation() == false);
701+
if (m_optimiserSettings.enabled)
702+
m_contracts[evmSourceName].evmRuntimeAssembly->optimise(optimiserSettings);
703+
m_contracts[evmSourceName].runtimeObject = m_contracts[evmSourceName].evmRuntimeAssembly->assemble();
704+
}
705+
else
706+
{
707+
for (Source const* source: m_sourceOrder)
708+
for (ASTPointer<ASTNode> const& node: source->ast->nodes())
709+
if (auto contract = dynamic_cast<ContractDefinition const*>(node.get()))
710+
if (isRequestedContract(*contract))
663711
{
664-
if (m_viaIR || m_generateIR || m_generateEwasm)
665-
generateIR(*contract);
666-
if (m_generateEvmBytecode)
712+
try
667713
{
668-
if (m_viaIR)
669-
generateEVMFromIR(*contract);
670-
else
671-
compileContract(*contract, otherCompilers);
714+
if (m_viaIR || m_generateIR || m_generateEwasm)
715+
generateIR(*contract);
716+
if (m_generateEvmBytecode)
717+
{
718+
if (m_viaIR)
719+
generateEVMFromIR(*contract);
720+
else
721+
compileContract(*contract, otherCompilers);
722+
}
723+
if (m_generateEwasm)
724+
generateEwasm(*contract);
672725
}
673-
if (m_generateEwasm)
674-
generateEwasm(*contract);
675-
}
676-
catch (Error const& _error)
677-
{
678-
if (_error.type() != Error::Type::CodeGenerationError)
679-
throw;
680-
m_errorReporter.error(_error.errorId(), _error.type(), SourceLocation(), _error.what());
681-
return false;
682-
}
683-
catch (UnimplementedFeatureError const& _unimplementedError)
684-
{
685-
if (
686-
SourceLocation const* sourceLocation =
687-
boost::get_error_info<langutil::errinfo_sourceLocation>(_unimplementedError)
688-
)
726+
catch (Error const& _error)
689727
{
690-
string const* comment = _unimplementedError.comment();
691-
m_errorReporter.error(
692-
1834_error,
693-
Error::Type::CodeGenerationError,
694-
*sourceLocation,
695-
"Unimplemented feature error" +
696-
((comment && !comment->empty()) ? ": " + *comment : string{}) +
697-
" in " +
698-
_unimplementedError.lineInfo()
699-
);
728+
if (_error.type() != Error::Type::CodeGenerationError)
729+
throw;
730+
m_errorReporter.error(_error.errorId(), _error.type(), SourceLocation(), _error.what());
700731
return false;
701732
}
702-
else
703-
throw;
733+
catch (UnimplementedFeatureError const& _unimplementedError)
734+
{
735+
if (SourceLocation const* sourceLocation
736+
= boost::get_error_info<langutil::errinfo_sourceLocation>(_unimplementedError))
737+
{
738+
string const* comment = _unimplementedError.comment();
739+
m_errorReporter.error(
740+
1834_error,
741+
Error::Type::CodeGenerationError,
742+
*sourceLocation,
743+
"Unimplemented feature error"
744+
+ ((comment && !comment->empty()) ? ": " + *comment : string{}) + " in "
745+
+ _unimplementedError.lineInfo());
746+
return false;
747+
}
748+
else
749+
throw;
750+
}
704751
}
705752
}
706753
m_stackState = CompilationSuccessful;
@@ -943,9 +990,10 @@ map<string, unsigned> CompilerStack::sourceIndices() const
943990
map<string, unsigned> indices;
944991
unsigned index = 0;
945992
for (auto const& s: m_sources)
946-
indices[s.first] = index++;
947-
solAssert(!indices.count(CompilerContext::yulUtilityFileName()), "");
948-
indices[CompilerContext::yulUtilityFileName()] = index++;
993+
if (s.first != CompilerContext::yulUtilityFileName())
994+
indices[s.first] = index++;
995+
if (indices.find(CompilerContext::yulUtilityFileName()) == indices.end())
996+
indices[CompilerContext::yulUtilityFileName()] = index++;
949997
return indices;
950998
}
951999

@@ -1492,6 +1540,11 @@ string CompilerStack::createMetadata(Contract const& _contract, bool _forIR) con
14921540
case CompilationSourceType::SolidityAST:
14931541
sourceType = "SolidityAST";
14941542
break;
1543+
case CompilationSourceType::EvmAssemblyJson:
1544+
sourceType = "EvmAssemblyJson";
1545+
break;
1546+
default:
1547+
solAssert(false);
14951548
}
14961549
meta["language"] = sourceType;
14971550
meta["compiler"]["version"] = VersionStringStrict;

libsolidity/interface/CompilerStack.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,9 @@ class CompilerStack: public langutil::CharStreamProvider
121121
/// Regular compilation from Solidity source files.
122122
Solidity,
123123
/// Compilation from an imported Solidity AST.
124-
SolidityAST
124+
SolidityAST,
125+
/// Compilation from an imported EVM Assembly JSON
126+
EvmAssemblyJson
125127
};
126128

127129
/// Creates a new compiler stack.
@@ -229,6 +231,10 @@ class CompilerStack: public langutil::CharStreamProvider
229231
/// Will throw errors if the import fails
230232
void importASTs(std::map<std::string, Json::Value> const& _sources);
231233

234+
/// Imports given Evm Assembly Json. Leads to the same internal state as parse().
235+
/// Will throw errors if the import fails
236+
void importEvmAssemblyJson(std::map<std::string, Json::Value> const& _sources);
237+
232238
/// Performs the analysis steps (imports, scopesetting, syntaxCheck, referenceResolving,
233239
/// typechecking, staticAnalysis) on previously parsed sources.
234240
/// @returns false on error.

libsolidity/interface/OptimiserSettings.h

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

160162
}

0 commit comments

Comments
 (0)