Browse Source
Conflicts: alethzero/CMakeLists.txt cmake/EthDependenciesDeprecated.cmake libdevcrypto/CryptoPP.h libdevcrypto/EC.cpp third/CMakeLists.txtcl-refactor
sveneh
10 years ago
147 changed files with 10127 additions and 4247 deletions
@ -0,0 +1,36 @@ |
|||
/*
|
|||
This file is part of cpp-ethereum. |
|||
|
|||
cpp-ethereum is free software: you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation, either version 3 of the License, or |
|||
(at your option) any later version. |
|||
|
|||
cpp-ethereum is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/** @file OurWebThreeStubServer.h
|
|||
* @author Gav Wood <i@gavwood.com> |
|||
* @date 2014 |
|||
*/ |
|||
|
|||
#include "OurWebThreeStubServer.h" |
|||
using namespace std; |
|||
using namespace dev; |
|||
using namespace dev::eth; |
|||
|
|||
OurWebThreeStubServer::OurWebThreeStubServer(jsonrpc::AbstractServerConnector* _conn, dev::WebThreeDirect& _web3, std::vector<dev::KeyPair> const& _accounts): |
|||
WebThreeStubServer(_conn, _web3, _accounts) |
|||
{} |
|||
|
|||
std::string OurWebThreeStubServer::shh_newIdentity() |
|||
{ |
|||
dev::KeyPair kp = dev::KeyPair::create(); |
|||
emit onNewId(QString::fromStdString(toJS(kp.sec()))); |
|||
return toJS(kp.pub()); |
|||
} |
@ -0,0 +1,38 @@ |
|||
/*
|
|||
This file is part of cpp-ethereum. |
|||
|
|||
cpp-ethereum is free software: you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation, either version 3 of the License, or |
|||
(at your option) any later version. |
|||
|
|||
cpp-ethereum is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/** @file OurWebThreeStubServer.cpp
|
|||
* @author Gav Wood <i@gavwood.com> |
|||
* @date 2014 |
|||
*/ |
|||
|
|||
#include <QtCore/QObject> |
|||
#include <libdevcore/CommonJS.h> |
|||
#include <libdevcrypto/Common.h> |
|||
#include <libweb3jsonrpc/WebThreeStubServer.h> |
|||
|
|||
class OurWebThreeStubServer: public QObject, public WebThreeStubServer |
|||
{ |
|||
Q_OBJECT |
|||
|
|||
public: |
|||
OurWebThreeStubServer(jsonrpc::AbstractServerConnector* _conn, dev::WebThreeDirect& _web3, std::vector<dev::KeyPair> const& _accounts); |
|||
|
|||
virtual std::string shh_newIdentity() override; |
|||
|
|||
signals: |
|||
void onNewId(QString _s); |
|||
}; |
@ -0,0 +1,36 @@ |
|||
/*
|
|||
This file is part of cpp-ethereum. |
|||
|
|||
cpp-ethereum is free software: you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation, either version 3 of the License, or |
|||
(at your option) any later version. |
|||
|
|||
cpp-ethereum is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/** @file Exceptions.h
|
|||
* @author Christian <c@ethdev.com> |
|||
* @date 2014 |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <libdevcore/Exceptions.h> |
|||
|
|||
namespace dev |
|||
{ |
|||
namespace eth |
|||
{ |
|||
|
|||
struct AssemblyException: virtual Exception {}; |
|||
struct InvalidDeposit: virtual AssemblyException {}; |
|||
struct InvalidOpcode: virtual AssemblyException {}; |
|||
|
|||
} |
|||
} |
@ -0,0 +1,337 @@ |
|||
/*
|
|||
This file is part of cpp-ethereum. |
|||
|
|||
cpp-ethereum is free software: you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation, either version 3 of the License, or |
|||
(at your option) any later version. |
|||
|
|||
cpp-ethereum is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/** @file Instruction.cpp
|
|||
* @author Gav Wood <i@gavwood.com> |
|||
* @date 2014 |
|||
*/ |
|||
|
|||
#include "Instruction.h" |
|||
|
|||
#include <libdevcore/Common.h> |
|||
#include <libdevcore/CommonIO.h> |
|||
#include <libdevcore/Log.h> |
|||
using namespace std; |
|||
using namespace dev; |
|||
using namespace dev::eth; |
|||
|
|||
const std::map<std::string, Instruction> dev::eth::c_instructions = |
|||
{ |
|||
{ "STOP", Instruction::STOP }, |
|||
{ "ADD", Instruction::ADD }, |
|||
{ "SUB", Instruction::SUB }, |
|||
{ "MUL", Instruction::MUL }, |
|||
{ "DIV", Instruction::DIV }, |
|||
{ "SDIV", Instruction::SDIV }, |
|||
{ "MOD", Instruction::MOD }, |
|||
{ "SMOD", Instruction::SMOD }, |
|||
{ "EXP", Instruction::EXP }, |
|||
{ "BNOT", Instruction::NOT }, |
|||
{ "LT", Instruction::LT }, |
|||
{ "GT", Instruction::GT }, |
|||
{ "SLT", Instruction::SLT }, |
|||
{ "SGT", Instruction::SGT }, |
|||
{ "EQ", Instruction::EQ }, |
|||
{ "NOT", Instruction::ISZERO }, |
|||
{ "AND", Instruction::AND }, |
|||
{ "OR", Instruction::OR }, |
|||
{ "XOR", Instruction::XOR }, |
|||
{ "BYTE", Instruction::BYTE }, |
|||
{ "ADDMOD", Instruction::ADDMOD }, |
|||
{ "MULMOD", Instruction::MULMOD }, |
|||
{ "SIGNEXTEND", Instruction::SIGNEXTEND }, |
|||
{ "SHA3", Instruction::SHA3 }, |
|||
{ "ADDRESS", Instruction::ADDRESS }, |
|||
{ "BALANCE", Instruction::BALANCE }, |
|||
{ "ORIGIN", Instruction::ORIGIN }, |
|||
{ "CALLER", Instruction::CALLER }, |
|||
{ "CALLVALUE", Instruction::CALLVALUE }, |
|||
{ "CALLDATALOAD", Instruction::CALLDATALOAD }, |
|||
{ "CALLDATASIZE", Instruction::CALLDATASIZE }, |
|||
{ "CALLDATACOPY", Instruction::CALLDATACOPY }, |
|||
{ "CODESIZE", Instruction::CODESIZE }, |
|||
{ "CODECOPY", Instruction::CODECOPY }, |
|||
{ "GASPRICE", Instruction::GASPRICE }, |
|||
{ "EXTCODESIZE", Instruction::EXTCODESIZE }, |
|||
{ "EXTCODECOPY", Instruction::EXTCODECOPY }, |
|||
{ "PREVHASH", Instruction::PREVHASH }, |
|||
{ "COINBASE", Instruction::COINBASE }, |
|||
{ "TIMESTAMP", Instruction::TIMESTAMP }, |
|||
{ "NUMBER", Instruction::NUMBER }, |
|||
{ "DIFFICULTY", Instruction::DIFFICULTY }, |
|||
{ "GASLIMIT", Instruction::GASLIMIT }, |
|||
{ "POP", Instruction::POP }, |
|||
{ "MLOAD", Instruction::MLOAD }, |
|||
{ "MSTORE", Instruction::MSTORE }, |
|||
{ "MSTORE8", Instruction::MSTORE8 }, |
|||
{ "SLOAD", Instruction::SLOAD }, |
|||
{ "SSTORE", Instruction::SSTORE }, |
|||
{ "JUMP", Instruction::JUMP }, |
|||
{ "JUMPI", Instruction::JUMPI }, |
|||
{ "PC", Instruction::PC }, |
|||
{ "MSIZE", Instruction::MSIZE }, |
|||
{ "GAS", Instruction::GAS }, |
|||
{ "JUMPDEST", Instruction::JUMPDEST }, |
|||
{ "PUSH1", Instruction::PUSH1 }, |
|||
{ "PUSH2", Instruction::PUSH2 }, |
|||
{ "PUSH3", Instruction::PUSH3 }, |
|||
{ "PUSH4", Instruction::PUSH4 }, |
|||
{ "PUSH5", Instruction::PUSH5 }, |
|||
{ "PUSH6", Instruction::PUSH6 }, |
|||
{ "PUSH7", Instruction::PUSH7 }, |
|||
{ "PUSH8", Instruction::PUSH8 }, |
|||
{ "PUSH9", Instruction::PUSH9 }, |
|||
{ "PUSH10", Instruction::PUSH10 }, |
|||
{ "PUSH11", Instruction::PUSH11 }, |
|||
{ "PUSH12", Instruction::PUSH12 }, |
|||
{ "PUSH13", Instruction::PUSH13 }, |
|||
{ "PUSH14", Instruction::PUSH14 }, |
|||
{ "PUSH15", Instruction::PUSH15 }, |
|||
{ "PUSH16", Instruction::PUSH16 }, |
|||
{ "PUSH17", Instruction::PUSH17 }, |
|||
{ "PUSH18", Instruction::PUSH18 }, |
|||
{ "PUSH19", Instruction::PUSH19 }, |
|||
{ "PUSH20", Instruction::PUSH20 }, |
|||
{ "PUSH21", Instruction::PUSH21 }, |
|||
{ "PUSH22", Instruction::PUSH22 }, |
|||
{ "PUSH23", Instruction::PUSH23 }, |
|||
{ "PUSH24", Instruction::PUSH24 }, |
|||
{ "PUSH25", Instruction::PUSH25 }, |
|||
{ "PUSH26", Instruction::PUSH26 }, |
|||
{ "PUSH27", Instruction::PUSH27 }, |
|||
{ "PUSH28", Instruction::PUSH28 }, |
|||
{ "PUSH29", Instruction::PUSH29 }, |
|||
{ "PUSH30", Instruction::PUSH30 }, |
|||
{ "PUSH31", Instruction::PUSH31 }, |
|||
{ "PUSH32", Instruction::PUSH32 }, |
|||
{ "DUP1", Instruction::DUP1 }, |
|||
{ "DUP2", Instruction::DUP2 }, |
|||
{ "DUP3", Instruction::DUP3 }, |
|||
{ "DUP4", Instruction::DUP4 }, |
|||
{ "DUP5", Instruction::DUP5 }, |
|||
{ "DUP6", Instruction::DUP6 }, |
|||
{ "DUP7", Instruction::DUP7 }, |
|||
{ "DUP8", Instruction::DUP8 }, |
|||
{ "DUP9", Instruction::DUP9 }, |
|||
{ "DUP10", Instruction::DUP10 }, |
|||
{ "DUP11", Instruction::DUP11 }, |
|||
{ "DUP12", Instruction::DUP12 }, |
|||
{ "DUP13", Instruction::DUP13 }, |
|||
{ "DUP14", Instruction::DUP14 }, |
|||
{ "DUP15", Instruction::DUP15 }, |
|||
{ "DUP16", Instruction::DUP16 }, |
|||
{ "SWAP1", Instruction::SWAP1 }, |
|||
{ "SWAP2", Instruction::SWAP2 }, |
|||
{ "SWAP3", Instruction::SWAP3 }, |
|||
{ "SWAP4", Instruction::SWAP4 }, |
|||
{ "SWAP5", Instruction::SWAP5 }, |
|||
{ "SWAP6", Instruction::SWAP6 }, |
|||
{ "SWAP7", Instruction::SWAP7 }, |
|||
{ "SWAP8", Instruction::SWAP8 }, |
|||
{ "SWAP9", Instruction::SWAP9 }, |
|||
{ "SWAP10", Instruction::SWAP10 }, |
|||
{ "SWAP11", Instruction::SWAP11 }, |
|||
{ "SWAP12", Instruction::SWAP12 }, |
|||
{ "SWAP13", Instruction::SWAP13 }, |
|||
{ "SWAP14", Instruction::SWAP14 }, |
|||
{ "SWAP15", Instruction::SWAP15 }, |
|||
{ "SWAP16", Instruction::SWAP16 }, |
|||
{ "LOG0", Instruction::LOG0 }, |
|||
{ "LOG1", Instruction::LOG1 }, |
|||
{ "LOG2", Instruction::LOG2 }, |
|||
{ "LOG3", Instruction::LOG3 }, |
|||
{ "LOG4", Instruction::LOG4 }, |
|||
{ "CREATE", Instruction::CREATE }, |
|||
{ "CALL", Instruction::CALL }, |
|||
{ "CALLCODE", Instruction::CALLCODE }, |
|||
{ "RETURN", Instruction::RETURN }, |
|||
{ "SUICIDE", Instruction::SUICIDE } |
|||
}; |
|||
|
|||
static const std::map<Instruction, InstructionInfo> c_instructionInfo = |
|||
{ // Add, Args, Ret, SideEffects
|
|||
{ Instruction::STOP, { "STOP", 0, 0, 0, true } }, |
|||
{ Instruction::ADD, { "ADD", 0, 2, 1, false } }, |
|||
{ Instruction::SUB, { "SUB", 0, 2, 1, false } }, |
|||
{ Instruction::MUL, { "MUL", 0, 2, 1, false } }, |
|||
{ Instruction::DIV, { "DIV", 0, 2, 1, false } }, |
|||
{ Instruction::SDIV, { "SDIV", 0, 2, 1, false } }, |
|||
{ Instruction::MOD, { "MOD", 0, 2, 1, false } }, |
|||
{ Instruction::SMOD, { "SMOD", 0, 2, 1, false } }, |
|||
{ Instruction::EXP, { "EXP", 0, 2, 1, false } }, |
|||
{ Instruction::NOT, { "NOT", 0, 1, 1, false } }, |
|||
{ Instruction::LT, { "LT", 0, 2, 1, false } }, |
|||
{ Instruction::GT, { "GT", 0, 2, 1, false } }, |
|||
{ Instruction::SLT, { "SLT", 0, 2, 1, false } }, |
|||
{ Instruction::SGT, { "SGT", 0, 2, 1, false } }, |
|||
{ Instruction::EQ, { "EQ", 0, 2, 1, false } }, |
|||
{ Instruction::ISZERO, { "ISZERO", 0, 1, 1, false } }, |
|||
{ Instruction::AND, { "AND", 0, 2, 1, false } }, |
|||
{ Instruction::OR, { "OR", 0, 2, 1, false } }, |
|||
{ Instruction::XOR, { "XOR", 0, 2, 1, false } }, |
|||
{ Instruction::BYTE, { "BYTE", 0, 2, 1, false } }, |
|||
{ Instruction::ADDMOD, { "ADDMOD", 0, 3, 1, false } }, |
|||
{ Instruction::MULMOD, { "MULMOD", 0, 3, 1, false } }, |
|||
{ Instruction::SIGNEXTEND, { "SIGNEXTEND", 0, 2, 1, false } }, |
|||
{ Instruction::SHA3, { "SHA3", 0, 2, 1, false } }, |
|||
{ Instruction::ADDRESS, { "ADDRESS", 0, 0, 1, false } }, |
|||
{ Instruction::BALANCE, { "BALANCE", 0, 1, 1, false } }, |
|||
{ Instruction::ORIGIN, { "ORIGIN", 0, 0, 1, false } }, |
|||
{ Instruction::CALLER, { "CALLER", 0, 0, 1, false } }, |
|||
{ Instruction::CALLVALUE, { "CALLVALUE", 0, 0, 1, false } }, |
|||
{ Instruction::CALLDATALOAD,{ "CALLDATALOAD", 0, 1, 1, false } }, |
|||
{ Instruction::CALLDATASIZE,{ "CALLDATASIZE", 0, 0, 1, false } }, |
|||
{ Instruction::CALLDATACOPY,{ "CALLDATACOPY", 0, 3, 0, true } }, |
|||
{ Instruction::CODESIZE, { "CODESIZE", 0, 0, 1, false } }, |
|||
{ Instruction::CODECOPY, { "CODECOPY", 0, 3, 0, true } }, |
|||
{ Instruction::GASPRICE, { "GASPRICE", 0, 0, 1, false } }, |
|||
{ Instruction::EXTCODESIZE, { "EXTCODESIZE", 0, 1, 1, false } }, |
|||
{ Instruction::EXTCODECOPY, { "EXTCODECOPY", 0, 4, 0, true } }, |
|||
{ Instruction::PREVHASH, { "PREVHASH", 0, 0, 1, false } }, |
|||
{ Instruction::COINBASE, { "COINBASE", 0, 0, 1, false } }, |
|||
{ Instruction::TIMESTAMP, { "TIMESTAMP", 0, 0, 1, false } }, |
|||
{ Instruction::NUMBER, { "NUMBER", 0, 0, 1, false } }, |
|||
{ Instruction::DIFFICULTY, { "DIFFICULTY", 0, 0, 1, false } }, |
|||
{ Instruction::GASLIMIT, { "GASLIMIT", 0, 0, 1, false } }, |
|||
{ Instruction::POP, { "POP", 0, 1, 0, false } }, |
|||
{ Instruction::MLOAD, { "MLOAD", 0, 1, 1, false } }, |
|||
{ Instruction::MSTORE, { "MSTORE", 0, 2, 0, true } }, |
|||
{ Instruction::MSTORE8, { "MSTORE8", 0, 2, 0, true } }, |
|||
{ Instruction::SLOAD, { "SLOAD", 0, 1, 1, false } }, |
|||
{ Instruction::SSTORE, { "SSTORE", 0, 2, 0, true } }, |
|||
{ Instruction::JUMP, { "JUMP", 0, 1, 0, true } }, |
|||
{ Instruction::JUMPI, { "JUMPI", 0, 2, 0, true } }, |
|||
{ Instruction::PC, { "PC", 0, 0, 1, false } }, |
|||
{ Instruction::MSIZE, { "MSIZE", 0, 0, 1, false } }, |
|||
{ Instruction::GAS, { "GAS", 0, 0, 1, false } }, |
|||
{ Instruction::JUMPDEST, { "JUMPDEST", 0, 1, 0, true } }, |
|||
{ Instruction::PUSH1, { "PUSH1", 1, 0, 1, false } }, |
|||
{ Instruction::PUSH2, { "PUSH2", 2, 0, 1, false } }, |
|||
{ Instruction::PUSH3, { "PUSH3", 3, 0, 1, false } }, |
|||
{ Instruction::PUSH4, { "PUSH4", 4, 0, 1, false } }, |
|||
{ Instruction::PUSH5, { "PUSH5", 5, 0, 1, false } }, |
|||
{ Instruction::PUSH6, { "PUSH6", 6, 0, 1, false } }, |
|||
{ Instruction::PUSH7, { "PUSH7", 7, 0, 1, false } }, |
|||
{ Instruction::PUSH8, { "PUSH8", 8, 0, 1, false } }, |
|||
{ Instruction::PUSH9, { "PUSH9", 9, 0, 1, false } }, |
|||
{ Instruction::PUSH10, { "PUSH10", 10, 0, 1, false } }, |
|||
{ Instruction::PUSH11, { "PUSH11", 11, 0, 1, false } }, |
|||
{ Instruction::PUSH12, { "PUSH12", 12, 0, 1, false } }, |
|||
{ Instruction::PUSH13, { "PUSH13", 13, 0, 1, false } }, |
|||
{ Instruction::PUSH14, { "PUSH14", 14, 0, 1, false } }, |
|||
{ Instruction::PUSH15, { "PUSH15", 15, 0, 1, false } }, |
|||
{ Instruction::PUSH16, { "PUSH16", 16, 0, 1, false } }, |
|||
{ Instruction::PUSH17, { "PUSH17", 17, 0, 1, false } }, |
|||
{ Instruction::PUSH18, { "PUSH18", 18, 0, 1, false } }, |
|||
{ Instruction::PUSH19, { "PUSH19", 19, 0, 1, false } }, |
|||
{ Instruction::PUSH20, { "PUSH20", 20, 0, 1, false } }, |
|||
{ Instruction::PUSH21, { "PUSH21", 21, 0, 1, false } }, |
|||
{ Instruction::PUSH22, { "PUSH22", 22, 0, 1, false } }, |
|||
{ Instruction::PUSH23, { "PUSH23", 23, 0, 1, false } }, |
|||
{ Instruction::PUSH24, { "PUSH24", 24, 0, 1, false } }, |
|||
{ Instruction::PUSH25, { "PUSH25", 25, 0, 1, false } }, |
|||
{ Instruction::PUSH26, { "PUSH26", 26, 0, 1, false } }, |
|||
{ Instruction::PUSH27, { "PUSH27", 27, 0, 1, false } }, |
|||
{ Instruction::PUSH28, { "PUSH28", 28, 0, 1, false } }, |
|||
{ Instruction::PUSH29, { "PUSH29", 29, 0, 1, false } }, |
|||
{ Instruction::PUSH30, { "PUSH30", 30, 0, 1, false } }, |
|||
{ Instruction::PUSH31, { "PUSH31", 31, 0, 1, false } }, |
|||
{ Instruction::PUSH32, { "PUSH32", 32, 0, 1, false } }, |
|||
{ Instruction::DUP1, { "DUP1", 0, 1, 2, false } }, |
|||
{ Instruction::DUP2, { "DUP2", 0, 2, 3, false } }, |
|||
{ Instruction::DUP3, { "DUP3", 0, 3, 4, false } }, |
|||
{ Instruction::DUP4, { "DUP4", 0, 4, 5, false } }, |
|||
{ Instruction::DUP5, { "DUP5", 0, 5, 6, false } }, |
|||
{ Instruction::DUP6, { "DUP6", 0, 6, 7, false } }, |
|||
{ Instruction::DUP7, { "DUP7", 0, 7, 8, false } }, |
|||
{ Instruction::DUP8, { "DUP8", 0, 8, 9, false } }, |
|||
{ Instruction::DUP9, { "DUP9", 0, 9, 10, false } }, |
|||
{ Instruction::DUP10, { "DUP10", 0, 10, 11, false } }, |
|||
{ Instruction::DUP11, { "DUP11", 0, 11, 12, false } }, |
|||
{ Instruction::DUP12, { "DUP12", 0, 12, 13, false } }, |
|||
{ Instruction::DUP13, { "DUP13", 0, 13, 14, false } }, |
|||
{ Instruction::DUP14, { "DUP14", 0, 14, 15, false } }, |
|||
{ Instruction::DUP15, { "DUP15", 0, 15, 16, false } }, |
|||
{ Instruction::DUP16, { "DUP16", 0, 16, 17, false } }, |
|||
{ Instruction::SWAP1, { "SWAP1", 0, 2, 2, false } }, |
|||
{ Instruction::SWAP2, { "SWAP2", 0, 3, 3, false } }, |
|||
{ Instruction::SWAP3, { "SWAP3", 0, 4, 4, false } }, |
|||
{ Instruction::SWAP4, { "SWAP4", 0, 5, 5, false } }, |
|||
{ Instruction::SWAP5, { "SWAP5", 0, 6, 6, false } }, |
|||
{ Instruction::SWAP6, { "SWAP6", 0, 7, 7, false } }, |
|||
{ Instruction::SWAP7, { "SWAP7", 0, 8, 8, false } }, |
|||
{ Instruction::SWAP8, { "SWAP8", 0, 9, 9, false } }, |
|||
{ Instruction::SWAP9, { "SWAP9", 0, 10, 10, false } }, |
|||
{ Instruction::SWAP10, { "SWAP10", 0, 11, 11, false } }, |
|||
{ Instruction::SWAP11, { "SWAP11", 0, 12, 12, false } }, |
|||
{ Instruction::SWAP12, { "SWAP12", 0, 13, 13, false } }, |
|||
{ Instruction::SWAP13, { "SWAP13", 0, 14, 14, false } }, |
|||
{ Instruction::SWAP14, { "SWAP14", 0, 15, 15, false } }, |
|||
{ Instruction::SWAP15, { "SWAP15", 0, 16, 16, false } }, |
|||
{ Instruction::SWAP16, { "SWAP16", 0, 17, 17, false } }, |
|||
{ Instruction::LOG0, { "LOG0", 0, 1, 0, true } }, |
|||
{ Instruction::LOG1, { "LOG1", 0, 2, 0, true } }, |
|||
{ Instruction::LOG2, { "LOG2", 0, 3, 0, true } }, |
|||
{ Instruction::LOG3, { "LOG3", 0, 4, 0, true } }, |
|||
{ Instruction::LOG4, { "LOG4", 0, 5, 0, true } }, |
|||
{ Instruction::CREATE, { "CREATE", 0, 3, 1, true } }, |
|||
{ Instruction::CALL, { "CALL", 0, 7, 1, true } }, |
|||
{ Instruction::CALLCODE, { "CALLCODE", 0, 7, 1, true } }, |
|||
{ Instruction::RETURN, { "RETURN", 0, 2, 0, true } }, |
|||
{ Instruction::SUICIDE, { "SUICIDE", 0, 1, 0, true } } |
|||
}; |
|||
|
|||
string dev::eth::disassemble(bytes const& _mem) |
|||
{ |
|||
stringstream ret; |
|||
unsigned numerics = 0; |
|||
for (auto it = _mem.begin(); it != _mem.end(); ++it) |
|||
{ |
|||
byte n = *it; |
|||
auto iit = c_instructionInfo.find((Instruction)n); |
|||
if (numerics || iit == c_instructionInfo.end() || (byte)iit->first != n) // not an instruction or expecting an argument...
|
|||
{ |
|||
if (numerics) |
|||
numerics--; |
|||
ret << "0x" << hex << (int)n << " "; |
|||
} |
|||
else |
|||
{ |
|||
auto const& ii = iit->second; |
|||
ret << ii.name << " "; |
|||
numerics = ii.additional; |
|||
} |
|||
} |
|||
return ret.str(); |
|||
} |
|||
|
|||
InstructionInfo dev::eth::instructionInfo(Instruction _inst) |
|||
{ |
|||
try |
|||
{ |
|||
return c_instructionInfo.at(_inst); |
|||
} |
|||
catch (...) |
|||
{ |
|||
cwarn << "<INVALID_INSTRUCTION: " << toString((unsigned)_inst) << ">\n" << boost::current_exception_diagnostic_information(); |
|||
return InstructionInfo({"<INVALID_INSTRUCTION: " + toString((unsigned)_inst) + ">", 0, 0, 0, false}); |
|||
} |
|||
} |
|||
|
|||
bool dev::eth::isValidInstruction(Instruction _inst) |
|||
{ |
|||
return !!c_instructionInfo.count(_inst); |
|||
} |
@ -1,337 +0,0 @@ |
|||
/*
|
|||
This file is part of cpp-ethereum. |
|||
|
|||
cpp-ethereum is free software: you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation, either version 3 of the License, or |
|||
(at your option) any later version. |
|||
|
|||
cpp-ethereum is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/** @file Instruction.cpp
|
|||
* @author Gav Wood <i@gavwood.com> |
|||
* @date 2014 |
|||
*/ |
|||
|
|||
#include "Instruction.h" |
|||
|
|||
#include <libdevcore/Common.h> |
|||
#include <libdevcore/CommonIO.h> |
|||
#include <libdevcore/Log.h> |
|||
using namespace std; |
|||
using namespace dev; |
|||
using namespace dev::eth; |
|||
|
|||
const std::map<std::string, Instruction> dev::eth::c_instructions = |
|||
{ |
|||
{ "STOP", Instruction::STOP }, |
|||
{ "ADD", Instruction::ADD }, |
|||
{ "SUB", Instruction::SUB }, |
|||
{ "MUL", Instruction::MUL }, |
|||
{ "DIV", Instruction::DIV }, |
|||
{ "SDIV", Instruction::SDIV }, |
|||
{ "MOD", Instruction::MOD }, |
|||
{ "SMOD", Instruction::SMOD }, |
|||
{ "EXP", Instruction::EXP }, |
|||
{ "BNOT", Instruction::NOT }, |
|||
{ "LT", Instruction::LT }, |
|||
{ "GT", Instruction::GT }, |
|||
{ "SLT", Instruction::SLT }, |
|||
{ "SGT", Instruction::SGT }, |
|||
{ "EQ", Instruction::EQ }, |
|||
{ "NOT", Instruction::ISZERO }, |
|||
{ "AND", Instruction::AND }, |
|||
{ "OR", Instruction::OR }, |
|||
{ "XOR", Instruction::XOR }, |
|||
{ "BYTE", Instruction::BYTE }, |
|||
{ "ADDMOD", Instruction::ADDMOD }, |
|||
{ "MULMOD", Instruction::MULMOD }, |
|||
{ "SIGNEXTEND", Instruction::SIGNEXTEND }, |
|||
{ "SHA3", Instruction::SHA3 }, |
|||
{ "ADDRESS", Instruction::ADDRESS }, |
|||
{ "BALANCE", Instruction::BALANCE }, |
|||
{ "ORIGIN", Instruction::ORIGIN }, |
|||
{ "CALLER", Instruction::CALLER }, |
|||
{ "CALLVALUE", Instruction::CALLVALUE }, |
|||
{ "CALLDATALOAD", Instruction::CALLDATALOAD }, |
|||
{ "CALLDATASIZE", Instruction::CALLDATASIZE }, |
|||
{ "CALLDATACOPY", Instruction::CALLDATACOPY }, |
|||
{ "CODESIZE", Instruction::CODESIZE }, |
|||
{ "CODECOPY", Instruction::CODECOPY }, |
|||
{ "GASPRICE", Instruction::GASPRICE }, |
|||
{ "EXTCODESIZE", Instruction::EXTCODESIZE }, |
|||
{ "EXTCODECOPY", Instruction::EXTCODECOPY }, |
|||
{ "PREVHASH", Instruction::PREVHASH }, |
|||
{ "COINBASE", Instruction::COINBASE }, |
|||
{ "TIMESTAMP", Instruction::TIMESTAMP }, |
|||
{ "NUMBER", Instruction::NUMBER }, |
|||
{ "DIFFICULTY", Instruction::DIFFICULTY }, |
|||
{ "GASLIMIT", Instruction::GASLIMIT }, |
|||
{ "POP", Instruction::POP }, |
|||
{ "MLOAD", Instruction::MLOAD }, |
|||
{ "MSTORE", Instruction::MSTORE }, |
|||
{ "MSTORE8", Instruction::MSTORE8 }, |
|||
{ "SLOAD", Instruction::SLOAD }, |
|||
{ "SSTORE", Instruction::SSTORE }, |
|||
{ "JUMP", Instruction::JUMP }, |
|||
{ "JUMPI", Instruction::JUMPI }, |
|||
{ "PC", Instruction::PC }, |
|||
{ "MSIZE", Instruction::MSIZE }, |
|||
{ "GAS", Instruction::GAS }, |
|||
{ "JUMPDEST", Instruction::JUMPDEST }, |
|||
{ "PUSH1", Instruction::PUSH1 }, |
|||
{ "PUSH2", Instruction::PUSH2 }, |
|||
{ "PUSH3", Instruction::PUSH3 }, |
|||
{ "PUSH4", Instruction::PUSH4 }, |
|||
{ "PUSH5", Instruction::PUSH5 }, |
|||
{ "PUSH6", Instruction::PUSH6 }, |
|||
{ "PUSH7", Instruction::PUSH7 }, |
|||
{ "PUSH8", Instruction::PUSH8 }, |
|||
{ "PUSH9", Instruction::PUSH9 }, |
|||
{ "PUSH10", Instruction::PUSH10 }, |
|||
{ "PUSH11", Instruction::PUSH11 }, |
|||
{ "PUSH12", Instruction::PUSH12 }, |
|||
{ "PUSH13", Instruction::PUSH13 }, |
|||
{ "PUSH14", Instruction::PUSH14 }, |
|||
{ "PUSH15", Instruction::PUSH15 }, |
|||
{ "PUSH16", Instruction::PUSH16 }, |
|||
{ "PUSH17", Instruction::PUSH17 }, |
|||
{ "PUSH18", Instruction::PUSH18 }, |
|||
{ "PUSH19", Instruction::PUSH19 }, |
|||
{ "PUSH20", Instruction::PUSH20 }, |
|||
{ "PUSH21", Instruction::PUSH21 }, |
|||
{ "PUSH22", Instruction::PUSH22 }, |
|||
{ "PUSH23", Instruction::PUSH23 }, |
|||
{ "PUSH24", Instruction::PUSH24 }, |
|||
{ "PUSH25", Instruction::PUSH25 }, |
|||
{ "PUSH26", Instruction::PUSH26 }, |
|||
{ "PUSH27", Instruction::PUSH27 }, |
|||
{ "PUSH28", Instruction::PUSH28 }, |
|||
{ "PUSH29", Instruction::PUSH29 }, |
|||
{ "PUSH30", Instruction::PUSH30 }, |
|||
{ "PUSH31", Instruction::PUSH31 }, |
|||
{ "PUSH32", Instruction::PUSH32 }, |
|||
{ "DUP1", Instruction::DUP1 }, |
|||
{ "DUP2", Instruction::DUP2 }, |
|||
{ "DUP3", Instruction::DUP3 }, |
|||
{ "DUP4", Instruction::DUP4 }, |
|||
{ "DUP5", Instruction::DUP5 }, |
|||
{ "DUP6", Instruction::DUP6 }, |
|||
{ "DUP7", Instruction::DUP7 }, |
|||
{ "DUP8", Instruction::DUP8 }, |
|||
{ "DUP9", Instruction::DUP9 }, |
|||
{ "DUP10", Instruction::DUP10 }, |
|||
{ "DUP11", Instruction::DUP11 }, |
|||
{ "DUP12", Instruction::DUP12 }, |
|||
{ "DUP13", Instruction::DUP13 }, |
|||
{ "DUP14", Instruction::DUP14 }, |
|||
{ "DUP15", Instruction::DUP15 }, |
|||
{ "DUP16", Instruction::DUP16 }, |
|||
{ "SWAP1", Instruction::SWAP1 }, |
|||
{ "SWAP2", Instruction::SWAP2 }, |
|||
{ "SWAP3", Instruction::SWAP3 }, |
|||
{ "SWAP4", Instruction::SWAP4 }, |
|||
{ "SWAP5", Instruction::SWAP5 }, |
|||
{ "SWAP6", Instruction::SWAP6 }, |
|||
{ "SWAP7", Instruction::SWAP7 }, |
|||
{ "SWAP8", Instruction::SWAP8 }, |
|||
{ "SWAP9", Instruction::SWAP9 }, |
|||
{ "SWAP10", Instruction::SWAP10 }, |
|||
{ "SWAP11", Instruction::SWAP11 }, |
|||
{ "SWAP12", Instruction::SWAP12 }, |
|||
{ "SWAP13", Instruction::SWAP13 }, |
|||
{ "SWAP14", Instruction::SWAP14 }, |
|||
{ "SWAP15", Instruction::SWAP15 }, |
|||
{ "SWAP16", Instruction::SWAP16 }, |
|||
{ "LOG0", Instruction::LOG0 }, |
|||
{ "LOG1", Instruction::LOG1 }, |
|||
{ "LOG2", Instruction::LOG2 }, |
|||
{ "LOG3", Instruction::LOG3 }, |
|||
{ "LOG4", Instruction::LOG4 }, |
|||
{ "CREATE", Instruction::CREATE }, |
|||
{ "CALL", Instruction::CALL }, |
|||
{ "CALLCODE", Instruction::CALLCODE }, |
|||
{ "RETURN", Instruction::RETURN }, |
|||
{ "SUICIDE", Instruction::SUICIDE } |
|||
}; |
|||
|
|||
static const std::map<Instruction, InstructionInfo> c_instructionInfo = |
|||
{ // Add, Args, Ret
|
|||
{ Instruction::STOP, { "STOP", 0, 0, 0 } }, |
|||
{ Instruction::ADD, { "ADD", 0, 2, 1 } }, |
|||
{ Instruction::SUB, { "SUB", 0, 2, 1 } }, |
|||
{ Instruction::MUL, { "MUL", 0, 2, 1 } }, |
|||
{ Instruction::DIV, { "DIV", 0, 2, 1 } }, |
|||
{ Instruction::SDIV, { "SDIV", 0, 2, 1 } }, |
|||
{ Instruction::MOD, { "MOD", 0, 2, 1 } }, |
|||
{ Instruction::SMOD, { "SMOD", 0, 2, 1 } }, |
|||
{ Instruction::EXP, { "EXP", 0, 2, 1 } }, |
|||
{ Instruction::NOT, { "BNOT", 0, 1, 1 } }, |
|||
{ Instruction::LT, { "LT", 0, 2, 1 } }, |
|||
{ Instruction::GT, { "GT", 0, 2, 1 } }, |
|||
{ Instruction::SLT, { "SLT", 0, 2, 1 } }, |
|||
{ Instruction::SGT, { "SGT", 0, 2, 1 } }, |
|||
{ Instruction::EQ, { "EQ", 0, 2, 1 } }, |
|||
{ Instruction::ISZERO, { "NOT", 0, 1, 1 } }, |
|||
{ Instruction::AND, { "AND", 0, 2, 1 } }, |
|||
{ Instruction::OR, { "OR", 0, 2, 1 } }, |
|||
{ Instruction::XOR, { "XOR", 0, 2, 1 } }, |
|||
{ Instruction::BYTE, { "BYTE", 0, 2, 1 } }, |
|||
{ Instruction::ADDMOD, { "ADDMOD", 0, 3, 1 } }, |
|||
{ Instruction::MULMOD, { "MULMOD", 0, 3, 1 } }, |
|||
{ Instruction::SIGNEXTEND, { "SIGNEXTEND", 0, 2, 1 } }, |
|||
{ Instruction::SHA3, { "SHA3", 0, 2, 1 } }, |
|||
{ Instruction::ADDRESS, { "ADDRESS", 0, 0, 1 } }, |
|||
{ Instruction::BALANCE, { "BALANCE", 0, 1, 1 } }, |
|||
{ Instruction::ORIGIN, { "ORIGIN", 0, 0, 1 } }, |
|||
{ Instruction::CALLER, { "CALLER", 0, 0, 1 } }, |
|||
{ Instruction::CALLVALUE, { "CALLVALUE", 0, 0, 1 } }, |
|||
{ Instruction::CALLDATALOAD,{ "CALLDATALOAD", 0, 1, 1 } }, |
|||
{ Instruction::CALLDATASIZE,{ "CALLDATASIZE", 0, 0, 1 } }, |
|||
{ Instruction::CALLDATACOPY,{ "CALLDATACOPY", 0, 3, 0 } }, |
|||
{ Instruction::CODESIZE, { "CODESIZE", 0, 0, 1 } }, |
|||
{ Instruction::CODECOPY, { "CODECOPY", 0, 3, 0 } }, |
|||
{ Instruction::GASPRICE, { "GASPRICE", 0, 0, 1 } }, |
|||
{ Instruction::EXTCODESIZE, { "EXTCODESIZE", 0, 1, 1 } }, |
|||
{ Instruction::EXTCODECOPY, { "EXTCODECOPY", 0, 4, 0 } }, |
|||
{ Instruction::PREVHASH, { "PREVHASH", 0, 0, 1 } }, |
|||
{ Instruction::COINBASE, { "COINBASE", 0, 0, 1 } }, |
|||
{ Instruction::TIMESTAMP, { "TIMESTAMP", 0, 0, 1 } }, |
|||
{ Instruction::NUMBER, { "NUMBER", 0, 0, 1 } }, |
|||
{ Instruction::DIFFICULTY, { "DIFFICULTY", 0, 0, 1 } }, |
|||
{ Instruction::GASLIMIT, { "GASLIMIT", 0, 0, 1 } }, |
|||
{ Instruction::POP, { "POP", 0, 1, 0 } }, |
|||
{ Instruction::MLOAD, { "MLOAD", 0, 1, 1 } }, |
|||
{ Instruction::MSTORE, { "MSTORE", 0, 2, 0 } }, |
|||
{ Instruction::MSTORE8, { "MSTORE8", 0, 2, 0 } }, |
|||
{ Instruction::SLOAD, { "SLOAD", 0, 1, 1 } }, |
|||
{ Instruction::SSTORE, { "SSTORE", 0, 2, 0 } }, |
|||
{ Instruction::JUMP, { "JUMP", 0, 1, 0 } }, |
|||
{ Instruction::JUMPI, { "JUMPI", 0, 2, 0 } }, |
|||
{ Instruction::PC, { "PC", 0, 0, 1 } }, |
|||
{ Instruction::MSIZE, { "MSIZE", 0, 0, 1 } }, |
|||
{ Instruction::GAS, { "GAS", 0, 0, 1 } }, |
|||
{ Instruction::JUMPDEST, { "JUMPDEST", 0, 1, 0 } }, |
|||
{ Instruction::PUSH1, { "PUSH1", 1, 0, 1 } }, |
|||
{ Instruction::PUSH2, { "PUSH2", 2, 0, 1 } }, |
|||
{ Instruction::PUSH3, { "PUSH3", 3, 0, 1 } }, |
|||
{ Instruction::PUSH4, { "PUSH4", 4, 0, 1 } }, |
|||
{ Instruction::PUSH5, { "PUSH5", 5, 0, 1 } }, |
|||
{ Instruction::PUSH6, { "PUSH6", 6, 0, 1 } }, |
|||
{ Instruction::PUSH7, { "PUSH7", 7, 0, 1 } }, |
|||
{ Instruction::PUSH8, { "PUSH8", 8, 0, 1 } }, |
|||
{ Instruction::PUSH9, { "PUSH9", 9, 0, 1 } }, |
|||
{ Instruction::PUSH10, { "PUSH10", 10, 0, 1 } }, |
|||
{ Instruction::PUSH11, { "PUSH11", 11, 0, 1 } }, |
|||
{ Instruction::PUSH12, { "PUSH12", 12, 0, 1 } }, |
|||
{ Instruction::PUSH13, { "PUSH13", 13, 0, 1 } }, |
|||
{ Instruction::PUSH14, { "PUSH14", 14, 0, 1 } }, |
|||
{ Instruction::PUSH15, { "PUSH15", 15, 0, 1 } }, |
|||
{ Instruction::PUSH16, { "PUSH16", 16, 0, 1 } }, |
|||
{ Instruction::PUSH17, { "PUSH17", 17, 0, 1 } }, |
|||
{ Instruction::PUSH18, { "PUSH18", 18, 0, 1 } }, |
|||
{ Instruction::PUSH19, { "PUSH19", 19, 0, 1 } }, |
|||
{ Instruction::PUSH20, { "PUSH20", 20, 0, 1 } }, |
|||
{ Instruction::PUSH21, { "PUSH21", 21, 0, 1 } }, |
|||
{ Instruction::PUSH22, { "PUSH22", 22, 0, 1 } }, |
|||
{ Instruction::PUSH23, { "PUSH23", 23, 0, 1 } }, |
|||
{ Instruction::PUSH24, { "PUSH24", 24, 0, 1 } }, |
|||
{ Instruction::PUSH25, { "PUSH25", 25, 0, 1 } }, |
|||
{ Instruction::PUSH26, { "PUSH26", 26, 0, 1 } }, |
|||
{ Instruction::PUSH27, { "PUSH27", 27, 0, 1 } }, |
|||
{ Instruction::PUSH28, { "PUSH28", 28, 0, 1 } }, |
|||
{ Instruction::PUSH29, { "PUSH29", 29, 0, 1 } }, |
|||
{ Instruction::PUSH30, { "PUSH30", 30, 0, 1 } }, |
|||
{ Instruction::PUSH31, { "PUSH31", 31, 0, 1 } }, |
|||
{ Instruction::PUSH32, { "PUSH32", 32, 0, 1 } }, |
|||
{ Instruction::DUP1, { "DUP1", 0, 1, 2 } }, |
|||
{ Instruction::DUP2, { "DUP2", 0, 2, 3 } }, |
|||
{ Instruction::DUP3, { "DUP3", 0, 3, 4 } }, |
|||
{ Instruction::DUP4, { "DUP4", 0, 4, 5 } }, |
|||
{ Instruction::DUP5, { "DUP5", 0, 5, 6 } }, |
|||
{ Instruction::DUP6, { "DUP6", 0, 6, 7 } }, |
|||
{ Instruction::DUP7, { "DUP7", 0, 7, 8 } }, |
|||
{ Instruction::DUP8, { "DUP8", 0, 8, 9 } }, |
|||
{ Instruction::DUP9, { "DUP9", 0, 9, 10 } }, |
|||
{ Instruction::DUP10, { "DUP10", 0, 10, 11 } }, |
|||
{ Instruction::DUP11, { "DUP11", 0, 11, 12 } }, |
|||
{ Instruction::DUP12, { "DUP12", 0, 12, 13 } }, |
|||
{ Instruction::DUP13, { "DUP13", 0, 13, 14 } }, |
|||
{ Instruction::DUP14, { "DUP14", 0, 14, 15 } }, |
|||
{ Instruction::DUP15, { "DUP15", 0, 15, 16 } }, |
|||
{ Instruction::DUP16, { "DUP16", 0, 16, 17 } }, |
|||
{ Instruction::SWAP1, { "SWAP1", 0, 2, 2 } }, |
|||
{ Instruction::SWAP2, { "SWAP2", 0, 3, 3 } }, |
|||
{ Instruction::SWAP3, { "SWAP3", 0, 4, 4 } }, |
|||
{ Instruction::SWAP4, { "SWAP4", 0, 5, 5 } }, |
|||
{ Instruction::SWAP5, { "SWAP5", 0, 6, 6 } }, |
|||
{ Instruction::SWAP6, { "SWAP6", 0, 7, 7 } }, |
|||
{ Instruction::SWAP7, { "SWAP7", 0, 8, 8 } }, |
|||
{ Instruction::SWAP8, { "SWAP8", 0, 9, 9 } }, |
|||
{ Instruction::SWAP9, { "SWAP9", 0, 10, 10 } }, |
|||
{ Instruction::SWAP10, { "SWAP10", 0, 11, 11 } }, |
|||
{ Instruction::SWAP11, { "SWAP11", 0, 12, 12 } }, |
|||
{ Instruction::SWAP12, { "SWAP12", 0, 13, 13 } }, |
|||
{ Instruction::SWAP13, { "SWAP13", 0, 14, 14 } }, |
|||
{ Instruction::SWAP14, { "SWAP14", 0, 15, 15 } }, |
|||
{ Instruction::SWAP15, { "SWAP15", 0, 16, 16 } }, |
|||
{ Instruction::SWAP16, { "SWAP16", 0, 17, 17 } }, |
|||
{ Instruction::LOG0, { "LOG0", 0, 1, 0 } }, |
|||
{ Instruction::LOG1, { "LOG1", 0, 2, 0 } }, |
|||
{ Instruction::LOG2, { "LOG2", 0, 3, 0 } }, |
|||
{ Instruction::LOG3, { "LOG3", 0, 4, 0 } }, |
|||
{ Instruction::LOG4, { "LOG4", 0, 5, 0 } }, |
|||
{ Instruction::CREATE, { "CREATE", 0, 3, 1 } }, |
|||
{ Instruction::CALL, { "CALL", 0, 7, 1 } }, |
|||
{ Instruction::CALLCODE, { "CALLCODE", 0, 7, 1 } }, |
|||
{ Instruction::RETURN, { "RETURN", 0, 2, 0 } }, |
|||
{ Instruction::SUICIDE, { "SUICIDE", 0, 1, 0} } |
|||
}; |
|||
|
|||
string dev::eth::disassemble(bytes const& _mem) |
|||
{ |
|||
stringstream ret; |
|||
unsigned numerics = 0; |
|||
for (auto it = _mem.begin(); it != _mem.end(); ++it) |
|||
{ |
|||
byte n = *it; |
|||
auto iit = c_instructionInfo.find((Instruction)n); |
|||
if (numerics || iit == c_instructionInfo.end() || (byte)iit->first != n) // not an instruction or expecting an argument...
|
|||
{ |
|||
if (numerics) |
|||
numerics--; |
|||
ret << "0x" << hex << (int)n << " "; |
|||
} |
|||
else |
|||
{ |
|||
auto const& ii = iit->second; |
|||
ret << ii.name << " "; |
|||
numerics = ii.additional; |
|||
} |
|||
} |
|||
return ret.str(); |
|||
} |
|||
|
|||
InstructionInfo dev::eth::instructionInfo(Instruction _inst) |
|||
{ |
|||
try |
|||
{ |
|||
return c_instructionInfo.at(_inst); |
|||
} |
|||
catch (...) |
|||
{ |
|||
cwarn << "<INVALID_INSTRUCTION: " << toString((unsigned)_inst) << ">\n" << boost::current_exception_diagnostic_information(); |
|||
return InstructionInfo({"<INVALID_INSTRUCTION: " + toString((unsigned)_inst) + ">", 0, 0, 0}); |
|||
} |
|||
} |
|||
|
|||
bool dev::eth::isValidInstruction(Instruction _inst) |
|||
{ |
|||
return !!c_instructionInfo.count(_inst); |
|||
} |
File diff suppressed because it is too large
@ -0,0 +1,87 @@ |
|||
/*
|
|||
This file is part of cpp-ethereum. |
|||
|
|||
cpp-ethereum is free software: you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation, either version 3 of the License, or |
|||
(at your option) any later version. |
|||
|
|||
cpp-ethereum is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/**
|
|||
* @author Christian <c@ethdev.com> |
|||
* @date 2014 |
|||
* Utilities for the solidity compiler. |
|||
*/ |
|||
|
|||
#include <utility> |
|||
#include <numeric> |
|||
#include <libsolidity/AST.h> |
|||
#include <libsolidity/Compiler.h> |
|||
|
|||
using namespace std; |
|||
|
|||
namespace dev { |
|||
namespace solidity { |
|||
|
|||
void CompilerContext::addStateVariable(VariableDeclaration const& _declaration) |
|||
{ |
|||
m_stateVariables[&_declaration] = m_stateVariablesSize; |
|||
m_stateVariablesSize += _declaration.getType()->getStorageSize(); |
|||
} |
|||
|
|||
void CompilerContext::initializeLocalVariables(unsigned _numVariables) |
|||
{ |
|||
if (_numVariables > 0) |
|||
{ |
|||
*this << u256(0); |
|||
for (unsigned i = 1; i < _numVariables; ++i) |
|||
*this << eth::Instruction::DUP1; |
|||
m_asm.adjustDeposit(-_numVariables); |
|||
} |
|||
} |
|||
|
|||
bool CompilerContext::isLocalVariable(Declaration const* _declaration) const |
|||
{ |
|||
return std::find(m_localVariables.begin(), m_localVariables.end(), _declaration) != m_localVariables.end(); |
|||
} |
|||
|
|||
eth::AssemblyItem CompilerContext::getFunctionEntryLabel(FunctionDefinition const& _function) const |
|||
{ |
|||
auto res = m_functionEntryLabels.find(&_function); |
|||
if (asserts(res != m_functionEntryLabels.end())) |
|||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Function entry label not found.")); |
|||
return res->second.tag(); |
|||
} |
|||
|
|||
unsigned CompilerContext::getBaseStackOffsetOfVariable(Declaration const& _declaration) const |
|||
{ |
|||
auto res = find(begin(m_localVariables), end(m_localVariables), &_declaration); |
|||
if (asserts(res != m_localVariables.end())) |
|||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Variable not found on stack.")); |
|||
return unsigned(end(m_localVariables) - res - 1); |
|||
} |
|||
|
|||
unsigned CompilerContext::baseToCurrentStackOffset(unsigned _baseOffset) const |
|||
{ |
|||
return _baseOffset + m_asm.deposit(); |
|||
} |
|||
|
|||
u256 CompilerContext::getStorageLocationOfVariable(const Declaration& _declaration) const |
|||
{ |
|||
auto it = m_stateVariables.find(&_declaration); |
|||
if (it == m_stateVariables.end()) |
|||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Variable not found in storage.")); |
|||
return it->second; |
|||
} |
|||
|
|||
|
|||
|
|||
} |
|||
} |
@ -0,0 +1,102 @@ |
|||
/*
|
|||
This file is part of cpp-ethereum. |
|||
|
|||
cpp-ethereum is free software: you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation, either version 3 of the License, or |
|||
(at your option) any later version. |
|||
|
|||
cpp-ethereum is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/**
|
|||
* @author Christian <c@ethdev.com> |
|||
* @date 2014 |
|||
* Utilities for the solidity compiler. |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <ostream> |
|||
#include <libevmcore/Instruction.h> |
|||
#include <libevmcore/Assembly.h> |
|||
#include <libsolidity/Types.h> |
|||
|
|||
namespace dev { |
|||
namespace solidity { |
|||
|
|||
|
|||
/**
|
|||
* Context to be shared by all units that compile the same contract. |
|||
* It stores the generated bytecode and the position of identifiers in memory and on the stack. |
|||
*/ |
|||
class CompilerContext |
|||
{ |
|||
public: |
|||
CompilerContext(): m_stateVariablesSize(0) {} |
|||
|
|||
void addStateVariable(VariableDeclaration const& _declaration); |
|||
void startNewFunction() { m_localVariables.clear(); m_asm.setDeposit(0); } |
|||
void initializeLocalVariables(unsigned _numVariables); |
|||
void addVariable(VariableDeclaration const& _declaration) { m_localVariables.push_back(&_declaration); } |
|||
void addFunction(FunctionDefinition const& _function) { m_functionEntryLabels.insert(std::make_pair(&_function, m_asm.newTag())); } |
|||
|
|||
void adjustStackOffset(int _adjustment) { m_asm.adjustDeposit(_adjustment); } |
|||
|
|||
bool isFunctionDefinition(Declaration const* _declaration) const { return m_functionEntryLabels.count(_declaration); } |
|||
bool isLocalVariable(Declaration const* _declaration) const; |
|||
bool isStateVariable(Declaration const* _declaration) const { return m_stateVariables.count(_declaration); } |
|||
|
|||
eth::AssemblyItem getFunctionEntryLabel(FunctionDefinition const& _function) const; |
|||
/// Returns the distance of the given local variable from the top of the local variable stack.
|
|||
unsigned getBaseStackOffsetOfVariable(Declaration const& _declaration) const; |
|||
/// If supplied by a value returned by @ref getBaseStackOffsetOfVariable(variable), returns
|
|||
/// the distance of that variable from the current top of the stack.
|
|||
unsigned baseToCurrentStackOffset(unsigned _baseOffset) const; |
|||
u256 getStorageLocationOfVariable(Declaration const& _declaration) const; |
|||
|
|||
/// Appends a JUMPI instruction to a new tag and @returns the tag
|
|||
eth::AssemblyItem appendConditionalJump() { return m_asm.appendJumpI().tag(); } |
|||
/// Appends a JUMPI instruction to @a _tag
|
|||
CompilerContext& appendConditionalJumpTo(eth::AssemblyItem const& _tag) { m_asm.appendJumpI(_tag); return *this; } |
|||
/// Appends a JUMP to a new tag and @returns the tag
|
|||
eth::AssemblyItem appendJump() { return m_asm.appendJump().tag(); } |
|||
/// Appends a JUMP to a specific tag
|
|||
CompilerContext& appendJumpTo(eth::AssemblyItem const& _tag) { m_asm.appendJump(_tag); return *this; } |
|||
/// Appends pushing of a new tag and @returns the new tag.
|
|||
eth::AssemblyItem pushNewTag() { return m_asm.append(m_asm.newPushTag()).tag(); } |
|||
/// @returns a new tag without pushing any opcodes or data
|
|||
eth::AssemblyItem newTag() { return m_asm.newTag(); } |
|||
/// Adds a subroutine to the code (in the data section) and pushes its size (via a tag)
|
|||
/// on the stack. @returns the assembly item corresponding to the pushed subroutine, i.e. its offset.
|
|||
eth::AssemblyItem addSubroutine(eth::Assembly const& _assembly) { return m_asm.appendSubSize(_assembly); } |
|||
|
|||
/// Append elements to the current instruction list and adjust @a m_stackOffset.
|
|||
CompilerContext& operator<<(eth::AssemblyItem const& _item) { m_asm.append(_item); return *this; } |
|||
CompilerContext& operator<<(eth::Instruction _instruction) { m_asm.append(_instruction); return *this; } |
|||
CompilerContext& operator<<(u256 const& _value) { m_asm.append(_value); return *this; } |
|||
CompilerContext& operator<<(bytes const& _data) { m_asm.append(_data); return *this; } |
|||
|
|||
eth::Assembly const& getAssembly() const { return m_asm; } |
|||
void streamAssembly(std::ostream& _stream) const { _stream << m_asm; } |
|||
bytes getAssembledBytecode(bool _optimize = false) { return m_asm.optimise(_optimize).assemble(); } |
|||
private: |
|||
eth::Assembly m_asm; |
|||
|
|||
/// Size of the state variables, offset of next variable to be added.
|
|||
u256 m_stateVariablesSize; |
|||
/// Storage offsets of state variables
|
|||
std::map<Declaration const*, u256> m_stateVariables; |
|||
/// Offsets of local variables on the stack.
|
|||
std::vector<Declaration const*> m_localVariables; |
|||
/// Labels pointing to the entry points of funcitons.
|
|||
std::map<Declaration const*, eth::AssemblyItem> m_functionEntryLabels; |
|||
}; |
|||
|
|||
} |
|||
} |
@ -0,0 +1,50 @@ |
|||
/*
|
|||
This file is part of cpp-ethereum. |
|||
|
|||
cpp-ethereum is free software: you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation, either version 3 of the License, or |
|||
(at your option) any later version. |
|||
|
|||
cpp-ethereum is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/**
|
|||
* @author Christian <c@ethdev.com> |
|||
* @date 2014 |
|||
* Full-stack compiler that converts a source code string to bytecode. |
|||
*/ |
|||
|
|||
#include <libsolidity/AST.h> |
|||
#include <libsolidity/Scanner.h> |
|||
#include <libsolidity/Parser.h> |
|||
#include <libsolidity/NameAndTypeResolver.h> |
|||
#include <libsolidity/Compiler.h> |
|||
#include <libsolidity/CompilerStack.h> |
|||
|
|||
using namespace std; |
|||
|
|||
namespace dev |
|||
{ |
|||
namespace solidity |
|||
{ |
|||
|
|||
bytes CompilerStack::compile(std::string const& _sourceCode, shared_ptr<Scanner> _scanner, |
|||
bool _optimize) |
|||
{ |
|||
if (!_scanner) |
|||
_scanner = make_shared<Scanner>(); |
|||
_scanner->reset(CharStream(_sourceCode)); |
|||
|
|||
ASTPointer<ContractDefinition> contract = Parser().parse(_scanner); |
|||
NameAndTypeResolver().resolveNamesAndTypes(*contract); |
|||
return Compiler::compile(*contract, _optimize); |
|||
} |
|||
|
|||
} |
|||
} |
@ -0,0 +1,43 @@ |
|||
/*
|
|||
This file is part of cpp-ethereum. |
|||
|
|||
cpp-ethereum is free software: you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation, either version 3 of the License, or |
|||
(at your option) any later version. |
|||
|
|||
cpp-ethereum is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/**
|
|||
* @author Christian <c@ethdev.com> |
|||
* @date 2014 |
|||
* Full-stack compiler that converts a source code string to bytecode. |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <string> |
|||
#include <memory> |
|||
#include <libdevcore/Common.h> |
|||
|
|||
namespace dev { |
|||
namespace solidity { |
|||
|
|||
class Scanner; // forward
|
|||
|
|||
class CompilerStack |
|||
{ |
|||
public: |
|||
/// Compile the given @a _sourceCode to bytecode. If a scanner is provided, it is used for
|
|||
/// scanning the source code - this is useful for printing exception information.
|
|||
static bytes compile(std::string const& _sourceCode, std::shared_ptr<Scanner> _scanner = std::shared_ptr<Scanner>(), bool _optimize = false); |
|||
}; |
|||
|
|||
} |
|||
} |
@ -0,0 +1,436 @@ |
|||
/*
|
|||
This file is part of cpp-ethereum. |
|||
|
|||
cpp-ethereum is free software: you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation, either version 3 of the License, or |
|||
(at your option) any later version. |
|||
|
|||
cpp-ethereum is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/**
|
|||
* @author Christian <c@ethdev.com> |
|||
* @date 2014 |
|||
* Solidity AST to EVM bytecode compiler for expressions. |
|||
*/ |
|||
|
|||
#include <utility> |
|||
#include <numeric> |
|||
#include <libsolidity/AST.h> |
|||
#include <libsolidity/ExpressionCompiler.h> |
|||
#include <libsolidity/CompilerContext.h> |
|||
|
|||
using namespace std; |
|||
|
|||
namespace dev { |
|||
namespace solidity { |
|||
|
|||
void ExpressionCompiler::compileExpression(CompilerContext& _context, Expression& _expression) |
|||
{ |
|||
ExpressionCompiler compiler(_context); |
|||
_expression.accept(compiler); |
|||
} |
|||
|
|||
void ExpressionCompiler::appendTypeConversion(CompilerContext& _context, |
|||
Type const& _typeOnStack, Type const& _targetType) |
|||
{ |
|||
ExpressionCompiler compiler(_context); |
|||
compiler.appendTypeConversion(_typeOnStack, _targetType); |
|||
} |
|||
|
|||
bool ExpressionCompiler::visit(Assignment& _assignment) |
|||
{ |
|||
_assignment.getRightHandSide().accept(*this); |
|||
appendTypeConversion(*_assignment.getRightHandSide().getType(), *_assignment.getType()); |
|||
m_currentLValue.reset(); |
|||
_assignment.getLeftHandSide().accept(*this); |
|||
|
|||
Token::Value op = _assignment.getAssignmentOperator(); |
|||
if (op != Token::ASSIGN) // compound assignment
|
|||
appendOrdinaryBinaryOperatorCode(Token::AssignmentToBinaryOp(op), *_assignment.getType()); |
|||
else |
|||
m_context << eth::Instruction::POP; |
|||
|
|||
storeInLValue(_assignment); |
|||
return false; |
|||
} |
|||
|
|||
void ExpressionCompiler::endVisit(UnaryOperation& _unaryOperation) |
|||
{ |
|||
//@todo type checking and creating code for an operator should be in the same place:
|
|||
// the operator should know how to convert itself and to which types it applies, so
|
|||
// put this code together with "Type::acceptsBinary/UnaryOperator" into a class that
|
|||
// represents the operator
|
|||
switch (_unaryOperation.getOperator()) |
|||
{ |
|||
case Token::NOT: // !
|
|||
m_context << eth::Instruction::ISZERO; |
|||
break; |
|||
case Token::BIT_NOT: // ~
|
|||
m_context << eth::Instruction::NOT; |
|||
break; |
|||
case Token::DELETE: // delete
|
|||
{ |
|||
// a -> a xor a (= 0).
|
|||
// @todo semantics change for complex types
|
|||
m_context << eth::Instruction::DUP1 << eth::Instruction::XOR; |
|||
storeInLValue(_unaryOperation); |
|||
break; |
|||
} |
|||
case Token::INC: // ++ (pre- or postfix)
|
|||
case Token::DEC: // -- (pre- or postfix)
|
|||
if (!_unaryOperation.isPrefixOperation()) |
|||
m_context << eth::Instruction::DUP1; |
|||
m_context << u256(1); |
|||
if (_unaryOperation.getOperator() == Token::INC) |
|||
m_context << eth::Instruction::ADD; |
|||
else |
|||
m_context << eth::Instruction::SWAP1 << eth::Instruction::SUB; // @todo avoid the swap
|
|||
storeInLValue(_unaryOperation, !_unaryOperation.isPrefixOperation()); |
|||
break; |
|||
case Token::ADD: // +
|
|||
// unary add, so basically no-op
|
|||
break; |
|||
case Token::SUB: // -
|
|||
m_context << u256(0) << eth::Instruction::SUB; |
|||
break; |
|||
default: |
|||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid unary operator: " + |
|||
string(Token::toString(_unaryOperation.getOperator())))); |
|||
} |
|||
} |
|||
|
|||
bool ExpressionCompiler::visit(BinaryOperation& _binaryOperation) |
|||
{ |
|||
Expression& leftExpression = _binaryOperation.getLeftExpression(); |
|||
Expression& rightExpression = _binaryOperation.getRightExpression(); |
|||
Type const& commonType = _binaryOperation.getCommonType(); |
|||
Token::Value const op = _binaryOperation.getOperator(); |
|||
|
|||
if (op == Token::AND || op == Token::OR) // special case: short-circuiting
|
|||
appendAndOrOperatorCode(_binaryOperation); |
|||
else |
|||
{ |
|||
bool cleanupNeeded = false; |
|||
if (commonType.getCategory() == Type::Category::INTEGER) |
|||
if (Token::isCompareOp(op) || op == Token::DIV || op == Token::MOD) |
|||
cleanupNeeded = true; |
|||
|
|||
rightExpression.accept(*this); |
|||
appendTypeConversion(*rightExpression.getType(), commonType, cleanupNeeded); |
|||
leftExpression.accept(*this); |
|||
appendTypeConversion(*leftExpression.getType(), commonType, cleanupNeeded); |
|||
if (Token::isCompareOp(op)) |
|||
appendCompareOperatorCode(op, commonType); |
|||
else |
|||
appendOrdinaryBinaryOperatorCode(op, commonType); |
|||
} |
|||
|
|||
// do not visit the child nodes, we already did that explicitly
|
|||
return false; |
|||
} |
|||
|
|||
bool ExpressionCompiler::visit(FunctionCall& _functionCall) |
|||
{ |
|||
if (_functionCall.isTypeConversion()) |
|||
{ |
|||
//@todo we only have integers and bools for now which cannot be explicitly converted
|
|||
if (asserts(_functionCall.getArguments().size() == 1)) |
|||
BOOST_THROW_EXCEPTION(InternalCompilerError()); |
|||
Expression& firstArgument = *_functionCall.getArguments().front(); |
|||
firstArgument.accept(*this); |
|||
appendTypeConversion(*firstArgument.getType(), *_functionCall.getType()); |
|||
} |
|||
else |
|||
{ |
|||
// Calling convention: Caller pushes return address and arguments
|
|||
// Callee removes them and pushes return values
|
|||
m_currentLValue.reset(); |
|||
_functionCall.getExpression().accept(*this); |
|||
if (asserts(m_currentLValue.isInCode())) |
|||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Code reference expected.")); |
|||
eth::AssemblyItem functionTag(eth::PushTag, m_currentLValue.location); |
|||
|
|||
FunctionDefinition const& function = dynamic_cast<FunctionType const&>(*_functionCall.getExpression().getType()).getFunction(); |
|||
|
|||
eth::AssemblyItem returnLabel = m_context.pushNewTag(); |
|||
std::vector<ASTPointer<Expression>> const& arguments = _functionCall.getArguments(); |
|||
if (asserts(arguments.size() == function.getParameters().size())) |
|||
BOOST_THROW_EXCEPTION(InternalCompilerError()); |
|||
for (unsigned i = 0; i < arguments.size(); ++i) |
|||
{ |
|||
arguments[i]->accept(*this); |
|||
appendTypeConversion(*arguments[i]->getType(), *function.getParameters()[i]->getType()); |
|||
} |
|||
|
|||
m_context.appendJumpTo(functionTag); |
|||
m_context << returnLabel; |
|||
|
|||
// callee adds return parameters, but removes arguments and return label
|
|||
m_context.adjustStackOffset(function.getReturnParameters().size() - arguments.size() - 1); |
|||
|
|||
// @todo for now, the return value of a function is its first return value, so remove
|
|||
// all others
|
|||
for (unsigned i = 1; i < function.getReturnParameters().size(); ++i) |
|||
m_context << eth::Instruction::POP; |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
void ExpressionCompiler::endVisit(MemberAccess&) |
|||
{ |
|||
|
|||
} |
|||
|
|||
void ExpressionCompiler::endVisit(IndexAccess&) |
|||
{ |
|||
|
|||
} |
|||
|
|||
void ExpressionCompiler::endVisit(Identifier& _identifier) |
|||
{ |
|||
Declaration const* declaration = _identifier.getReferencedDeclaration(); |
|||
if (m_context.isLocalVariable(declaration)) |
|||
m_currentLValue = LValueLocation(LValueLocation::STACK, |
|||
m_context.getBaseStackOffsetOfVariable(*declaration)); |
|||
else if (m_context.isStateVariable(declaration)) |
|||
m_currentLValue = LValueLocation(LValueLocation::STORAGE, |
|||
m_context.getStorageLocationOfVariable(*declaration)); |
|||
else if (m_context.isFunctionDefinition(declaration)) |
|||
m_currentLValue = LValueLocation(LValueLocation::CODE, |
|||
m_context.getFunctionEntryLabel(dynamic_cast<FunctionDefinition const&>(*declaration)).data()); |
|||
else |
|||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Identifier type not supported or identifier not found.")); |
|||
|
|||
retrieveLValueValue(_identifier); |
|||
} |
|||
|
|||
void ExpressionCompiler::endVisit(Literal& _literal) |
|||
{ |
|||
switch (_literal.getType()->getCategory()) |
|||
{ |
|||
case Type::Category::INTEGER: |
|||
case Type::Category::BOOL: |
|||
m_context << _literal.getType()->literalValue(_literal); |
|||
break; |
|||
default: |
|||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Only integer and boolean literals implemented for now.")); |
|||
} |
|||
} |
|||
|
|||
void ExpressionCompiler::appendAndOrOperatorCode(BinaryOperation& _binaryOperation) |
|||
{ |
|||
Token::Value const op = _binaryOperation.getOperator(); |
|||
if (asserts(op == Token::OR || op == Token::AND)) |
|||
BOOST_THROW_EXCEPTION(InternalCompilerError()); |
|||
|
|||
_binaryOperation.getLeftExpression().accept(*this); |
|||
m_context << eth::Instruction::DUP1; |
|||
if (op == Token::AND) |
|||
m_context << eth::Instruction::ISZERO; |
|||
eth::AssemblyItem endLabel = m_context.appendConditionalJump(); |
|||
m_context << eth::Instruction::POP; |
|||
_binaryOperation.getRightExpression().accept(*this); |
|||
m_context << endLabel; |
|||
} |
|||
|
|||
void ExpressionCompiler::appendCompareOperatorCode(Token::Value _operator, Type const& _type) |
|||
{ |
|||
if (_operator == Token::EQ || _operator == Token::NE) |
|||
{ |
|||
m_context << eth::Instruction::EQ; |
|||
if (_operator == Token::NE) |
|||
m_context << eth::Instruction::ISZERO; |
|||
} |
|||
else |
|||
{ |
|||
IntegerType const& type = dynamic_cast<IntegerType const&>(_type); |
|||
bool const isSigned = type.isSigned(); |
|||
|
|||
switch (_operator) |
|||
{ |
|||
case Token::GTE: |
|||
m_context << (isSigned ? eth::Instruction::SLT : eth::Instruction::LT) |
|||
<< eth::Instruction::ISZERO; |
|||
break; |
|||
case Token::LTE: |
|||
m_context << (isSigned ? eth::Instruction::SGT : eth::Instruction::GT) |
|||
<< eth::Instruction::ISZERO; |
|||
break; |
|||
case Token::GT: |
|||
m_context << (isSigned ? eth::Instruction::SGT : eth::Instruction::GT); |
|||
break; |
|||
case Token::LT: |
|||
m_context << (isSigned ? eth::Instruction::SLT : eth::Instruction::LT); |
|||
break; |
|||
default: |
|||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown comparison operator.")); |
|||
} |
|||
} |
|||
} |
|||
|
|||
void ExpressionCompiler::appendOrdinaryBinaryOperatorCode(Token::Value _operator, Type const& _type) |
|||
{ |
|||
if (Token::isArithmeticOp(_operator)) |
|||
appendArithmeticOperatorCode(_operator, _type); |
|||
else if (Token::isBitOp(_operator)) |
|||
appendBitOperatorCode(_operator); |
|||
else if (Token::isShiftOp(_operator)) |
|||
appendShiftOperatorCode(_operator); |
|||
else |
|||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown binary operator.")); |
|||
} |
|||
|
|||
void ExpressionCompiler::appendArithmeticOperatorCode(Token::Value _operator, Type const& _type) |
|||
{ |
|||
IntegerType const& type = dynamic_cast<IntegerType const&>(_type); |
|||
bool const isSigned = type.isSigned(); |
|||
|
|||
switch (_operator) |
|||
{ |
|||
case Token::ADD: |
|||
m_context << eth::Instruction::ADD; |
|||
break; |
|||
case Token::SUB: |
|||
m_context << eth::Instruction::SUB; |
|||
break; |
|||
case Token::MUL: |
|||
m_context << eth::Instruction::MUL; |
|||
break; |
|||
case Token::DIV: |
|||
m_context << (isSigned ? eth::Instruction::SDIV : eth::Instruction::DIV); |
|||
break; |
|||
case Token::MOD: |
|||
m_context << (isSigned ? eth::Instruction::SMOD : eth::Instruction::MOD); |
|||
break; |
|||
default: |
|||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown arithmetic operator.")); |
|||
} |
|||
} |
|||
|
|||
void ExpressionCompiler::appendBitOperatorCode(Token::Value _operator) |
|||
{ |
|||
switch (_operator) |
|||
{ |
|||
case Token::BIT_OR: |
|||
m_context << eth::Instruction::OR; |
|||
break; |
|||
case Token::BIT_AND: |
|||
m_context << eth::Instruction::AND; |
|||
break; |
|||
case Token::BIT_XOR: |
|||
m_context << eth::Instruction::XOR; |
|||
break; |
|||
default: |
|||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown bit operator.")); |
|||
} |
|||
} |
|||
|
|||
void ExpressionCompiler::appendShiftOperatorCode(Token::Value _operator) |
|||
{ |
|||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Shift operators not yet implemented.")); |
|||
switch (_operator) |
|||
{ |
|||
case Token::SHL: |
|||
break; |
|||
case Token::SAR: |
|||
break; |
|||
default: |
|||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown shift operator.")); |
|||
} |
|||
} |
|||
|
|||
void ExpressionCompiler::appendTypeConversion(Type const& _typeOnStack, Type const& _targetType, bool _cleanupNeeded) |
|||
{ |
|||
// For a type extension, we need to remove all higher-order bits that we might have ignored in
|
|||
// previous operations.
|
|||
// @todo: store in the AST whether the operand might have "dirty" higher order bits
|
|||
|
|||
if (_typeOnStack == _targetType && !_cleanupNeeded) |
|||
return; |
|||
if (_typeOnStack.getCategory() == Type::Category::INTEGER) |
|||
appendHighBitsCleanup(dynamic_cast<IntegerType const&>(_typeOnStack)); |
|||
else if (_typeOnStack != _targetType) |
|||
// All other types should not be convertible to non-equal types.
|
|||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid type conversion requested.")); |
|||
} |
|||
|
|||
void ExpressionCompiler::appendHighBitsCleanup(IntegerType const& _typeOnStack) |
|||
{ |
|||
if (_typeOnStack.getNumBits() == 256) |
|||
return; |
|||
else if (_typeOnStack.isSigned()) |
|||
m_context << u256(_typeOnStack.getNumBits() / 8 - 1) << eth::Instruction::SIGNEXTEND; |
|||
else |
|||
m_context << ((u256(1) << _typeOnStack.getNumBits()) - 1) << eth::Instruction::AND; |
|||
} |
|||
|
|||
void ExpressionCompiler::retrieveLValueValue(Expression const& _expression) |
|||
{ |
|||
switch (m_currentLValue.locationType) |
|||
{ |
|||
case LValueLocation::CODE: |
|||
// not stored on the stack
|
|||
break; |
|||
case LValueLocation::STACK: |
|||
{ |
|||
unsigned stackPos = m_context.baseToCurrentStackOffset(unsigned(m_currentLValue.location)); |
|||
if (stackPos >= 15) //@todo correct this by fetching earlier or moving to memory
|
|||
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_expression.getLocation()) |
|||
<< errinfo_comment("Stack too deep.")); |
|||
m_context << eth::dupInstruction(stackPos + 1); |
|||
break; |
|||
} |
|||
case LValueLocation::STORAGE: |
|||
m_context << m_currentLValue.location << eth::Instruction::SLOAD; |
|||
break; |
|||
case LValueLocation::MEMORY: |
|||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Location type not yet implemented.")); |
|||
break; |
|||
default: |
|||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unsupported location type.")); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
void ExpressionCompiler::storeInLValue(Expression const& _expression, bool _move) |
|||
{ |
|||
switch (m_currentLValue.locationType) |
|||
{ |
|||
case LValueLocation::STACK: |
|||
{ |
|||
unsigned stackPos = m_context.baseToCurrentStackOffset(unsigned(m_currentLValue.location)); |
|||
if (stackPos > 16) |
|||
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_expression.getLocation()) |
|||
<< errinfo_comment("Stack too deep.")); |
|||
else if (stackPos > 0) |
|||
m_context << eth::swapInstruction(stackPos) << eth::Instruction::POP; |
|||
if (!_move) |
|||
retrieveLValueValue(_expression); |
|||
break; |
|||
} |
|||
case LValueLocation::STORAGE: |
|||
if (!_move) |
|||
m_context << eth::Instruction::DUP1; |
|||
m_context << m_currentLValue.location << eth::Instruction::SSTORE; |
|||
break; |
|||
case LValueLocation::CODE: |
|||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Location type does not support assignment.")); |
|||
break; |
|||
case LValueLocation::MEMORY: |
|||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Location type not yet implemented.")); |
|||
break; |
|||
default: |
|||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unsupported location type.")); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
} |
|||
} |
@ -0,0 +1,117 @@ |
|||
/*
|
|||
This file is part of cpp-ethereum. |
|||
|
|||
cpp-ethereum is free software: you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation, either version 3 of the License, or |
|||
(at your option) any later version. |
|||
|
|||
cpp-ethereum is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/**
|
|||
* @author Christian <c@ethdev.com> |
|||
* @date 2014 |
|||
* Solidity AST to EVM bytecode compiler for expressions. |
|||
*/ |
|||
|
|||
#include <libdevcore/Common.h> |
|||
#include <libsolidity/ASTVisitor.h> |
|||
|
|||
namespace dev { |
|||
namespace eth |
|||
{ |
|||
class AssemblyItem; // forward
|
|||
} |
|||
namespace solidity { |
|||
|
|||
class CompilerContext; // forward
|
|||
class Type; // forward
|
|||
class IntegerType; // forward
|
|||
|
|||
/**
|
|||
* Compiler for expressions, i.e. converts an AST tree whose root is an Expression into a stream |
|||
* of EVM instructions. It needs a compiler context that is the same for the whole compilation |
|||
* unit. |
|||
*/ |
|||
class ExpressionCompiler: private ASTVisitor |
|||
{ |
|||
public: |
|||
/// Compile the given @a _expression into the @a _context.
|
|||
static void compileExpression(CompilerContext& _context, Expression& _expression); |
|||
|
|||
/// Appends code to remove dirty higher order bits in case of an implicit promotion to a wider type.
|
|||
static void appendTypeConversion(CompilerContext& _context, Type const& _typeOnStack, Type const& _targetType); |
|||
|
|||
private: |
|||
ExpressionCompiler(CompilerContext& _compilerContext): m_context(_compilerContext) {} |
|||
|
|||
virtual bool visit(Assignment& _assignment) override; |
|||
virtual void endVisit(UnaryOperation& _unaryOperation) override; |
|||
virtual bool visit(BinaryOperation& _binaryOperation) override; |
|||
virtual bool visit(FunctionCall& _functionCall) override; |
|||
virtual void endVisit(MemberAccess& _memberAccess) override; |
|||
virtual void endVisit(IndexAccess& _indexAccess) override; |
|||
virtual void endVisit(Identifier& _identifier) override; |
|||
virtual void endVisit(Literal& _literal) override; |
|||
|
|||
///@{
|
|||
///@name Append code for various operator types
|
|||
void appendAndOrOperatorCode(BinaryOperation& _binaryOperation); |
|||
void appendCompareOperatorCode(Token::Value _operator, Type const& _type); |
|||
void appendOrdinaryBinaryOperatorCode(Token::Value _operator, Type const& _type); |
|||
|
|||
void appendArithmeticOperatorCode(Token::Value _operator, Type const& _type); |
|||
void appendBitOperatorCode(Token::Value _operator); |
|||
void appendShiftOperatorCode(Token::Value _operator); |
|||
/// @}
|
|||
|
|||
/// Appends an implicit or explicit type conversion. For now this comprises only erasing
|
|||
/// higher-order bits (@see appendHighBitCleanup) when widening integer types.
|
|||
/// If @a _cleanupNeeded, high order bits cleanup is also done if no type conversion would be
|
|||
/// necessary.
|
|||
void appendTypeConversion(Type const& _typeOnStack, Type const& _targetType, bool _cleanupNeeded = false); |
|||
//// Appends code that cleans higher-order bits for integer types.
|
|||
void appendHighBitsCleanup(IntegerType const& _typeOnStack); |
|||
|
|||
/// Copies the value of the current lvalue to the top of the stack.
|
|||
void retrieveLValueValue(Expression const& _expression); |
|||
/// Stores the value on top of the stack in the current lvalue. Removes it from the stack if
|
|||
/// @a _move is true.
|
|||
void storeInLValue(Expression const& _expression, bool _move = false); |
|||
|
|||
/**
|
|||
* Location of an lvalue, either in code (for a function) on the stack, in the storage or memory. |
|||
*/ |
|||
struct LValueLocation |
|||
{ |
|||
enum LocationType { INVALID, CODE, STACK, MEMORY, STORAGE }; |
|||
|
|||
LValueLocation() { reset(); } |
|||
LValueLocation(LocationType _type, u256 const& _location): locationType(_type), location(_location) {} |
|||
void reset() { locationType = INVALID; location = 0; } |
|||
bool isValid() const { return locationType != INVALID; } |
|||
bool isInCode() const { return locationType == CODE; } |
|||
bool isInOnStack() const { return locationType == STACK; } |
|||
bool isInMemory() const { return locationType == MEMORY; } |
|||
bool isInStorage() const { return locationType == STORAGE; } |
|||
|
|||
LocationType locationType; |
|||
/// Depending on the type, this is the id of a tag (code), the base offset of a stack
|
|||
/// variable (@see CompilerContext::getBaseStackOffsetOfVariable) or the offset in
|
|||
/// storage or memory.
|
|||
u256 location; |
|||
}; |
|||
|
|||
LValueLocation m_currentLValue; |
|||
CompilerContext& m_context; |
|||
}; |
|||
|
|||
|
|||
} |
|||
} |
@ -1,55 +1,55 @@ |
|||
[ |
|||
{ "method": "coinbase", "params": [], "order": [], "returns" : "" }, |
|||
{ "method": "setCoinbase", "params": [""], "order": [], "returns" : true }, |
|||
{ "method": "listening", "params": [], "order": [], "returns" : false }, |
|||
{ "method": "setListening", "params": [false], "order" : [], "returns" : true }, |
|||
{ "method": "mining", "params": [], "order": [], "returns" : false }, |
|||
{ "method": "setMining", "params": [false], "order" : [], "returns" : true }, |
|||
{ "method": "gasPrice", "params": [], "order": [], "returns" : "" }, |
|||
{ "method": "account", "params": [], "order": [], "returns" : "" }, |
|||
{ "method": "accounts", "params": [], "order": [], "returns" : [] }, |
|||
{ "method": "peerCount", "params": [], "order": [], "returns" : 0 }, |
|||
{ "method": "defaultBlock", "params": [], "order": [], "returns" : 0}, |
|||
{ "method": "setDefaultBlock", "params": [0], "order": [], "returns" : true}, |
|||
{ "method": "number", "params": [], "order": [], "returns" : 0}, |
|||
|
|||
{ "method": "balanceAt", "params": [""], "order": [], "returns" : ""}, |
|||
{ "method": "stateAt", "params": ["", ""], "order": [], "returns": ""}, |
|||
{ "method": "countAt", "params": [""], "order": [], "returns" : 0.0}, |
|||
{ "method": "codeAt", "params": [""], "order": [], "returns": ""}, |
|||
|
|||
{ "method": "transact", "params": [{}], "order": [], "returns": ""}, |
|||
{ "method": "call", "params": [{}], "order": [], "returns": ""}, |
|||
|
|||
{ "method": "blockByHash", "params": [""],"order": [], "returns": {}}, |
|||
{ "method": "blockByNumber", "params": [0],"order": [], "returns": {}}, |
|||
{ "method": "transactionByHash", "params": ["", 0], "order": [], "returns": {}}, |
|||
{ "method": "transactionByNumber", "params": [0, 0], "order": [], "returns": {}}, |
|||
{ "method": "uncleByHash", "params": ["", 0], "order": [], "returns": {}}, |
|||
{ "method": "uncleByNumber", "params": [0, 0], "order": [], "returns": {}}, |
|||
|
|||
{ "method": "compile", "params": [""], "order": [], "returns": ""}, |
|||
|
|||
{ "method": "newFilter", "params": [{}], "order": [], "returns": 0}, |
|||
{ "method": "newFilterString", "params": [""], "order": [], "returns": 0}, |
|||
{ "method": "uninstallFilter", "params": [0], "order": [], "returns": true}, |
|||
{ "method": "changed", "params": [0], "order": [], "returns": false}, |
|||
{ "method": "getMessages", "params": [0], "order": [], "returns": []}, |
|||
|
|||
{ "method": "put", "params": ["", "", ""], "order": [], "returns": true}, |
|||
{ "method": "get", "params": ["", ""], "order": [], "returns": ""}, |
|||
{ "method": "putString", "params": ["", "", ""], "order": [], "returns": true}, |
|||
{ "method": "getString", "params": ["", ""], "order": [], "returns": ""}, |
|||
|
|||
{ "method": "post", "params": [{}], "order": [], "returns": true}, |
|||
{ "method": "newIdentity", "params": [], "order": [], "returns": ""}, |
|||
{ "method": "haveIdentity", "params": [""], "order": [], "returns": false}, |
|||
{ "method": "newGroup", "params": ["", ""], "order": [], "returns": ""}, |
|||
{ "method": "addToGroup", "params": ["", ""], "order": [], "returns": ""}, |
|||
|
|||
{ "method": "shhNewFilter", "params": [{}], "order": [], "returns": 0}, |
|||
{ "method": "shhUninstallFilter", "params": [0], "order": [], "returns": true}, |
|||
{ "method": "shhChanged", "params": [0], "order": [], "returns": []} |
|||
{ "method": "eth_coinbase", "params": [], "order": [], "returns" : "" }, |
|||
{ "method": "eth_setCoinbase", "params": [""], "order": [], "returns" : true }, |
|||
{ "method": "eth_listening", "params": [], "order": [], "returns" : false }, |
|||
{ "method": "eth_setListening", "params": [false], "order" : [], "returns" : true }, |
|||
{ "method": "eth_mining", "params": [], "order": [], "returns" : false }, |
|||
{ "method": "eth_setMining", "params": [false], "order" : [], "returns" : true }, |
|||
{ "method": "eth_gasPrice", "params": [], "order": [], "returns" : "" }, |
|||
{ "method": "eth_accounts", "params": [], "order": [], "returns" : [] }, |
|||
{ "method": "eth_peerCount", "params": [], "order": [], "returns" : 0 }, |
|||
{ "method": "eth_defaultBlock", "params": [], "order": [], "returns" : 0}, |
|||
{ "method": "eth_setDefaultBlock", "params": [0], "order": [], "returns" : true}, |
|||
{ "method": "eth_number", "params": [], "order": [], "returns" : 0}, |
|||
|
|||
{ "method": "eth_balanceAt", "params": [""], "order": [], "returns" : ""}, |
|||
{ "method": "eth_stateAt", "params": ["", ""], "order": [], "returns": ""}, |
|||
{ "method": "eth_countAt", "params": [""], "order": [], "returns" : 0.0}, |
|||
{ "method": "eth_codeAt", "params": [""], "order": [], "returns": ""}, |
|||
|
|||
{ "method": "eth_transact", "params": [{}], "order": [], "returns": ""}, |
|||
{ "method": "eth_call", "params": [{}], "order": [], "returns": ""}, |
|||
|
|||
{ "method": "eth_blockByHash", "params": [""],"order": [], "returns": {}}, |
|||
{ "method": "eth_blockByNumber", "params": [0],"order": [], "returns": {}}, |
|||
{ "method": "eth_transactionByHash", "params": ["", 0], "order": [], "returns": {}}, |
|||
{ "method": "eth_transactionByNumber", "params": [0, 0], "order": [], "returns": {}}, |
|||
{ "method": "eth_uncleByHash", "params": ["", 0], "order": [], "returns": {}}, |
|||
{ "method": "eth_uncleByNumber", "params": [0, 0], "order": [], "returns": {}}, |
|||
|
|||
{ "method": "eth_lll", "params": [""], "order": [], "returns": ""}, |
|||
{ "method": "eth_compile", "params": [""], "order": [], "returns": ""}, |
|||
|
|||
{ "method": "eth_newFilter", "params": [{}], "order": [], "returns": 0}, |
|||
{ "method": "eth_newFilterString", "params": [""], "order": [], "returns": 0}, |
|||
{ "method": "eth_uninstallFilter", "params": [0], "order": [], "returns": true}, |
|||
{ "method": "eth_changed", "params": [0], "order": [], "returns": false}, |
|||
{ "method": "eth_getMessages", "params": [0], "order": [], "returns": []}, |
|||
|
|||
{ "method": "db_put", "params": ["", "", ""], "order": [], "returns": true}, |
|||
{ "method": "db_get", "params": ["", ""], "order": [], "returns": ""}, |
|||
{ "method": "db_putString", "params": ["", "", ""], "order": [], "returns": true}, |
|||
{ "method": "db_getString", "params": ["", ""], "order": [], "returns": ""}, |
|||
|
|||
{ "method": "shh_post", "params": [{}], "order": [], "returns": true}, |
|||
{ "method": "shh_newIdentity", "params": [], "order": [], "returns": ""}, |
|||
{ "method": "shh_haveIdentity", "params": [""], "order": [], "returns": false}, |
|||
{ "method": "shh_newGroup", "params": ["", ""], "order": [], "returns": ""}, |
|||
{ "method": "shh_addToGroup", "params": ["", ""], "order": [], "returns": ""}, |
|||
|
|||
{ "method": "shh_newFilter", "params": [{}], "order": [], "returns": 0}, |
|||
{ "method": "shh_uninstallFilter", "params": [0], "order": [], "returns": true}, |
|||
{ "method": "shh_changed", "params": [0], "order": [], "returns": []} |
|||
|
|||
] |
|||
|
|||
|
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue