Browse Source

Merge pull request #1604 from LianaHus/sol_Machine_friendly_output

Sol machine friendly output
cl-refactor
chriseth 10 years ago
parent
commit
4fa948d10a
  1. 120
      libevmcore/Assembly.cpp
  2. 20
      libevmcore/Assembly.h
  3. 1
      libevmcore/CMakeLists.txt
  4. 1
      liblll/CMakeLists.txt
  5. 5
      libsolidity/Compiler.h
  6. 6
      libsolidity/CompilerContext.h
  7. 4
      libsolidity/CompilerStack.cpp
  8. 3
      libsolidity/CompilerStack.h
  9. 44
      solc/CommandLineInterface.cpp

120
libevmcore/Assembly.cpp

@ -24,7 +24,7 @@
#include <libdevcore/Log.h>
#include <libevmcore/CommonSubexpressionEliminator.h>
#include <libevmcore/ControlFlowGraph.h>
#include <json/json.h>
using namespace std;
using namespace dev;
using namespace dev::eth;
@ -65,6 +65,13 @@ void Assembly::append(Assembly const& _a, int _deposit)
}
}
string Assembly::out() const
{
stringstream ret;
stream(ret);
return ret.str();
}
unsigned Assembly::bytesRequired() const
{
for (unsigned br = 1;; ++br)
@ -101,7 +108,7 @@ string Assembly::getLocationFromSources(StringMap const& _sourceCodes, SourceLoc
return move(cut);
}
ostream& Assembly::stream(ostream& _out, string const& _prefix, StringMap const& _sourceCodes) const
ostream& Assembly::streamAsm(ostream& _out, string const& _prefix, StringMap const& _sourceCodes) const
{
_out << _prefix << ".code:" << endl;
for (AssemblyItem const& i: m_items)
@ -157,6 +164,115 @@ ostream& Assembly::stream(ostream& _out, string const& _prefix, StringMap const&
return _out;
}
Json::Value Assembly::createJsonValue(string _name, int _begin, int _end, string _value, string _jumpType) const
{
Json::Value value;
value["name"] = _name;
value["begin"] = _begin;
value["end"] = _end;
if (!_value.empty())
value["value"] = _value;
if (!_jumpType.empty())
value["jumpType"] = _jumpType;
return value;
}
string toStringInHex(u256 _value)
{
std::stringstream hexStr;
hexStr << hex << _value;
return hexStr.str();
}
Json::Value Assembly::streamAsmJson(ostream& _out, StringMap const& _sourceCodes) const
{
Json::Value root;
Json::Value collection(Json::arrayValue);
for (AssemblyItem const& i: m_items)
{
switch (i.type())
{
case Operation:
collection.append(
createJsonValue(instructionInfo(i.instruction()).name, i.getLocation().start, i.getLocation().end, i.getJumpTypeAsString()));
break;
case Push:
collection.append(
createJsonValue("PUSH", i.getLocation().start, i.getLocation().end, toStringInHex(i.data()), i.getJumpTypeAsString()));
break;
case PushString:
collection.append(
createJsonValue("PUSH tag", i.getLocation().start, i.getLocation().end, m_strings.at((h256)i.data())));
break;
case PushTag:
collection.append(
createJsonValue("PUSH [tag]", i.getLocation().start, i.getLocation().end, toStringInHex(i.data())));
break;
case PushSub:
collection.append(
createJsonValue("PUSH [$]", i.getLocation().start, i.getLocation().end, dev::toString(h256(i.data()))));
break;
case PushSubSize:
collection.append(
createJsonValue("PUSH #[$]", i.getLocation().start, i.getLocation().end, dev::toString(h256(i.data()))));
break;
case PushProgramSize:
collection.append(
createJsonValue("PUSHSIZE", i.getLocation().start, i.getLocation().end));
break;
case Tag:
{
collection.append(
createJsonValue("tag", i.getLocation().start, i.getLocation().end, string(i.data())));
collection.append(
createJsonValue("JUMDEST", i.getLocation().start, i.getLocation().end));
}
break;
case PushData:
{
Json::Value pushData;
pushData["name"] = "PUSH hex";
collection.append(createJsonValue("PUSH hex", i.getLocation().start, i.getLocation().end, toStringInHex(i.data())));
}
break;
default:
BOOST_THROW_EXCEPTION(InvalidOpcode());
}
}
root[".code"] = collection;
if (!m_data.empty() || !m_subs.empty())
{
Json::Value data;
for (auto const& i: m_data)
if (u256(i.first) >= m_subs.size())
data[toStringInHex((u256)i.first)] = toHex(i.second);
for (size_t i = 0; i < m_subs.size(); ++i)
{
std::stringstream hexStr;
hexStr << hex << i;
data[hexStr.str()] = m_subs[i].stream(_out, "", _sourceCodes, true);
}
root[".data"] = data;
_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)
{
m_deposit += _i.deposit();

20
libevmcore/Assembly.h

@ -29,7 +29,12 @@
#include <libevmcore/Instruction.h>
#include <libevmcore/AssemblyItem.h>
#include "Exceptions.h"
#include <json/json.h>
namespace Json
{
class Value;
}
namespace dev
{
namespace eth
@ -76,7 +81,7 @@ public:
void popTo(int _deposit) { while (m_deposit > _deposit) append(Instruction::POP); }
void injectStart(AssemblyItem const& _i);
std::string out() const { std::stringstream ret; stream(ret); return ret.str(); }
std::string out() const;
int deposit() const { return m_deposit; }
void adjustDeposit(int _adjustment) { m_deposit += _adjustment; if (asserts(m_deposit >= 0)) BOOST_THROW_EXCEPTION(InvalidDeposit()); }
void setDeposit(int _deposit) { m_deposit = _deposit; if (asserts(m_deposit >= 0)) BOOST_THROW_EXCEPTION(InvalidDeposit()); }
@ -86,13 +91,24 @@ public:
bytes assemble() const;
Assembly& optimise(bool _enable);
std::ostream& stream(std::ostream& _out, std::string const& _prefix = "", const StringMap &_sourceCodes = StringMap()) const;
Json::Value stream(
std::ostream& _out,
std::string const& _prefix = "",
const StringMap &_sourceCodes = StringMap(),
bool _inJsonFormat = false
) const;
protected:
std::string getLocationFromSources(StringMap const& _sourceCodes, SourceLocation const& _location) const;
void donePath() { if (m_totalDeposit != INT_MAX && m_totalDeposit != m_deposit) BOOST_THROW_EXCEPTION(InvalidDeposit()); }
unsigned bytesRequired() const;
private:
Json::Value streamAsmJson(std::ostream& _out, const StringMap &_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;
protected:
unsigned m_usedTags = 0;
AssemblyItems m_items;
mutable std::map<h256, bytes> m_data;

1
libevmcore/CMakeLists.txt

@ -11,6 +11,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB")
aux_source_directory(. SRC_LIST)
include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS})
include_directories(BEFORE ..)
include_directories(${Boost_INCLUDE_DIRS})

1
liblll/CMakeLists.txt

@ -11,6 +11,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB")
aux_source_directory(. SRC_LIST)
include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS})
include_directories(BEFORE ..)
include_directories(${Boost_INCLUDE_DIRS})

5
libsolidity/Compiler.h

@ -42,9 +42,10 @@ public:
bytes getAssembledBytecode() { return m_context.getAssembledBytecode(m_optimize); }
bytes getRuntimeBytecode() { return m_runtimeContext.getAssembledBytecode(m_optimize);}
/// @arg _sourceCodes is the map of input files to source code strings
void streamAssembly(std::ostream& _stream, StringMap const& _sourceCodes = StringMap()) const
/// @arg _inJsonFromat shows whether the out should be in Json format
void streamAssembly(std::ostream& _stream, StringMap const& _sourceCodes = StringMap(), bool _inJsonFormat = false) const
{
m_context.streamAssembly(_stream, _sourceCodes);
m_context.streamAssembly(_stream, _sourceCodes, _inJsonFormat);
}
/// @returns Assembly items of the normal compiler context
eth::AssemblyItems const& getAssemblyItems() const { return m_context.getAssembly().getItems(); }

6
libsolidity/CompilerContext.h

@ -122,7 +122,11 @@ public:
eth::Assembly const& getAssembly() const { return m_asm; }
/// @arg _sourceCodes is the map of input files to source code strings
void streamAssembly(std::ostream& _stream, StringMap const& _sourceCodes = StringMap()) const { m_asm.stream(_stream, "", _sourceCodes); }
/// @arg _inJsonFormat shows whether the out should be in Json format
void streamAssembly(std::ostream& _stream, StringMap const& _sourceCodes = StringMap(), bool _inJsonFormat = false) const
{
m_asm.stream(_stream, "", _sourceCodes, _inJsonFormat);
}
bytes getAssembledBytecode(bool _optimize = false) { return m_asm.optimise(_optimize).assemble(); }

4
libsolidity/CompilerStack.cpp

@ -184,11 +184,11 @@ dev::h256 CompilerStack::getContractCodeHash(string const& _contractName) const
return dev::sha3(getRuntimeBytecode(_contractName));
}
void CompilerStack::streamAssembly(ostream& _outStream, string const& _contractName, StringMap _sourceCodes) const
void CompilerStack::streamAssembly(ostream& _outStream, string const& _contractName, StringMap _sourceCodes, bool _inJsonFormat) const
{
Contract const& contract = getContract(_contractName);
if (contract.compiler)
getContract(_contractName).compiler->streamAssembly(_outStream, _sourceCodes);
contract.compiler->streamAssembly(_outStream, _sourceCodes, _inJsonFormat);
else
_outStream << "Contract not fully implemented" << endl;
}

3
libsolidity/CompilerStack.h

@ -102,8 +102,9 @@ public:
/// Streams a verbose version of the assembly to @a _outStream.
/// @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.
void streamAssembly(std::ostream& _outStream, std::string const& _contractName = "", StringMap _sourceCodes = StringMap()) const;
void streamAssembly(std::ostream& _outStream, std::string const& _contractName = "", StringMap _sourceCodes = StringMap(), bool _inJsonFormat = false) const;
/// Returns a string representing the contract interface in JSON.
/// Prerequisite: Successful call to parse or compile.

44
solc/CommandLineInterface.cpp

@ -55,6 +55,7 @@ namespace solidity
static string const g_argAbiStr = "json-abi";
static string const g_argSolAbiStr = "sol-abi";
static string const g_argAsmStr = "asm";
static string const g_argAsmJsonStr = "asm-json";
static string const g_argAstStr = "ast";
static string const g_argAstJson = "ast-json";
static string const g_argBinaryStr = "binary";
@ -80,10 +81,15 @@ static bool needStdout(po::variables_map const& _args)
{
return
argToStdout(_args, g_argAbiStr) || argToStdout(_args, g_argSolAbiStr) ||
argToStdout(_args, g_argNatspecUserStr) || argToStdout(_args, g_argAstJson) ||
argToStdout(_args, g_argNatspecDevStr) || argToStdout(_args, g_argAsmStr) ||
argToStdout(_args, g_argOpcodesStr) || argToStdout(_args, g_argBinaryStr);
argToStdout(_args, g_argAbiStr) ||
argToStdout(_args, g_argSolAbiStr) ||
argToStdout(_args, g_argNatspecUserStr) ||
argToStdout(_args, g_argAstJson) ||
argToStdout(_args, g_argNatspecDevStr) ||
argToStdout(_args, g_argAsmStr) ||
argToStdout(_args, g_argAsmJsonStr) ||
argToStdout(_args, g_argOpcodesStr) ||
argToStdout(_args, g_argBinaryStr);
}
static inline bool outputToFile(OutputType type)
@ -215,23 +221,25 @@ bool CommandLineInterface::parseArguments(int argc, char** argv)
("add-std", po::value<bool>()->default_value(false), "Add standard contracts")
("input-file", po::value<vector<string>>(), "input file")
(g_argAstStr.c_str(), po::value<OutputType>()->value_name("stdout|file|both"),
"Request to output the AST of the contract.")
"Request to output the AST of the contract.")
(g_argAstJson.c_str(), po::value<OutputType>()->value_name("stdout|file|both"),
"Request to output the AST of the contract in JSON format.")
"Request to output the AST of the contract in JSON format.")
(g_argAsmStr.c_str(), po::value<OutputType>()->value_name("stdout|file|both"),
"Request to output the EVM assembly of the contract.")
"Request to output the EVM assembly of the contract.")
(g_argAsmJsonStr.c_str(), po::value<OutputType>()->value_name("stdout|file|both"),
"Request to output the EVM assembly of the contract in JSON format.")
(g_argOpcodesStr.c_str(), po::value<OutputType>()->value_name("stdout|file|both"),
"Request to output the Opcodes of the contract.")
"Request to output the Opcodes of the contract.")
(g_argBinaryStr.c_str(), po::value<OutputType>()->value_name("stdout|file|both"),
"Request to output the contract in binary (hexadecimal).")
"Request to output the contract in binary (hexadecimal).")
(g_argAbiStr.c_str(), po::value<OutputType>()->value_name("stdout|file|both"),
"Request to output the contract's JSON ABI interface.")
"Request to output the contract's JSON ABI interface.")
(g_argSolAbiStr.c_str(), po::value<OutputType>()->value_name("stdout|file|both"),
"Request to output the contract's Solidity ABI interface.")
"Request to output the contract's Solidity ABI interface.")
(g_argNatspecUserStr.c_str(), po::value<OutputType>()->value_name("stdout|file|both"),
"Request to output the contract's Natspec user documentation.")
"Request to output the contract's Natspec user documentation.")
(g_argNatspecDevStr.c_str(), po::value<OutputType>()->value_name("stdout|file|both"),
"Request to output the contract's Natspec developer documentation.");
"Request to output the contract's Natspec developer documentation.");
// All positional options should be interpreted as input files
po::positional_options_description p;
@ -411,19 +419,19 @@ void CommandLineInterface::actOnInput()
cout << endl << "======= " << contract << " =======" << endl;
// do we need EVM assembly?
if (m_args.count(g_argAsmStr))
if (m_args.count(g_argAsmStr) || m_args.count(g_argAsmJsonStr))
{
auto choice = m_args[g_argAsmStr].as<OutputType>();
auto choice = m_args.count(g_argAsmStr) ? m_args[g_argAsmStr].as<OutputType>() : m_args[g_argAsmJsonStr].as<OutputType>();
if (outputToStdout(choice))
{
cout << "EVM assembly:" << endl;
m_compiler->streamAssembly(cout, contract, m_sourceCodes);
m_compiler->streamAssembly(cout, contract, m_sourceCodes, m_args.count(g_argAsmJsonStr));
}
if (outputToFile(choice))
{
ofstream outFile(contract + ".evm");
m_compiler->streamAssembly(outFile, contract, m_sourceCodes);
ofstream outFile(contract + (m_args.count(g_argAsmJsonStr) ? "_evm.json" : ".evm"));
m_compiler->streamAssembly(outFile, contract, m_sourceCodes, m_args.count(g_argAsmJsonStr));
outFile.close();
}
}

Loading…
Cancel
Save