diff --git a/CMakeLists.txt b/CMakeLists.txt index b1ce840325d..2b037c49085 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -123,6 +123,9 @@ endif() #Global include path for all libs. include_directories("${CMAKE_SOURCE_DIR}") +option(ALETH_INTERPRETER_SHARED "Build aleth-interpreter as a shared library" OFF) +add_subdirectory(libaleth-interpreter) + add_subdirectory(libdevcore) add_subdirectory(libdevcrypto) add_subdirectory(libp2p) diff --git a/aleth-vm/main.cpp b/aleth-vm/main.cpp index 585a56edebe..f40c3714819 100644 --- a/aleth-vm/main.cpp +++ b/aleth-vm/main.cpp @@ -28,7 +28,6 @@ #include #include #include -#include #include #include diff --git a/aleth/main.cpp b/aleth/main.cpp index 79bc2fef8c0..68e74bdf8c3 100644 --- a/aleth/main.cpp +++ b/aleth/main.cpp @@ -40,7 +40,6 @@ #include #include #include -#include #include #include diff --git a/cmake/toolchains/cxx11-pic.cmake b/cmake/toolchains/cxx11-pic.cmake new file mode 100644 index 00000000000..22c63ac04cb --- /dev/null +++ b/cmake/toolchains/cxx11-pic.cmake @@ -0,0 +1,6 @@ +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED TRUE) +set(CMAKE_CXX_EXTENSIONS OFF) + +set(CMAKE_CXX_FLAGS_INIT "-fPIC" CACHE STRING "" FORCE) +set(CMAKE_C_FLAGS_INIT "-fPIC" CACHE STRING "" FORCE) diff --git a/libaleth-interpreter/CMakeLists.txt b/libaleth-interpreter/CMakeLists.txt new file mode 100644 index 00000000000..4ba555fd0af --- /dev/null +++ b/libaleth-interpreter/CMakeLists.txt @@ -0,0 +1,21 @@ +# Aleth: Ethereum C++ client, tools and libraries. +# Copyright 2018 Aleth Autors. +# Licensed under the GNU General Public License, Version 3. See the LICENSE file. + +if(ALETH_INTERPRETER_SHARED) + set(library_type SHARED) +else() + set(library_type STATIC) +endif() + +add_library( + aleth-interpreter + ${library_type} + interpreter.h + VM.cpp + VM.h + VMCalls.cpp + VMConfig.h + VMOpt.cpp +) +target_link_libraries(aleth-interpreter PRIVATE devcore aleth-buildinfo evmc::evmc evmc::instructions) diff --git a/libevm/VM.cpp b/libaleth-interpreter/VM.cpp similarity index 83% rename from libevm/VM.cpp rename to libaleth-interpreter/VM.cpp index cc6dba97891..068e4dca28e 100644 --- a/libevm/VM.cpp +++ b/libaleth-interpreter/VM.cpp @@ -801,93 +801,6 @@ void VM::interpretCases() } NEXT -#if EIP_615 - CASE(JUMPTO) - { - ON_OP(); - updateIOGas(); - - m_PC = decodeJumpDest(m_code.data(), m_PC); - } - CONTINUE - - CASE(JUMPIF) - { - ON_OP(); - updateIOGas(); - - if (m_SP[0]) - m_PC = decodeJumpDest(m_code.data(), m_PC); - else - ++m_PC; - } - CONTINUE - - CASE(JUMPV) - { - ON_OP(); - updateIOGas(); - m_PC = decodeJumpvDest(m_code.data(), m_PC, byte(m_SP[0])); - } - CONTINUE - - CASE(JUMPSUB) - { - ON_OP(); - updateIOGas(); - *m_RP++ = m_PC++; - m_PC = decodeJumpDest(m_code.data(), m_PC); - } - CONTINUE - - CASE(JUMPSUBV) - { - ON_OP(); - updateIOGas(); - *m_RP++ = m_PC; - m_PC = decodeJumpvDest(m_code.data(), m_PC, byte(m_SP[0])); - } - CONTINUE - - CASE(RETURNSUB) - { - ON_OP(); - updateIOGas(); - - m_PC = *m_RP--; - } - NEXT - - CASE(BEGINSUB) - { - ON_OP(); - updateIOGas(); - } - NEXT - - - CASE(BEGINDATA) - { - ON_OP(); - updateIOGas(); - } - NEXT - - CASE(GETLOCAL) - { - ON_OP(); - updateIOGas(); - } - NEXT - - CASE(PUTLOCAL) - { - ON_OP(); - updateIOGas(); - } - NEXT - -#else CASE(JUMPTO) CASE(JUMPIF) CASE(JUMPV) @@ -902,320 +815,7 @@ void VM::interpretCases() throwBadInstruction(); } CONTINUE -#endif - -#if EIP_616 - - CASE(XADD) - { - ON_OP(); - updateIOGas(); - - xadd(simdType()); - } - CONTINUE - - CASE(XMUL) - { - ON_OP(); - updateIOGas(); - - xmul(simdType()); - } - CONTINUE - - CASE(XSUB) - { - ON_OP(); - updateIOGas(); - - xsub(simdType()); - } - CONTINUE - - CASE(XDIV) - { - ON_OP(); - updateIOGas(); - - xdiv(simdType()); - } - CONTINUE - - CASE(XSDIV) - { - ON_OP(); - updateIOGas(); - - xsdiv(simdType()); - } - CONTINUE - - CASE(XMOD) - { - ON_OP(); - updateIOGas(); - - xmod(simdType()); - } - CONTINUE - - CASE(XSMOD) - { - ON_OP(); - updateIOGas(); - - xsmod(simdType()); - } - CONTINUE - - CASE(XLT) - { - ON_OP(); - updateIOGas(); - - xlt(simdType()); - } - CONTINUE - - CASE(XGT) - { - ON_OP(); - updateIOGas(); - - xgt(simdType()); - } - CONTINUE - - CASE(XSLT) - { - ON_OP(); - updateIOGas(); - - xslt(simdType()); - } - CONTINUE - - CASE(XSGT) - { - ON_OP(); - updateIOGas(); - - xsgt(simdType()); - } - CONTINUE - - CASE(XEQ) - { - ON_OP(); - updateIOGas(); - - xeq(simdType()); - } - CONTINUE - - CASE(XISZERO) - { - ON_OP(); - updateIOGas(); - - xzero(simdType()); - } - CONTINUE - - CASE(XAND) - { - ON_OP(); - updateIOGas(); - - xand(simdType()); - } - CONTINUE - - CASE(XOOR) - { - ON_OP(); - updateIOGas(); - - xoor(simdType()); - } - CONTINUE - - CASE(XXOR) - { - ON_OP(); - updateIOGas(); - - xxor(simdType()); - } - CONTINUE - - CASE(XNOT) - { - ON_OP(); - updateIOGas(); - - xnot(simdType()); - } - CONTINUE - - CASE(XSHL) - { - ON_OP(); - updateIOGas(); - - xshl(simdType()); - } - CONTINUE - - CASE(XSHR) - { - ON_OP(); - updateIOGas(); - - xshr(simdType()); - } - CONTINUE - - CASE(XSAR) - { - ON_OP(); - updateIOGas(); - - xsar(simdType()); - } - CONTINUE - - CASE(XROL) - { - ON_OP(); - updateIOGas(); - - xrol(simdType()); - } - CONTINUE - - CASE(XROR) - { - ON_OP(); - updateIOGas(); - - xror(simdType()); - } - CONTINUE - - CASE(XMLOAD) - { - updateMem(toInt63(m_SP[0]) + 32); - ON_OP(); - updateIOGas(); - - xmload(simdType()); - } - CONTINUE - CASE(XMSTORE) - { - updateMem(toInt63(m_SP[0]) + 32); - ON_OP(); - updateIOGas(); - - xmstore(simdType()); - } - CONTINUE - - CASE(XSLOAD) - { - m_runGas = toInt63(m_schedule->sloadGas); - ON_OP(); - updateIOGas(); - - xsload(simdType()); - } - CONTINUE - - CASE(XSSTORE) - { - if (m_message->flags & EVMC_STATIC) - throwDisallowedStateChange(); - - updateSSGas(); - ON_OP(); - updateIOGas(); - - xsstore(simdType()); - } - CONTINUE - - CASE(XVTOWIDE) - { - ON_OP(); - updateIOGas(); - - xvtowide(simdType()); - } - CONTINUE - - CASE(XWIDETOV) - { - ON_OP(); - updateIOGas(); - - xwidetov(simdType()); - } - CONTINUE - - CASE(XPUSH) - { - ON_OP(); - updateIOGas(); - - xpush(simdType()); - } - CONTINUE - - CASE(XPUT) - { - ON_OP(); - updateIOGas(); - - uint8_t b = ++m_PC; - uint8_t c = ++m_PC; - xput(m_code[b], m_code[c]); - ++m_PC; - } - CONTINUE - - CASE(XGET) - { - ON_OP(); - updateIOGas(); - - uint8_t b = ++m_PC; - uint8_t c = ++m_PC; - xget(m_code[b], m_code[c]); - ++m_PC; - } - CONTINUE - - CASE(XSWIZZLE) - { - ON_OP(); - updateIOGas(); - - xswizzle(simdType()); - } - CONTINUE - - CASE(XSHUFFLE) - { - ON_OP(); - updateIOGas(); - - xshuffle(simdType()); - } - CONTINUE -#else CASE(XADD) CASE(XMUL) CASE(XSUB) @@ -1253,7 +853,6 @@ void VM::interpretCases() throwBadInstruction(); } CONTINUE -#endif CASE(ADDRESS) { diff --git a/libevm/VM.h b/libaleth-interpreter/VM.h similarity index 74% rename from libevm/VM.h rename to libaleth-interpreter/VM.h index d08ab35a26f..aed71597ab6 100644 --- a/libevm/VM.h +++ b/libaleth-interpreter/VM.h @@ -17,9 +17,9 @@ #pragma once -#include "Instruction.h" #include "VMConfig.h" -#include "VMFace.h" + +#include #include #include @@ -67,12 +67,6 @@ class VM : public evmc_instance owning_bytes_ref exec(evmc_context* _context, evmc_revision _rev, const evmc_message* _msg, uint8_t const* _code, size_t _codeSize); -#if EIP_615 - // invalid code will throw an exeption - void validate(ExtVMFace& _ext); - void validateSubroutine(uint64_t _PC, uint64_t* _rp, u256* _sp); -#endif - bytes const& memory() const { return m_mem; } u256s stack() const { u256s stack(m_SP, m_stackEnd); @@ -114,14 +108,6 @@ class VM : public evmc_instance u256 *m_stackEnd = &m_stack[VMSchedule::stackLimit]; size_t stackSize() { return m_stackEnd - m_SP; } -#if EIP_615 - // space for return stack - uint64_t m_return[1024]; - - // mark PCs with frame size to detect cycles and stack mismatch - std::vector m_frameSize; -#endif - // constant pool std::vector m_pool; @@ -130,9 +116,6 @@ class VM : public evmc_instance uint64_t m_PC = 0; // program counter u256* m_SP = m_stackEnd; // stack pointer u256* m_SPP = m_SP; // stack pointer prime (next SP) -#if EIP_615 - uint64_t* m_RP = m_return - 1; // return pointer -#endif // metering and memory state uint64_t m_runGas = 0; @@ -198,59 +181,6 @@ class VM : public evmc_instance uint64_t w = uint64_t(v); return w; } - - // - // implementations of simd opcodes - // - // input bytes are the inline simd type descriptors for the operand vectors on the stack - // -#if EIP_616 - - void xadd (uint8_t); - void xmul (uint8_t); - void xsub (uint8_t); - void xdiv (uint8_t); - void xsdiv (uint8_t); - void xmod (uint8_t); - void xsmod (uint8_t); - void xlt (uint8_t); - void xslt (uint8_t); - void xgt (uint8_t); - void xsgt (uint8_t); - void xeq (uint8_t); - void xzero (uint8_t); - void xand (uint8_t); - void xoor (uint8_t); - void xxor (uint8_t); - void xnot (uint8_t); - void xshr (uint8_t); - void xsar (uint8_t); - void xshl (uint8_t); - void xrol (uint8_t); - void xror (uint8_t); - void xmload (uint8_t); - void xmstore (uint8_t); - void xsload (uint8_t); - void xsstore (uint8_t); - void xvtowide(uint8_t); - void xwidetov(uint8_t); - void xpush (uint8_t); - void xput (uint8_t, uint8_t); - void xget (uint8_t, uint8_t); - void xswizzle(uint8_t); - void xshuffle(uint8_t); - - u256 vtow(uint8_t _b, const u256& _in); - void wtov(uint8_t _b, u256 _in, u256& _o_out); - - uint8_t simdType() - { - uint8_t nt = m_code[++m_PC]; // advance PC and get simd type from code - ++m_PC; // advance PC to next opcode, ready to continue - return nt; - } - -#endif }; } diff --git a/libevm/VMCalls.cpp b/libaleth-interpreter/VMCalls.cpp similarity index 100% rename from libevm/VMCalls.cpp rename to libaleth-interpreter/VMCalls.cpp diff --git a/libevm/VMConfig.h b/libaleth-interpreter/VMConfig.h similarity index 98% rename from libevm/VMConfig.h rename to libaleth-interpreter/VMConfig.h index 7802bd5e72e..efde13b243a 100644 --- a/libevm/VMConfig.h +++ b/libaleth-interpreter/VMConfig.h @@ -24,9 +24,6 @@ namespace eth // // interpreter configuration macros for development, optimizations and tracing // -// EIP_615 - subroutines and static jumps -// EIP_616 - SIMD -// // EVM_OPTIMIZE - all optimizations off when false (TO DO - MAKE DYNAMIC) // // EVM_SWITCH_DISPATCH - dispatch via loop and switch @@ -38,14 +35,6 @@ namespace eth // // EVM_TRACE - provides various levels of tracing -#ifndef EIP_615 -#define EIP_615 false -#endif - -#ifndef EIP_616 -#define EIP_616 false -#endif - #ifndef EVM_JUMP_DISPATCH #ifdef __GNUC__ #define EVM_JUMP_DISPATCH true diff --git a/libevm/VMOpt.cpp b/libaleth-interpreter/VMOpt.cpp similarity index 91% rename from libevm/VMOpt.cpp rename to libaleth-interpreter/VMOpt.cpp index b294202119c..ca31be3cc1d 100644 --- a/libevm/VMOpt.cpp +++ b/libaleth-interpreter/VMOpt.cpp @@ -86,29 +86,6 @@ void VM::optimize() { pc += (byte)op - (byte)Instruction::PUSH1 + 1; } -#if EIP_615 - else if ( - op == Instruction::JUMPTO || - op == Instruction::JUMPIF || - op == Instruction::JUMPSUB) - { - ++pc; - pc += 4; - } - else if (op == Instruction::JUMPV || op == Instruction::JUMPSUBV) - { - ++pc; - pc += 4 * m_code[pc]; // number of 4-byte dests followed by table - } - else if (op == Instruction::BEGINSUB) - { - m_beginSubs.push_back(pc); - } - else if (op == Instruction::BEGINDATA) - { - break; - } -#endif } #ifdef EVM_DO_FIRST_PASS_OPTIMIZATION diff --git a/libaleth-interpreter/interpreter.h b/libaleth-interpreter/interpreter.h new file mode 100644 index 00000000000..2e534c6eda0 --- /dev/null +++ b/libaleth-interpreter/interpreter.h @@ -0,0 +1,22 @@ +/* Aleth: Ethereum C++ client, tools and libraries. + * Copyright 2018 Aleth Autors. + * Licensed under the GNU General Public License, Version 3. See the LICENSE file. + */ + +#pragma once + +#include + +#if __cplusplus +extern "C" { +/* TODO: Move NOEXCEPT to evmc.h */ +#define NOEXCEPT noexcept +#else +#define NOEXCEPT +#endif + +struct evmc_instance* evmc_create_interpreter() NOEXCEPT; + +#if __cplusplus +} +#endif diff --git a/libevm/CMakeLists.txt b/libevm/CMakeLists.txt index 64646c5111c..8d6a56485dc 100644 --- a/libevm/CMakeLists.txt +++ b/libevm/CMakeLists.txt @@ -3,17 +3,11 @@ set(sources EVMC.cpp EVMC.h ExtVMFace.cpp ExtVMFace.h Instruction.cpp Instruction.h - interpreter.h LegacyVM.cpp LegacyVM.h + LegacyVMConfig.h LegacyVMCalls.cpp LegacyVMOpt.cpp VMFace.h - VMConfig.h - VM.cpp VM.h - VMCalls.cpp - VMOpt.cpp - VMSIMD.cpp - VMValidate.cpp VMFactory.cpp VMFactory.h ) @@ -21,8 +15,8 @@ add_library(evm ${sources}) target_link_libraries( evm - PUBLIC ethcore devcore evmc::evmc evmc::instructions - PRIVATE aleth-buildinfo jsoncpp_lib_static Boost::program_options ${CMAKE_DL_LIBS} + PUBLIC ethcore devcore evmc::evmc + PRIVATE aleth-interpreter aleth-buildinfo jsoncpp_lib_static Boost::program_options ${CMAKE_DL_LIBS} ) if(EVM_OPTIMIZE) diff --git a/libevm/EVMC.cpp b/libevm/EVMC.cpp index 92159cff446..1ec7e34a70b 100644 --- a/libevm/EVMC.cpp +++ b/libevm/EVMC.cpp @@ -4,7 +4,6 @@ #include "EVMC.h" #include -#include #include namespace dev diff --git a/libevm/LegacyVM.h b/libevm/LegacyVM.h index 266ca350107..f4838f304c0 100644 --- a/libevm/LegacyVM.h +++ b/libevm/LegacyVM.h @@ -18,7 +18,7 @@ #pragma once #include "Instruction.h" -#include "VMConfig.h" +#include "LegacyVMConfig.h" #include "VMFace.h" namespace dev diff --git a/libevm/LegacyVMConfig.h b/libevm/LegacyVMConfig.h new file mode 100644 index 00000000000..7e879e9d1eb --- /dev/null +++ b/libevm/LegacyVMConfig.h @@ -0,0 +1,444 @@ +/* + 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 . +*/ +#pragma once + +namespace dev + { + namespace eth + { +/////////////////////////////////////////////////////////////////////////////// +// +// interpreter configuration macros for development, optimizations and tracing +// +// EIP_615 - subroutines and static jumps +// EIP_616 - SIMD +// +// EVM_OPTIMIZE - all optimizations off when false (TO DO - MAKE DYNAMIC) +// +// EVM_SWITCH_DISPATCH - dispatch via loop and switch +// EVM_JUMP_DISPATCH - dispatch via a jump table - available only on GCC +// +// EVM_USE_CONSTANT_POOL - constants unpacked and ready to assign to stack +// +// EVM_REPLACE_CONST_JUMP - pre-verified jumps to save runtime lookup +// +// EVM_TRACE - provides various levels of tracing + +#ifndef EIP_615 +#define EIP_615 false +#endif + +#ifndef EIP_616 +#define EIP_616 false +#endif + +#ifndef EVM_JUMP_DISPATCH +#ifdef __GNUC__ +#define EVM_JUMP_DISPATCH true +#else +#define EVM_JUMP_DISPATCH false +#endif +#endif +#if EVM_JUMP_DISPATCH + #ifndef __GNUC__ +#error "address of label extension available only on Gnu" +#endif +#else +#define EVM_SWITCH_DISPATCH true +#endif + +#ifndef EVM_OPTIMIZE +#define EVM_OPTIMIZE false +#endif +#if EVM_OPTIMIZE + #define EVM_REPLACE_CONST_JUMP true +#define EVM_USE_CONSTANT_POOL true +#define EVM_DO_FIRST_PASS_OPTIMIZATION (EVM_REPLACE_CONST_JUMP || EVM_USE_CONSTANT_POOL) +#endif + + +/////////////////////////////////////////////////////////////////////////////// +// +// set EVM_TRACE to 3, 2, 1, or 0 for lots to no tracing to cerr +// +#ifndef EVM_TRACE +#define EVM_TRACE 0 +#endif +#if EVM_TRACE > 0 + + #undef ON_OP +#if EVM_TRACE > 2 +#define ON_OP() \ + (cerr << "### " << ++m_nSteps << ": " << m_PC << " " << instructionInfo(m_OP).name << endl) +#else +#define ON_OP() onOperation() +#endif + +#define TRACE_STR(level, str) \ + if ((level) <= EVM_TRACE) \ + cerr << "$$$ " << (str) << endl; + +#define TRACE_VAL(level, name, val) \ + if ((level) <= EVM_TRACE) \ + cerr << "=== " << (name) << " " << hex << (val) << endl; +#define TRACE_OP(level, pc, op) \ + if ((level) <= EVM_TRACE) \ + cerr << "*** " << (pc) << " " << instructionInfo(op).name << endl; + +#define TRACE_PRE_OPT(level, pc, op) \ + if ((level) <= EVM_TRACE) \ + cerr << "<<< " << (pc) << " " << instructionInfo(op).name << endl; + +#define TRACE_POST_OPT(level, pc, op) \ + if ((level) <= EVM_TRACE) \ + cerr << ">>> " << (pc) << " " << instructionInfo(op).name << endl; +#else +#define TRACE_STR(level, str) +#define TRACE_VAL(level, name, val) +#define TRACE_OP(level, pc, op) +#define TRACE_PRE_OPT(level, pc, op) +#define TRACE_POST_OPT(level, pc, op) +#define ON_OP() onOperation() +#endif + +// Executive swallows exceptions in some circumstances +#if 0 +#define THROW_EXCEPTION(X) ((cerr << "!!! EVM EXCEPTION " << (X).what() << endl), abort()) +#else +#if EVM_TRACE > 0 + #define THROW_EXCEPTION(X) \ + ((cerr << "!!! EVM EXCEPTION " << (X).what() << endl), BOOST_THROW_EXCEPTION(X)) +#else +#define THROW_EXCEPTION(X) BOOST_THROW_EXCEPTION(X) +#endif +#endif + + +/////////////////////////////////////////////////////////////////////////////// +// +// build a simple loop-and-switch interpreter +// +#if EVM_SWITCH_DISPATCH + + #define INIT_CASES +#define DO_CASES \ + for (;;) \ + { \ + fetchInstruction(); \ + switch (m_OP) \ + { +#define CASE(name) case Instruction::name: +#define NEXT \ + ++m_PC; \ + break; +#define CONTINUE continue; +#define BREAK return; +#define DEFAULT default: +#define WHILE_CASES \ + } \ + } + + +/////////////////////////////////////////////////////////////////////////////// +// +// build an indirect-threaded interpreter using a jump table of +// label addresses (a gcc extension) +// +#elif EVM_JUMP_DISPATCH + + #define INIT_CASES \ + \ + static const void* const jumpTable[256] = { \ + &&STOP, /* 00 */ \ + &&ADD, \ + &&MUL, \ + &&SUB, \ + &&DIV, \ + &&SDIV, \ + &&MOD, \ + &&SMOD, \ + &&ADDMOD, \ + &&MULMOD, \ + &&EXP, \ + &&SIGNEXTEND, \ + &&INVALID, \ + &&INVALID, \ + &&INVALID, \ + &&INVALID, \ + &<, /* 10, */ \ + &>, \ + &&SLT, \ + &&SGT, \ + &&EQ, \ + &&ISZERO, \ + &&AND, \ + &&OR, \ + &&XOR, \ + &&NOT, \ + &&BYTE, \ + &&SHL, \ + &&SHR, \ + &&SAR, \ + &&INVALID, \ + &&INVALID, \ + &&SHA3, /* 20, */ \ + &&INVALID, \ + &&INVALID, \ + &&INVALID, \ + &&INVALID, \ + &&INVALID, \ + &&INVALID, \ + &&INVALID, \ + &&INVALID, \ + &&INVALID, \ + &&INVALID, \ + &&INVALID, \ + &&INVALID, \ + &&INVALID, \ + &&INVALID, \ + &&INVALID, \ + &&ADDRESS, /* 30, */ \ + &&BALANCE, \ + &&ORIGIN, \ + &&CALLER, \ + &&CALLVALUE, \ + &&CALLDATALOAD, \ + &&CALLDATASIZE, \ + &&CALLDATACOPY, \ + &&CODESIZE, \ + &&CODECOPY, \ + &&GASPRICE, \ + &&EXTCODESIZE, \ + &&EXTCODECOPY, \ + &&RETURNDATASIZE, \ + &&RETURNDATACOPY, \ + &&INVALID, \ + &&BLOCKHASH, /* 40, */ \ + &&COINBASE, \ + &&TIMESTAMP, \ + &&NUMBER, \ + &&DIFFICULTY, \ + &&GASLIMIT, \ + &&INVALID, \ + &&INVALID, \ + &&INVALID, \ + &&INVALID, \ + &&INVALID, \ + &&INVALID, \ + &&INVALID, \ + &&INVALID, \ + &&INVALID, \ + &&INVALID, \ + &&POP, /* 50, */ \ + &&MLOAD, \ + &&MSTORE, \ + &&MSTORE8, \ + &&SLOAD, \ + &&SSTORE, \ + &&JUMP, \ + &&JUMPI, \ + &&PC, \ + &&MSIZE, \ + &&GAS, \ + &&JUMPDEST, \ + &&BEGINDATA, \ + &&BEGINSUB, \ + &&INVALID, \ + &&INVALID, \ + &&PUSH1, /* 60, */ \ + &&PUSH2, \ + &&PUSH3, \ + &&PUSH4, \ + &&PUSH5, \ + &&PUSH6, \ + &&PUSH7, \ + &&PUSH8, \ + &&PUSH9, \ + &&PUSH10, \ + &&PUSH11, \ + &&PUSH12, \ + &&PUSH13, \ + &&PUSH14, \ + &&PUSH15, \ + &&PUSH16, \ + &&PUSH17, /* 70, */ \ + &&PUSH18, \ + &&PUSH19, \ + &&PUSH20, \ + &&PUSH21, \ + &&PUSH22, \ + &&PUSH23, \ + &&PUSH24, \ + &&PUSH25, \ + &&PUSH26, \ + &&PUSH27, \ + &&PUSH28, \ + &&PUSH29, \ + &&PUSH30, \ + &&PUSH31, \ + &&PUSH32, \ + &&DUP1, /* 80, */ \ + &&DUP2, \ + &&DUP3, \ + &&DUP4, \ + &&DUP5, \ + &&DUP6, \ + &&DUP7, \ + &&DUP8, \ + &&DUP9, \ + &&DUP10, \ + &&DUP11, \ + &&DUP12, \ + &&DUP13, \ + &&DUP14, \ + &&DUP15, \ + &&DUP16, \ + &&SWAP1, /* 90, */ \ + &&SWAP2, \ + &&SWAP3, \ + &&SWAP4, \ + &&SWAP5, \ + &&SWAP6, \ + &&SWAP7, \ + &&SWAP8, \ + &&SWAP9, \ + &&SWAP10, \ + &&SWAP11, \ + &&SWAP12, \ + &&SWAP13, \ + &&SWAP14, \ + &&SWAP15, \ + &&SWAP16, \ + &&LOG0, /* A0, */ \ + &&LOG1, \ + &&LOG2, \ + &&LOG3, \ + &&LOG4, \ + &&INVALID, \ + &&INVALID, \ + &&INVALID, \ + &&INVALID, \ + &&INVALID, \ + &&INVALID, \ + &&INVALID, \ + &&PUSHC, \ + &&JUMPC, \ + &&JUMPCI, \ + &&INVALID, \ + &&JUMPTO, /* B0, */ \ + &&JUMPIF, \ + &&JUMPSUB, \ + &&JUMPV, \ + &&JUMPSUBV, \ + &&BEGINSUB, \ + &&BEGINDATA, \ + &&RETURNSUB, \ + &&PUTLOCAL, \ + &&GETLOCAL, \ + &&INVALID, \ + &&INVALID, \ + &&INVALID, \ + &&INVALID, \ + &&INVALID, \ + &&INVALID, \ + &&INVALID, /* C0, */ \ + &&XADD, \ + &&XMUL, \ + &&XSUB, \ + &&XDIV, \ + &&XSDIV, \ + &&XMOD, \ + &&XSMOD, \ + &&INVALID, \ + &&INVALID, \ + &&INVALID, \ + &&INVALID, \ + &&INVALID, \ + &&INVALID, \ + &&INVALID, \ + &&INVALID, \ + &&XLT, /* D0 */ \ + &&XGT, \ + &&XSLT, \ + &&XSGT, \ + &&XEQ, \ + &&XISZERO, \ + &&XAND, \ + &&XOOR, \ + &&XXOR, \ + &&XNOT, \ + &&INVALID, \ + &&XSHL, \ + &&XSHR, \ + &&XSAR, \ + &&XROL, \ + &&XROR, \ + &&XPUSH, /* E0, */ \ + &&XMLOAD, \ + &&XMSTORE, \ + &&INVALID, \ + &&XSLOAD, \ + &&XSSTORE, \ + &&XVTOWIDE, \ + &&XWIDETOV, \ + &&XGET, \ + &&XPUT, \ + &&XSWIZZLE, \ + &&XSHUFFLE, \ + &&INVALID, \ + &&INVALID, \ + &&INVALID, \ + &&INVALID, \ + &&CREATE, /* F0, */ \ + &&CALL, \ + &&CALLCODE, \ + &&RETURN, \ + &&DELEGATECALL, \ + &&INVALID, \ + &&INVALID, \ + &&INVALID, \ + &&INVALID, \ + &&INVALID, \ + &&STATICCALL, \ + &&CREATE2, \ + &&INVALID, \ + &&REVERT, \ + &&INVALID, \ + &&SUICIDE, \ + }; + +#define DO_CASES \ + fetchInstruction(); \ + goto* jumpTable[(int)m_OP]; +#define CASE(name) \ + name: +#define NEXT \ + ++m_PC; \ + fetchInstruction(); \ + goto* jumpTable[(int)m_OP]; +#define CONTINUE \ + fetchInstruction(); \ + goto* jumpTable[(int)m_OP]; +#define BREAK return; +#define DEFAULT +#define WHILE_CASES + +#else +#error No opcode dispatch configured +#endif + } + } diff --git a/libevm/VMFactory.cpp b/libevm/VMFactory.cpp index 86f9d435358..652885b8fe5 100644 --- a/libevm/VMFactory.cpp +++ b/libevm/VMFactory.cpp @@ -18,7 +18,8 @@ #include "VMFactory.h" #include "EVMC.h" #include "LegacyVM.h" -#include "interpreter.h" + +#include #include #include diff --git a/libevm/VMSIMD.cpp b/libevm/VMSIMD.cpp deleted file mode 100644 index 99e30772e7d..00000000000 --- a/libevm/VMSIMD.cpp +++ /dev/null @@ -1,737 +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 . -*/ - -#include "VM.h" - -#if EIP_616 - -namespace dev -{ -namespace eth -{ - -// conversion functions to overlay vectors on storage for u256 stack slots -// a dirty trick but it keeps the SIMD types from polluting the rest of the VM -// so at least assert there's room for the trick, and use wrappers for some safety -static_assert(sizeof(uint64_t[4]) <= sizeof(u256), "stack slot too narrow for SIMD"); -using a64x4 = uint64_t[4]; -using a32x8 = uint32_t[8]; -using a16x16 = uint16_t[16]; -using a8x32 = uint8_t [32]; - -inline a64x4 & v64x4 (u256 & _stackItem) { return (a64x4&) *(a64x4*) &_stackItem; } -inline a32x8 & v32x8 (u256 & _stackItem) { return (a32x8&) *(a32x8*) &_stackItem; } -inline a16x16 & v16x16(u256 & _stackItem) { return (a16x16&)*(a16x16*)&_stackItem; } -inline a8x32 & v8x32 (u256 & _stackItem) { return (a8x32&) *(a8x32*) &_stackItem; } -inline a64x4 const& v64x4 (u256 const& _stackItem) { return (a64x4&) *(a64x4*) &_stackItem; } -inline a32x8 const& v32x8 (u256 const& _stackItem) { return (a32x8&) *(a32x8*) &_stackItem; } -inline a16x16 const& v16x16(u256 const& _stackItem) { return (a16x16&)*(a16x16*)&_stackItem; } -inline a8x32 const& v8x32 (u256 const& _stackItem) { return (a8x32&) *(a8x32*) &_stackItem; } - -enum { Bits8, Bits16, Bits32, Bits64 }; - -// tried using template template functions, gave up fighting the compiler after a day -#define EVALXOPS(OP, _type) EVALXOP(OP, int8_t, int16_t, int32_t, int64_t, _type) -#define EVALXOPU(OP, _type) EVALXOP(OP, uint8_t, uint16_t, uint32_t, uint64_t, _type) -#define EVALXOP(OP, T8, T16, T32, T64, _type) \ -{ \ - uint8_t const t = (_type) & 0xf; \ - m_SPP[0] = 0; \ - switch (t) \ - { \ - case Bits8: \ - for (int i = 0; i < 32; ++i) \ - v8x32(m_SPP[0])[i] = (uint8_t) OP((T8) v8x32(m_SP[0])[i], (T8) v8x32(m_SP[1])[i]); \ - break; \ - case Bits16: \ - for (int i = 0; i < 16; ++i) \ - v16x16(m_SPP[0])[i] = (uint16_t)OP((T16)v16x16(m_SP[0])[i], (T16)v16x16(m_SP[1])[i]); \ - break; \ - case Bits32: \ - for (int i = 0; i < 8; ++i) \ - v32x8(m_SPP[0])[i] = (uint32_t)OP((T32)v32x8(m_SP[0])[i], (T32)v32x8(m_SP[1])[i]); \ - break; \ - case Bits64: \ - for (int i = 0; i < 4; ++i) \ - v64x4(m_SPP[0])[i] = (uint64_t)OP((T64)v64x4(m_SP[0])[i], (T64)v64x4(m_SP[1])[i]); \ - break; \ - default: throwBadInstruction(); \ - } \ -} -#define ADD( x1, x2) ((x1) + (x2)) -#define MUL( x1, x2) ((x1) * (x2)) -#define SUB( x1, x2) ((x1) - (x2)) -#define DIV( x1, x2) ((x1) / (x2)) -#define MOD( x1, x2) ((x1) % (x2)) -#define LT( x1, x2) ((x1) < (x2)) -#define GT( x1, x2) ((x1) > (x2)) -#define EQ( x1, x2) ((x1) == (x2)) -#define ZERO(x1, x2) ((x1) == 0) -#define AND( x1, x2) ((x1) & (x2)) -#define OR( x1, x2) ((x1) | (x2)) -#define XOR( x1, x2) ((x1) ^ (x2)) -#define NOT( x1, x2) (~(x1)) -#define SHR( x1, x2) ((x1) >> (x2)) -#define SHL( x1, x2) ((x1) << (x2)) -#define ROL( x1, x2) (((x1) << (x2))|((x1) >> (sizeof(x1) * 8 - (x2)))) -#define ROR( x1, x2) (((x1) >> (x2))|((x1) << (sizeof(x1) * 8 - (x2)))) - -void VM::xadd (uint8_t _type) { EVALXOPU(ADD, _type); } -void VM::xmul (uint8_t _type) { EVALXOPU(MUL, _type); } -void VM::xsub (uint8_t _type) { EVALXOPU(SUB, _type); } -void VM::xdiv (uint8_t _type) { EVALXOPU(DIV, _type); } -void VM::xsdiv(uint8_t _type) { EVALXOPS(DIV, _type); } -void VM::xmod (uint8_t _type) { EVALXOPU(MOD, _type); } -void VM::xsmod(uint8_t _type) { EVALXOPS(MOD, _type); } -void VM::xlt (uint8_t _type) { EVALXOPU(LT, _type); } -void VM::xslt (uint8_t _type) { EVALXOPS(LT, _type); } -void VM::xgt (uint8_t _type) { EVALXOPU(GT, _type); } -void VM::xsgt (uint8_t _type) { EVALXOPS(GT, _type); } -void VM::xeq (uint8_t _type) { EVALXOPU(EQ, _type); } -void VM::xzero(uint8_t _type) { EVALXOPU(ZERO,_type); } -void VM::xand (uint8_t _type) { EVALXOPU(AND, _type); } -void VM::xoor (uint8_t _type) { EVALXOPU(OR, _type); } -void VM::xxor (uint8_t _type) { EVALXOPU(XOR, _type); } -void VM::xnot (uint8_t _type) { EVALXOPU(NOT, _type); } -void VM::xshr (uint8_t _type) { EVALXOPU(SHR, _type); } -void VM::xsar (uint8_t _type) { EVALXOPS(SHR, _type); } -void VM::xshl (uint8_t _type) { EVALXOPU(SHL, _type); } -void VM::xrol (uint8_t _type) { EVALXOPU(ROL, _type); } -void VM::xror (uint8_t _type) { EVALXOPU(ROR, _type); } - -// SIMD type encodes log base 2 of lane width and count - one in each nibble -// -inline uint8_t pow2N(uint8_t _n) -{ - static uint8_t exp[6] = { 1, 2, 4, 8, 16, 32 }; - return exp[_n]; -} - -inline uint8_t laneCount(uint8_t _type) -{ - return pow2N(_type & 0xf); -} - -inline uint8_t laneWidth(uint8_t _type) -{ - return pow2N(_type >> 4); -} - -// in must be by reference because it is really just memory for a vector -u256 VM::vtow(uint8_t _type, const u256& _in) -{ - u256 out; - uint8_t const count = laneCount(_type); - uint8_t const width = laneWidth(_type); - switch (width) - { - case Bits8: - for (int i = count - 1; 0 <= i; --i) - { - out << 8; - out |= v8x32(_in) [i]; - } - break; - case Bits16: - for (int i = count - 1; 0 <= i; --i) - { - out << 16; - out |= v16x16(_in)[i]; - } - break; - case Bits32: - for (int i = count - 1; 0 <= i; --i) - { - out << 32; - out |= v32x8(_in) [i]; - } - break; - case Bits64: - for (int i = count - 1; 0 <= i; --i) - { - out << 64; - out |= v64x4(_in) [i]; - } - break; - default: - throwBadInstruction(); - } - return out; -} - -// out must be by reference because it is really just memory for a vector -void VM::wtov(uint8_t _type, u256 _in, u256& o_out) -{ - uint8_t const count = laneCount(_type); - uint8_t const width = laneWidth(_type); - switch (width) - { - case Bits8: - for (int i = count - 1; 0 <= i; --i) - { - v8x32(o_out) [i] = (uint8_t )(_in & 0xff); - _in >>= 8; - } - break; - case Bits16: - for (int i = count - 1; 0 <= i; --i) - { - v16x16(o_out)[i] = (uint16_t)(_in & 0xffff); - _in >>= 16; - } - break; - case Bits32: - for (int i = count - 1; 0 <= i; --i) - { - v32x8(o_out) [i] = (uint32_t)(_in & 0xffffff); - _in >>= 32; - } - break; - case Bits64: - for (int i = count - 1; 0 <= i; --i) - { - v64x4(o_out) [i] = (uint64_t)(_in & 0xffffffff); - _in >>= 64; - } - break; - default: - throwBadInstruction(); - } -} - -void VM::xmload (uint8_t _type) -{ - // goes onto stack element by element, LSB first - uint8_t const* vecData = m_mem.data() + toInt15(m_SP[0]); - uint8_t const count = laneCount(_type); - uint8_t const width = laneWidth(_type); - - switch (width) - { - case Bits8: - for (int j = count, i = count - 1; 0 <= i; --i) - { - int v = 0; - v |= vecData[--j]; - v8x32(m_SPP[0])[i] = v; - } - break; - case Bits16: - for (int j = count, i = count - 1; 0 <= i; --i) - { - int v = 0; - v |= vecData[--j]; - v <<= 8; - v |= vecData[--j]; - v16x16(m_SPP[0])[i] = v; - } - break; - case Bits32: - for (int j = count, i = count - 1; 0 <= i; --i) - { - int v = 0; - v |= vecData[--j]; - v <<= 8; - v |= vecData[--j]; - v <<= 8; - v |= vecData[--j]; - v <<= 8; - v |= vecData[--j]; - v32x8(m_SPP[0])[i] = v; - } - break; - case Bits64: - for (int j = count, i = count - 1; 0 <= i; --i) - { - int v = 0; - v |= vecData[--j]; - v <<= 8; - v |= vecData[--j]; - v <<= 8; - v |= vecData[--j]; - v <<= 8; - v |= vecData[--j]; - v <<= 8; - v |= vecData[--j]; - v <<= 8; - v |= vecData[--j]; - v <<= 8; - v |= vecData[--j]; - v <<= 8; - v |= vecData[--j]; - v64x4(m_SPP[0])[i] = v; - } - break; - default: - throwBadInstruction(); - } -} - -void VM::xmstore(uint8_t _type) -{ - // n bytes of type t elements in stack vector - // goes onto memory by element, LSB first - uint8_t* vecData = m_mem.data() + toInt15(m_SP[0]); - uint8_t const count = laneCount(_type); - uint8_t const width = laneWidth(_type); - - switch (width) - { - case Bits8: - for (int j = count, i = count - 1; 0 <= i; --i) - { - int v = 0; - v = v8x32(m_SPP[0])[i]; - vecData[--j] = (uint8_t)v; - } - break; - case Bits16: - for (int j = count, i = count - 1; 0 <= i; --i) - { - int v = 2; - v = v16x16(m_SPP[0])[i]; - vecData[--j] = (uint8_t)v; - v >>= 8; - vecData[--j] = (uint8_t)v; - } - break; - case Bits32: - for (int j = count, i = count - 1; 0 <= i; --i) - { - int v = 4; - v = v32x8(m_SPP[0])[i]; - vecData[--j] = (uint8_t)v; - v >>= 8; - vecData[--j] = (uint8_t)v; - v >>= 8; - vecData[--j] = (uint8_t)v; - v >>= 8; - vecData[--j] = (uint8_t)v; - } - break; - case Bits64: - for (int j = count, i = count - 1; 0 <= i; --i) - { - int v = 0; - v = v64x4(m_SPP[0])[i]; - vecData[--j] = (uint8_t)v; - v >>= 8; - vecData[--j] = (uint8_t)v; - v >>= 8; - vecData[--j] = (uint8_t)v; - v >>= 8; - vecData[--j] = (uint8_t)v; - v >>= 8; - vecData[--j] = (uint8_t)v; - v >>= 8; - vecData[--j] = (uint8_t)v; - v >>= 8; - vecData[--j] = (uint8_t)v; - v >>= 8; - vecData[--j] = (uint8_t)v; - } - break; - default: - throwBadInstruction(); - } -} - -void VM::xsload(uint8_t _type) -{ - u256 w = m_ext->store(m_SP[0]); - wtov(_type, w, m_SPP[0]); -} - -void VM::xsstore(uint8_t _type) -{ - u256 w = vtow(_type, m_SP[1]); - m_ext->setStore(m_SP[0], w); -} - -void VM::xvtowide(uint8_t _type) -{ - m_SPP[0] = vtow(_type, m_SP[0]); -} - -void VM::xwidetov(uint8_t _type) -{ - wtov(_type, m_SP[0], m_SPP[0]); -} - -void VM::xpush(uint8_t _type) -{ - uint8_t const count = laneCount(_type); - uint8_t const width = laneWidth(_type); - - // Construct a vector out of n bytes following XPUSH. - // This requires the code has been copied and extended by 32 zero - // bytes to handle "out of code" push data here. - - // given the type of the vector - // mask and shift in the inline bytes - m_SPP[0] = 0; - switch (width) - { - case Bits8: - for (int i = 0; i < count ; ++i) - { - v8x32(m_SPP[0])[i] = m_code[++m_PC]; - } - break; - case Bits16: - for (int i = 0; i < count; ++i) - { - uint16_t v = m_code[++m_PC]; - v = (v << 8) | m_code[++m_PC]; - v16x16(m_SPP[0])[i] = v; - } - break; - case Bits32: - for (int i = 0; i < count; ++i) - { - uint32_t v = m_code[m_PC]; - v = (v << 8) | m_code[++m_PC]; - v = (v << 8) | m_code[++m_PC]; - v = (v << 8) | m_code[++m_PC]; - v32x8(m_SPP[0])[i] = v; - } - break; - case Bits64: - for (int i = 0; i < count; ++i) - { - uint64_t v = m_code[++m_PC]; - v = (v << 8) | m_code[++m_PC]; - v = (v << 8) | m_code[++m_PC]; - v = (v << 8) | m_code[++m_PC]; - v = (v << 8) | m_code[++m_PC]; - v = (v << 8) | m_code[++m_PC]; - v = (v << 8) | m_code[++m_PC]; - v = (v << 8) | m_code[++m_PC]; - v64x4(m_SPP[0])[i] = v; - } - break; - default: - throwBadInstruction(); - } -} - -void VM::xget(uint8_t _srcType, uint8_t _idxType) -{ - uint8_t const srcWidth = laneWidth(_srcType); - uint8_t const idxCount = laneCount(_idxType); - uint8_t const idxWidth = laneWidth(_idxType); - - // given the type of the source and index - // for every element of the index get the indexed element from the source - switch (srcWidth) - { - case Bits8: - - switch (idxWidth) - { - case Bits8: - for (int i = 0; i < idxCount; ++i) - v8x32 (m_SPP[1])[i] = v8x32(m_SP[0])[v8x32 (m_SP[1])[i] % idxCount]; - break; - case Bits16: - for (int i = 0; i< idxCount; ++i) - v16x16(m_SPP[1])[i] = v8x32(m_SP[0])[v16x16(m_SP[1])[i] % idxCount]; - break; - case Bits32: - for (int i = 0; i< idxCount; ++i) - v32x8 (m_SPP[1])[i] = v8x32(m_SP[0])[v32x8 (m_SP[1])[i] % idxCount]; - break; - case Bits64: - for (int i = 0; i< idxCount; ++i) - v64x4 (m_SPP[1])[i] = v8x32(m_SP[0])[v64x4 (m_SP[1])[i] % idxCount]; - break; - default: - throwBadInstruction(); - } - break; - - case Bits16: - - switch (idxWidth) - { - case Bits8: - for (int i = 0; i < idxCount; ++i) - v8x32 (m_SPP[0])[i] = v16x16(m_SP[1])[v8x32 (m_SP[0])[i] % idxCount]; - break; - case Bits16: - for (int i = 0; i < idxCount; ++i) - v16x16(m_SPP[0])[i] = v16x16(m_SP[1])[v16x16(m_SP[0])[i] % idxCount]; - break; - case Bits32: - for (int i = 0; i < idxCount; ++i) - v32x8 (m_SPP[0])[i] = v16x16(m_SP[1])[v32x8 (m_SP[0])[i] % idxCount]; - break; - case Bits64: - for (int i = 0; i < idxCount; ++i) - v64x4 (m_SPP[0])[i] = v16x16(m_SP[1])[v64x4 (m_SP[0])[i] % idxCount]; - break; - default: - throwBadInstruction(); - } - break; - - case Bits32: - - switch (idxWidth) - { - case Bits8: - for (int i = 0; i < idxCount; ++i) - v8x32 (m_SPP[0])[i] = v32x8(m_SP[1])[v8x32 (m_SP[0])[i] % idxCount]; - break; - case Bits16: - for (int i = 0; i < idxCount; ++i) - v16x16(m_SPP[0])[i] = v32x8(m_SP[1])[v16x16(m_SP[0])[i] % idxCount]; - break; - case Bits32: - for (int i = 0; i < idxCount; ++i) - v32x8 (m_SPP[0])[i] = v32x8(m_SP[1])[v32x8 (m_SP[0])[i] % idxCount]; - break; - case Bits64: - for (int i = 0; i < idxCount; ++i) - v64x4 (m_SPP[0])[i] = v32x8(m_SP[1])[v64x4 (m_SP[0])[i] % idxCount]; - break; - default: - throwBadInstruction(); - } - break; - - case Bits64: - - switch (idxWidth) - { - case Bits8: - for (int i = 0; i < idxCount; ++i) - v8x32 (m_SPP[0])[i] = v64x4(m_SP[1])[v8x32 (m_SP[0])[i] % idxCount]; - break; - case Bits16: - for (int i = 0; i < idxCount; ++i) - v16x16(m_SPP[0])[i] = v64x4(m_SP[1])[v16x16(m_SP[0])[i] % idxCount]; - break; - case Bits32: - for (int i = 0; i < idxCount; ++i) - v32x8 (m_SPP[0])[i] = v64x4(m_SP[1])[v32x8 (m_SP[0])[i] % idxCount]; - break; - case Bits64: - for (int i = 0; i < idxCount; ++i) - v64x4 (m_SPP[0])[i] = v64x4(m_SP[1])[v64x4 (m_SP[0])[i] % idxCount]; - break; - default: - throwBadInstruction(); - } - break; - - default: - throwBadInstruction(); - } -} - -void VM::xput(uint8_t _srcType, uint8_t _dstType) -{ - uint8_t const srcWidth = laneWidth(_srcType); - uint8_t const dstCount = laneCount(_dstType); - uint8_t const dstWidth = laneWidth(_dstType); - - // given the type of the source, destination and index - // for every element of the index put the indexed replacement in the destination - switch (srcWidth) - { - case Bits8: - - switch (dstWidth) - { - case Bits8: - for (int i = 0; i < dstCount; ++i) - v8x32 (m_SPP[0])[v8x32(m_SP[1])[i] % 32] = v8x32(m_SP[0])[i]; - break; - case Bits16: - for (int i = 0; i < dstCount; ++i) - v16x16(m_SPP[0])[v8x32(m_SP[1])[i] % 16] = v8x32(m_SP[0])[i]; - break; - case Bits32: - for (int i = 0; i < dstCount; ++i) - v32x8 (m_SPP[0])[v8x32(m_SP[1])[i] % 8] = v8x32(m_SP[0])[i]; - break; - case Bits64: - for (int i = 0; i < dstCount; ++i) - v64x4 (m_SPP[0])[v8x32(m_SP[1])[i] % 4] = v8x32(m_SP[0])[i]; - break; - default: - throwBadInstruction(); - } - break; - - case Bits16: - - switch (dstWidth) - { - case Bits8: - for (int i = 0; i < dstCount; ++i) - v8x32 (m_SPP[0])[v16x16(m_SP[1])[i] % 32] = v16x16(m_SP[0])[i]; - break; - case Bits16: - for (int i = 0; i < dstCount; ++i) - v16x16(m_SPP[0])[v16x16(m_SP[1])[i] % 16] = v16x16(m_SP[0])[i]; - break; - case Bits32: - for (int i = 0; i < dstCount; ++i) - v32x8(m_SPP[0])[v16x16(m_SP[1])[i] % 8] = v16x16(m_SP[0])[i]; - break; - case Bits64: - for (int i = 0; i < dstCount; ++i) - v64x4(m_SPP[0])[v16x16(m_SP[1])[i] % 4] = v16x16(m_SP[0])[i]; - break; - default: - throwBadInstruction(); - } - break; - - case Bits32: - - switch (dstWidth) - { - case Bits8: - for (int i = 0; i < dstCount; ++i) - v8x32 (m_SPP[0])[v32x8(m_SP[1])[i] % 32] = v32x8(m_SP[0])[i]; - break; - case Bits16: - for (int i = 0; i < dstCount; ++i) - v16x16(m_SPP[0])[v32x8(m_SP[1])[i] % 16] = v32x8(m_SP[0])[i]; - break; - case Bits32: - for (int i = 0; i < dstCount; ++i) - v32x8 (m_SPP[0])[v32x8(m_SP[1])[i] % 8] = v32x8(m_SP[0])[i]; - break; - case Bits64: - for (int i = 0; i < dstCount; ++i) - v64x4 (m_SPP[0])[v32x8(m_SP[1])[i] % 4] = v32x8(m_SP[0])[i]; - break; - default: - throwBadInstruction(); - } - break; - - case Bits64: - - switch (dstWidth) - { - case Bits8: - for (int i = 0; i < dstCount; ++i) - v8x32 (m_SPP[0])[v64x4(m_SP[1])[i] % 32] = v64x4(m_SP[0])[i]; - break; - case Bits16: - for (int i = 0; i < dstCount; ++i) - v16x16(m_SPP[0])[v64x4(m_SP[1])[i] % 16] = v64x4(m_SP[0])[i]; - break; - case Bits32: - for (int i = 0; i < dstCount; ++i) - v32x8 (m_SPP[0])[v64x4(m_SP[1])[i] % 8] = v64x4(m_SP[0])[i]; - break; - case Bits64: - for (int i = 0; i < dstCount; ++i) - v64x4 (m_SPP[0])[v64x4(m_SP[1])[i] % 4] = v64x4(m_SP[0])[i]; - break; - default: - throwBadInstruction(); - } - break; - - default: - throwBadInstruction(); - } -} - -void VM::xswizzle(uint8_t _type) -{ - uint8_t const count = laneCount(_type); - uint8_t const width = laneWidth(_type); - - // given the type of the source and mask - // for every index in the mask copy out the indexed value in the source - switch (width) - { - case Bits8: - for (int i = 0; i < count; ++i) - v8x32 (m_SPP[0])[i] = v8x32(m_SP[1]) [v8x32 (m_SP[0])[i] % count]; - break; - case Bits16: - for (int i = 0; i < count; ++i) - v16x16(m_SPP[0])[i] = v16x16(m_SP[1])[v16x16(m_SP[0])[i] % count]; - break; - case Bits32: - for (int i = 0; i < count; ++i) - v32x8 (m_SPP[0])[i] = v32x8(m_SP[1]) [v32x8 (m_SP[0])[i] % count]; - break; - case Bits64: - for (int i = 0; i < count; ++i) - v64x4 (m_SPP[0])[i] = v64x4(m_SP[1]) [v64x4 (m_SP[0])[i] % count]; - break; - default: - throwBadInstruction(); - } -} - -void VM::xshuffle(uint8_t _type) -{ - // n type t elements in source and mask vectors - uint8_t const count = laneCount(_type); - uint8_t const width = laneWidth(_type); - - // given the type of the sources and mask - // for every index in the mask copy out the indexed value in one of the sources - switch (width) - { - case Bits8: - for (int i = 0; i < count; ++i) - { - int j = v8x32(m_SP[0]) [i]; - v8x32 (m_SPP[0])[i] = j < count ? v8x32(m_SP[1]) [j] : v8x32 (m_SP[2])[(j - count) % count]; - } - break; - case Bits16: - for (int i = 0; i < count; ++i) - { - int j = v16x16(m_SP[0])[i]; - v16x16(m_SPP[0])[i] = j < count ? v16x16(m_SP[1])[j] : v16x16(m_SP[2])[(j - count) % count]; - } - break; - case Bits32: - for (int i = 0; i < count; ++i) - { - int j = v32x8(m_SP[0]) [i]; - v32x8 (m_SPP[0])[i] = j < count ? v32x8(m_SP[1]) [j] : v32x8 (m_SP[2])[(j - count) % count]; - } - break; - case Bits64: - for (int i = 0; i < count; ++i) - { - int j = v64x4(m_SP[0]) [i]; - v64x4 (m_SPP[0])[i] = j < count ? v64x4(m_SP[1]) [j] : v64x4 (m_SP[2])[(j - count) % count]; - } - break; - default: - throwBadInstruction(); - } -} - -}} - -#endif diff --git a/libevm/VMValidate.cpp b/libevm/VMValidate.cpp deleted file mode 100644 index 77ef82d4542..00000000000 --- a/libevm/VMValidate.cpp +++ /dev/null @@ -1,171 +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 . -*/ - -#if EIP_615 - -// validator is not a full interpreter, canot support optimized dispatch -#define EVM_JUMP_DISPATCH false - -#include "VM.h" - -using namespace std; -using namespace dev; -using namespace dev::eth; - -/////////////////////////////////////////////////////////////////////////////// -// -// invalid code will throw an exception -// - -void VM::validate(ExtVMFace& _ext) -{ - m_ext = &_ext; - initEntry(); - size_t PC; - Instruction OP; - for (PC = 0; bool(OP = Instruction(m_code[PC])); ++PC) - { - if (OP == Instruction::BEGINSUB) - validateSubroutine(PC, m_return, m_stack); - else if (OP == Instruction::BEGINDATA) - break; - else if ( - Instruction::PUSH1 <= OP && - PC <= (size_t)Instruction::PUSH32) - PC += (size_t)OP - (size_t)Instruction::PUSH1; - else if ( - OP == Instruction::JUMPTO || - OP == Instruction::JUMPIF || - OP == Instruction::JUMPSUB) - PC += 4; - else if (OP == Instruction::JUMPV || OP == Instruction::JUMPSUBV) - PC += 4 * m_code[PC]; // number of 4-byte dests followed by table - } -} - -// we validate each subroutine individually, as if at top level -// - PC is the offset in the code to start validating at -// - RP is the top PC on return stack that RETURNSUB returns to -// - SP = FP at the top level, so the stack size is also the frame size -void VM::validateSubroutine(uint64_t _pc, uint64_t* _rp, u256* _sp) -{ - // set current interpreter state - m_PC = _pc, m_RP = _rp, m_SP = _sp; - - INIT_CASES - DO_CASES - { - CASE(JUMPDEST) - { - // if frame size is set then we have been here before - size_t frameSize = m_frameSize[m_PC]; - if (0 != frameSize) - { - // check for constant frame size - if (stackSize() != frameSize) - throwBadStack(stackSize(), frameSize); - - // return to break cycle in control flow graph - return; - } - // set frame size to check later - m_frameSize[m_PC] = stackSize(); - ++m_PC; - } - NEXT - - CASE(JUMPTO) - { - // extract jump destination from bytecode - m_PC = decodeJumpDest(m_code.data(), m_PC); - } - NEXT - - CASE(JUMPIF) - { - // recurse to validate code to jump to, saving and restoring - // interpreter state around call - _pc = m_PC, _rp = m_RP, _sp = m_SP; - validateSubroutine(decodeJumpvDest(m_code.data(), m_PC, byte(m_SP[0])), _rp, _sp); - m_PC = _pc, m_RP = _rp, m_SP = _sp; - ++m_PC; - } - NEXT - - CASE(JUMPV) - { - // for every jump destination in jump vector - for (size_t dest = 0, nDests = m_code[m_PC+1]; dest < nDests; ++dest) - { - // recurse to validate code to jump to, saving and - // restoring interpreter state around call - _pc = m_PC, _rp = m_RP, _sp = m_SP; - validateSubroutine(decodeJumpDest(m_code.data(), m_PC), _rp, _sp); - m_PC = _pc, m_RP = _rp, m_SP = _sp; - } - } - BREAK - - CASE(JUMPSUB) - { - // check for enough arguments on stack - size_t destPC = decodeJumpDest(m_code.data(), m_PC); - byte nArgs = m_code[destPC+1]; - if (stackSize() < nArgs) - throwBadStack(stackSize(), nArgs); - } - NEXT - - CASE(JUMPSUBV) - { - // for every subroutine in jump vector - _pc = m_PC; - for (size_t sub = 0, nSubs = m_code[m_PC+1]; sub < nSubs; ++sub) - { - // check for enough arguments on stack - u256 slot = sub; - _sp = &slot; - size_t destPC = decodeJumpvDest(m_code.data(), _pc, byte(m_SP[0])); - byte nArgs = m_code[destPC+1]; - if (stackSize() < nArgs) - throwBadStack(stackSize(), nArgs); - } - m_PC = _pc; - } - NEXT - - CASE(RETURNSUB) - CASE(RETURN) - CASE(SUICIDE) - CASE(STOP) - { - // return to top level - } - BREAK; - - CASE(BEGINSUB) - CASE(BEGINDATA) - CASE(INVALID) - DEFAULT - { - throwBadInstruction(); - } - } - WHILE_CASES -} - -#endif diff --git a/libevm/interpreter.h b/libevm/interpreter.h deleted file mode 100644 index c8cc84813cd..00000000000 --- a/libevm/interpreter.h +++ /dev/null @@ -1,6 +0,0 @@ - -#pragma once - -#include - -extern "C" evmc_instance* evmc_create_interpreter() noexcept; diff --git a/test/tools/jsontests/StateTests.cpp b/test/tools/jsontests/StateTests.cpp index 95aeac0f181..a01946ee4d5 100644 --- a/test/tools/jsontests/StateTests.cpp +++ b/test/tools/jsontests/StateTests.cpp @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include diff --git a/test/tools/jsontests/vm.h b/test/tools/jsontests/vm.h index e0d39337f24..af9638a9b60 100644 --- a/test/tools/jsontests/vm.h +++ b/test/tools/jsontests/vm.h @@ -27,7 +27,6 @@ along with cpp-ethereum. If not, see . #include #include #include -#include #include #include #include