Merge pull request #2853 from ethereum/cleanup-asm-stream

Split out the JSON functionality from assembly.stream()
This commit is contained in:
chriseth 2017-09-12 13:23:59 +02:00 committed by GitHub
commit 513ae59bba
10 changed files with 76 additions and 61 deletions

View File

@ -181,7 +181,7 @@ private:
}
ostream& Assembly::streamAsm(ostream& _out, string const& _prefix, StringMap const& _sourceCodes) const
void Assembly::assemblyStream(ostream& _out, string const& _prefix, StringMap const& _sourceCodes) const
{
Functionalizer f(_out, _prefix, _sourceCodes);
@ -199,18 +199,23 @@ ostream& Assembly::streamAsm(ostream& _out, string const& _prefix, StringMap con
for (size_t i = 0; i < m_subs.size(); ++i)
{
_out << endl << _prefix << "sub_" << i << ": assembly {\n";
m_subs[i]->streamAsm(_out, _prefix + " ", _sourceCodes);
m_subs[i]->assemblyStream(_out, _prefix + " ", _sourceCodes);
_out << _prefix << "}" << endl;
}
}
if (m_auxiliaryData.size() > 0)
_out << endl << _prefix << "auxdata: 0x" << toHex(m_auxiliaryData) << endl;
return _out;
}
Json::Value Assembly::createJsonValue(string _name, int _begin, int _end, string _value, string _jumpType) const
string Assembly::assemblyString(StringMap const& _sourceCodes) const
{
ostringstream tmp;
assemblyStream(tmp, "", _sourceCodes);
return tmp.str();
}
Json::Value Assembly::createJsonValue(string _name, int _begin, int _end, string _value, string _jumpType)
{
Json::Value value;
value["name"] = _name;
@ -223,14 +228,14 @@ Json::Value Assembly::createJsonValue(string _name, int _begin, int _end, string
return value;
}
string toStringInHex(u256 _value)
string Assembly::toStringInHex(u256 _value)
{
std::stringstream hexStr;
hexStr << hex << _value;
return hexStr.str();
}
Json::Value Assembly::streamAsmJson(ostream& _out, StringMap const& _sourceCodes) const
Json::Value Assembly::assemblyJSON(StringMap const& _sourceCodes) const
{
Json::Value root;
@ -301,29 +306,16 @@ Json::Value Assembly::streamAsmJson(ostream& _out, StringMap const& _sourceCodes
{
std::stringstream hexStr;
hexStr << hex << i;
data[hexStr.str()] = m_subs[i]->stream(_out, "", _sourceCodes, true);
data[hexStr.str()] = m_subs[i]->assemblyJSON(_sourceCodes);
}
}
if (m_auxiliaryData.size() > 0)
root[".auxdata"] = toHex(m_auxiliaryData);
_out << root;
return root;
}
Json::Value Assembly::stream(ostream& _out, string const& _prefix, StringMap const& _sourceCodes, bool _inJsonFormat) const
{
if (_inJsonFormat)
return streamAsmJson(_out, _sourceCodes);
else
{
streamAsm(_out, _prefix, _sourceCodes);
return Json::Value();
}
}
AssemblyItem const& Assembly::append(AssemblyItem const& _i)
{
assertThrow(m_deposit >= 0, AssemblyException, "");

View File

@ -120,11 +120,19 @@ public:
/// If @a _enable is not set, will perform some simple peephole optimizations.
Assembly& optimise(bool _enable, bool _isCreation = true, size_t _runs = 200);
Json::Value stream(
/// Create a text representation of the assembly.
std::string assemblyString(
StringMap const& _sourceCodes = StringMap()
) const;
void assemblyStream(
std::ostream& _out,
std::string const& _prefix = "",
const StringMap &_sourceCodes = StringMap(),
bool _inJsonFormat = false
StringMap const& _sourceCodes = StringMap()
) const;
/// Create a JSON representation of the assembly.
Json::Value assemblyJSON(
StringMap const& _sourceCodes = StringMap()
) const;
protected:
@ -136,9 +144,8 @@ protected:
unsigned bytesRequired(unsigned subTagSize) const;
private:
Json::Value streamAsmJson(std::ostream& _out, StringMap const& _sourceCodes) const;
std::ostream& streamAsm(std::ostream& _out, std::string const& _prefix, StringMap const& _sourceCodes) const;
Json::Value createJsonValue(std::string _name, int _begin, int _end, std::string _value = std::string(), std::string _jumpType = std::string()) const;
static Json::Value createJsonValue(std::string _name, int _begin, int _end, std::string _value = std::string(), std::string _jumpType = std::string());
static std::string toStringInHex(u256 _value);
protected:
/// 0 is reserved for exception
@ -161,7 +168,7 @@ protected:
inline std::ostream& operator<<(std::ostream& _out, Assembly const& _a)
{
_a.stream(_out);
_a.assemblyStream(_out);
return _out;
}

View File

@ -72,14 +72,13 @@ std::string dev::eth::compileLLLToAsm(std::string const& _src, bool _opt, std::v
{
CompilerState cs;
cs.populateStandard();
stringstream ret;
auto assembly = CodeFragment::compile(_src, cs).assembly(cs);
if (_opt)
assembly = assembly.optimise(true);
assembly.stream(ret);
string ret = assembly.assemblyString();
for (auto i: cs.treesToKill)
killBigints(i);
return ret.str();
return ret;
}
catch (Exception const& _e)
{

View File

@ -60,10 +60,14 @@ public:
/// @returns Only the runtime object (without constructor).
eth::LinkerObject runtimeObject() const { return m_context.assembledRuntimeObject(m_runtimeSub); }
/// @arg _sourceCodes is the map of input files to source code strings
/// @arg _inJsonFromat shows whether the out should be in Json format
Json::Value streamAssembly(std::ostream& _stream, StringMap const& _sourceCodes = StringMap(), bool _inJsonFormat = false) const
std::string assemblyString(StringMap const& _sourceCodes = StringMap()) const
{
return m_context.streamAssembly(_stream, _sourceCodes, _inJsonFormat);
return m_context.assemblyString(_sourceCodes);
}
/// @arg _sourceCodes is the map of input files to source code strings
Json::Value assemblyJSON(StringMap const& _sourceCodes = StringMap()) const
{
return m_context.assemblyJSON(_sourceCodes);
}
/// @returns Assembly items of the normal compiler context
eth::AssemblyItems const& assemblyItems() const { return m_context.assembly().items(); }

View File

@ -209,10 +209,15 @@ public:
eth::Assembly& nonConstAssembly() { return *m_asm; }
/// @arg _sourceCodes is the map of input files to source code strings
/// @arg _inJsonFormat shows whether the out should be in Json format
Json::Value streamAssembly(std::ostream& _stream, StringMap const& _sourceCodes = StringMap(), bool _inJsonFormat = false) const
std::string assemblyString(StringMap const& _sourceCodes = StringMap()) const
{
return m_asm->stream(_stream, "", _sourceCodes, _inJsonFormat);
return m_asm->assemblyString(_sourceCodes);
}
/// @arg _sourceCodes is the map of input files to source code strings
Json::Value assemblyJSON(StringMap const& _sourceCodes = StringMap()) const
{
return m_asm->assemblyJSON(_sourceCodes);
}
eth::LinkerObject const& assembledObject() const { return m_asm->assemble(); }

View File

@ -91,9 +91,7 @@ MachineAssemblyObject AssemblyStack::assemble(Machine _machine) const
eth::Assembly assembly;
assembly::CodeGenerator::assemble(*m_parserResult, *m_analysisInfo, assembly);
object.bytecode = make_shared<eth::LinkerObject>(assembly.assemble());
ostringstream tmp;
assembly.stream(tmp);
object.assembly = tmp.str();
object.assembly = assembly.assemblyString();
return object;
}
case Machine::EVM15:

View File

@ -347,16 +347,24 @@ eth::LinkerObject const& CompilerStack::cloneObject(string const& _contractName)
return contract(_contractName).cloneObject;
}
Json::Value CompilerStack::streamAssembly(ostream& _outStream, string const& _contractName, StringMap _sourceCodes, bool _inJsonFormat) const
/// FIXME: cache this string
string CompilerStack::assemblyString(string const& _contractName, StringMap _sourceCodes) const
{
Contract const& currentContract = contract(_contractName);
if (currentContract.compiler)
return currentContract.compiler->streamAssembly(_outStream, _sourceCodes, _inJsonFormat);
return currentContract.compiler->assemblyString(_sourceCodes);
else
{
_outStream << "Contract not fully implemented" << endl;
return Json::Value();
return string();
}
/// FIXME: cache the JSON
Json::Value CompilerStack::assemblyJSON(string const& _contractName, StringMap _sourceCodes) const
{
Contract const& currentContract = contract(_contractName);
if (currentContract.compiler)
return currentContract.compiler->assemblyJSON(_sourceCodes);
else
return Json::Value();
}
vector<string> CompilerStack::sourceNames() const

View File

@ -190,11 +190,15 @@ public:
/// if the contract does not (yet) have bytecode.
std::string const* runtimeSourceMapping(std::string const& _contractName = "") const;
/// Streams a verbose version of the assembly to @a _outStream.
/// @return a verbose text representation of the assembly.
/// @arg _sourceCodes is the map of input files to source code strings
/// @arg _inJsonFromat shows whether the out should be in Json format
/// Prerequisite: Successful compilation.
Json::Value streamAssembly(std::ostream& _outStream, std::string const& _contractName = "", StringMap _sourceCodes = StringMap(), bool _inJsonFormat = false) const;
std::string assemblyString(std::string const& _contractName = "", StringMap _sourceCodes = StringMap()) const;
/// @returns a JSON representation of the assembly.
/// @arg _sourceCodes is the map of input files to source code strings
/// Prerequisite: Successful compilation.
Json::Value assemblyJSON(std::string const& _contractName = "", StringMap _sourceCodes = StringMap()) const;
/// @returns a JSON representing the contract ABI.
/// Prerequisite: Successful call to parse or compile.

View File

@ -400,10 +400,8 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
// EVM
Json::Value evmData(Json::objectValue);
// @TODO: add ir
ostringstream tmp;
m_compilerStack.streamAssembly(tmp, contractName, createSourceList(_input), false);
evmData["assembly"] = tmp.str();
evmData["legacyAssembly"] = m_compilerStack.streamAssembly(tmp, contractName, createSourceList(_input), true);
evmData["assembly"] = m_compilerStack.assemblyString(contractName, createSourceList(_input));
evmData["legacyAssembly"] = m_compilerStack.assemblyJSON(contractName, createSourceList(_input));
evmData["methodIdentifiers"] = m_compilerStack.methodIdentifiers(contractName);
evmData["gasEstimates"] = m_compilerStack.gasEstimates(contractName);

View File

@ -865,10 +865,7 @@ void CommandLineInterface::handleCombinedJSON()
if (requests.count(g_strOpcodes))
contractData[g_strOpcodes] = solidity::disassemble(m_compiler->object(contractName).bytecode);
if (requests.count(g_strAsm))
{
ostringstream unused;
contractData[g_strAsm] = m_compiler->streamAssembly(unused, contractName, m_sourceCodes, true);
}
contractData[g_strAsm] = m_compiler->assemblyJSON(contractName, m_sourceCodes);
if (requests.count(g_strSrcMap))
{
auto map = m_compiler->sourceMapping(contractName);
@ -1150,16 +1147,19 @@ void CommandLineInterface::outputCompilationResults()
// do we need EVM assembly?
if (m_args.count(g_argAsm) || m_args.count(g_argAsmJson))
{
string ret;
if (m_args.count(g_argAsmJson))
ret = dev::jsonPrettyPrint(m_compiler->assemblyJSON(contract, m_sourceCodes));
else
ret = m_compiler->assemblyString(contract, m_sourceCodes);
if (m_args.count(g_argOutputDir))
{
stringstream data;
m_compiler->streamAssembly(data, contract, m_sourceCodes, m_args.count(g_argAsmJson));
createFile(m_compiler->filesystemFriendlyName(contract) + (m_args.count(g_argAsmJson) ? "_evm.json" : ".evm"), data.str());
createFile(m_compiler->filesystemFriendlyName(contract) + (m_args.count(g_argAsmJson) ? "_evm.json" : ".evm"), ret);
}
else
{
cout << "EVM assembly:" << endl;
m_compiler->streamAssembly(cout, contract, m_sourceCodes, m_args.count(g_argAsmJson));
cout << "EVM assembly:" << endl << ret << endl;
}
}