diff --git a/CMakeLists.txt b/CMakeLists.txt index a449f9a60..5ab394a80 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,13 +3,14 @@ cmake_minimum_required(VERSION 2.8.12) project(evmjit) set_property(GLOBAL PROPERTY USE_FOLDERS ON) +set(CMAKE_AUTOMOC OFF) -if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") +if(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC") else() - set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wno-unknown-pragmas -Wextra -fPIC") + set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wextra -Wconversion -Wno-sign-conversion -Wno-unknown-pragmas") endif() -if(CMAKE_SYSTEM_NAME STREQUAL "Linux") +if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") # Do not allow unresovled symbols in shared library (default on linux) set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--no-undefined") endif() @@ -21,7 +22,7 @@ if(LLVM_DIR OR APPLE) # local LLVM build message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") add_definitions(${LLVM_DEFINITIONS}) # TODO: bitwriter is needed only for evmcc - llvm_map_components_to_libnames(LLVM_LIBS core support mcjit x86asmparser x86codegen bitwriter) + llvm_map_components_to_libnames(LLVM_LIBS core support mcjit x86asmparser x86codegen bitwriter ipo) else() # Workaround for Ubuntu broken LLVM package message(STATUS "Using llvm-3.5-dev package from Ubuntu. If does not work, build LLVM and set -DLLVM_DIR=llvm-build/share/llvm/cmake") diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 000000000..630157f98 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Paweł Bylica + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 000000000..a480e83dc --- /dev/null +++ b/README.md @@ -0,0 +1,43 @@ +# The Ethereum EVM JIT + +EVM JIT is a library for just-in-time compilation of Ethereum EVM code. +It can be used to substitute classic interpreter-like EVM Virtual Machine in Ethereum client. + +## Build + +### Linux / Ubuntu + +1. Install llvm-3.5-dev package + 1. For Ubuntu 14.04 using LLVM deb packages source: http://llvm.org/apt + 2. For Ubuntu 14.10 using Ubuntu packages +2. Build library with cmake + 1. `mkdir build && cd $_` + 2. `cmake .. && make` +3. Install library + 1. `sudo make install` + 2. `sudo ldconfig` + +### OSX + +1. Install llvm35 + 1. `brew install llvm35 --disable-shared --HEAD` +2. Build library with cmake + 1. `mkdir build && cd $_` + 2. `cmake -DLLVM_DIR=/usr/local/lib/llvm-3.5/share/llvm/cmake .. && make` +3. Install library + 1. `make install` (with admin rights?) + +### Windows + +Ask me. + +## Options + +Options to evmjit library can be passed by environmental variables, e.g. `EVMJIT_CACHE=0 testeth --jit`. + +Option | Default value | Description +------------- | ------------- | ---------------------------------------------- +EVMJIT_CACHE | 1 | Enables on disk cache for compiled EVM objects +EVMJIT_DUMP | 0 | Dumps generated LLVM module to standard output + + diff --git a/evmcc/test/arith/addmod.evm b/evmcc/test/arith/addmod.evm deleted file mode 100644 index 4ca71e065..000000000 --- a/evmcc/test/arith/addmod.evm +++ /dev/null @@ -1 +0,0 @@ -60646107b760271460005560006001f2 diff --git a/evmcc/test/arith/addmod.lll b/evmcc/test/arith/addmod.lll deleted file mode 100644 index 11a6b2cb9..000000000 --- a/evmcc/test/arith/addmod.lll +++ /dev/null @@ -1,12 +0,0 @@ -;; Should return (1975 + 39) `mod` 100 = 14 = 0x0e -(asm -100 -1975 -39 -ADDMOD -0 -MSTORE8 -0 -1 -RETURN -) \ No newline at end of file diff --git a/evmcc/test/arith/arith1.evm b/evmcc/test/arith/arith1.evm deleted file mode 100644 index c7a029f52..000000000 --- a/evmcc/test/arith/arith1.evm +++ /dev/null @@ -1 +0,0 @@ -60016001900160070260050160029004600490066021900560150160030260059007600303600960110860005460086000f2 diff --git a/evmcc/test/arith/arith1.lll b/evmcc/test/arith/arith1.lll deleted file mode 100644 index 4757a7420..000000000 --- a/evmcc/test/arith/arith1.lll +++ /dev/null @@ -1,37 +0,0 @@ - -(asm -1 -1 -SWAP1 -ADD ;; 2 -7 -MUL ;; 14 -5 -ADD ;; 19 -2 -SWAP1 -DIV ;; 9 -4 -SWAP1 -MOD ;; 1 -33 -SWAP1 -SDIV;; 0 -21 -ADD ;; 21 -3 -MUL ;; 63 -5 -SWAP1 -SMOD;; 3 -3 -SUB ;; 0 -9 -17 -EXP ;; 17^9 -0 -MSTORE -8 -0 -RETURN -) \ No newline at end of file diff --git a/evmcc/test/arith/arith_bnot.evm b/evmcc/test/arith/arith_bnot.evm deleted file mode 100644 index 4cfaf8f55..000000000 --- a/evmcc/test/arith/arith_bnot.evm +++ /dev/null @@ -1 +0,0 @@ -6201e2406000546000530960005460206000f2 diff --git a/evmcc/test/arith/arith_bnot.lll b/evmcc/test/arith/arith_bnot.lll deleted file mode 100644 index a83b05a9a..000000000 --- a/evmcc/test/arith/arith_bnot.lll +++ /dev/null @@ -1,14 +0,0 @@ - -(asm -123456 -0 -MSTORE -0 -MLOAD -BNOT -0 -MSTORE -32 -0 -RETURN -) \ No newline at end of file diff --git a/evmcc/test/arith/div.evm b/evmcc/test/arith/div.evm deleted file mode 100644 index b68d5d202..000000000 --- a/evmcc/test/arith/div.evm +++ /dev/null @@ -1 +0,0 @@ -60027ffedcba9876543210fedcba9876543210fedcba9876543210fedcba98765432100460005460206000f2 diff --git a/evmcc/test/arith/div.lll b/evmcc/test/arith/div.lll deleted file mode 100644 index 72c22bfdc..000000000 --- a/evmcc/test/arith/div.lll +++ /dev/null @@ -1,10 +0,0 @@ -(asm -0x2 -0xfedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210 -DIV -0 -MSTORE -32 -0 -RETURN -) diff --git a/evmcc/test/arith/fib1.evm b/evmcc/test/arith/fib1.evm deleted file mode 100644 index 4c141314e..000000000 --- a/evmcc/test/arith/fib1.evm +++ /dev/null @@ -1 +0,0 @@ -60016001818101818101818101818101818101818101818101818101818101818101818101818101818101818101818101818101818101 diff --git a/evmcc/test/arith/fib1.lll b/evmcc/test/arith/fib1.lll deleted file mode 100644 index 286bed275..000000000 --- a/evmcc/test/arith/fib1.lll +++ /dev/null @@ -1,57 +0,0 @@ -;; Fibbonacci unrolled - -(asm -1 -1 -DUP2 -DUP2 -ADD -DUP2 -DUP2 -ADD -DUP2 -DUP2 -ADD -DUP2 -DUP2 -ADD -DUP2 -DUP2 -ADD -DUP2 -DUP2 -ADD -DUP2 -DUP2 -ADD -DUP2 -DUP2 -ADD -DUP2 -DUP2 -ADD -DUP2 -DUP2 -ADD -DUP2 -DUP2 -ADD -DUP2 -DUP2 -ADD -DUP2 -DUP2 -ADD -DUP2 -DUP2 -ADD -DUP2 -DUP2 -ADD -DUP2 -DUP2 -ADD -DUP2 -DUP2 -ADD -) \ No newline at end of file diff --git a/evmcc/test/arith/mul.evm b/evmcc/test/arith/mul.evm deleted file mode 100644 index 7e8afd268..000000000 --- a/evmcc/test/arith/mul.evm +++ /dev/null @@ -1 +0,0 @@ -7001234567890abcdef0fedcba09876543217001234567890abcdef0fedcba09876543217001234567890abcdef0fedcba0987654321020260005460206000f2 diff --git a/evmcc/test/arith/mul.lll b/evmcc/test/arith/mul.lll deleted file mode 100644 index b0fa343bb..000000000 --- a/evmcc/test/arith/mul.lll +++ /dev/null @@ -1,13 +0,0 @@ -(asm -0x1234567890abcdef0fedcba0987654321 -0x1234567890abcdef0fedcba0987654321 -0x1234567890abcdef0fedcba0987654321 -MUL -MUL -0 -MSTORE -32 -0 -RETURN -;; 47d0817e4167b1eb4f9fc722b133ef9d7d9a6fb4c2c1c442d000107a5e419561 -) diff --git a/evmcc/test/arith/mulmod.evm b/evmcc/test/arith/mulmod.evm deleted file mode 100644 index e34a06154..000000000 --- a/evmcc/test/arith/mulmod.evm +++ /dev/null @@ -1 +0,0 @@ -6064601b60251560005560006001f2 diff --git a/evmcc/test/arith/mulmod.lll b/evmcc/test/arith/mulmod.lll deleted file mode 100644 index 5e87f0843..000000000 --- a/evmcc/test/arith/mulmod.lll +++ /dev/null @@ -1,12 +0,0 @@ -;; Should return (27 * 37) `mod` 100 = 99 = 0x63 -(asm -100 -27 -37 -MULMOD -0 -MSTORE8 -0 -1 -RETURN -) \ No newline at end of file diff --git a/evmcc/test/except/badinst1.evm b/evmcc/test/except/badinst1.evm deleted file mode 100644 index 69aadac5e..000000000 --- a/evmcc/test/except/badinst1.evm +++ /dev/null @@ -1 +0,0 @@ -4a diff --git a/evmcc/test/ext/calldatacopy1.evm b/evmcc/test/ext/calldatacopy1.evm deleted file mode 100644 index f20019651..000000000 --- a/evmcc/test/ext/calldatacopy1.evm +++ /dev/null @@ -1 +0,0 @@ -60326000600a37600053600a6014f2 diff --git a/evmcc/test/ext/calldatacopy1.lll b/evmcc/test/ext/calldatacopy1.lll deleted file mode 100644 index 3d2ae0a78..000000000 --- a/evmcc/test/ext/calldatacopy1.lll +++ /dev/null @@ -1,13 +0,0 @@ -(asm -50 ;; byte count -0 ;; source index in calldata array -10 ;; dest index in memory -CALLDATACOPY - -0 -MLOAD ;; to dump memory - -10 -20 -RETURN -) \ No newline at end of file diff --git a/evmcc/test/ext/calldatacopy2.evm b/evmcc/test/ext/calldatacopy2.evm deleted file mode 100644 index e8eea8da7..000000000 --- a/evmcc/test/ext/calldatacopy2.evm +++ /dev/null @@ -1 +0,0 @@ -606464e8d4a510006000376000536000600af2 diff --git a/evmcc/test/ext/calldatacopy2.lll b/evmcc/test/ext/calldatacopy2.lll deleted file mode 100644 index 6bbea48d8..000000000 --- a/evmcc/test/ext/calldatacopy2.lll +++ /dev/null @@ -1,13 +0,0 @@ -(asm -100 ;; byte count -1000000000000 ;; source index in calldata array -0 ;; dest index in memory -CALLDATACOPY - -0 -MLOAD ;; to dump memory - -0 -10 -RETURN -) \ No newline at end of file diff --git a/evmcc/test/ext/codecopy1.evm b/evmcc/test/ext/codecopy1.evm deleted file mode 100644 index d286f9232..000000000 --- a/evmcc/test/ext/codecopy1.evm +++ /dev/null @@ -1 +0,0 @@ -60146000600a39600053600a6014f2 diff --git a/evmcc/test/ext/codecopy1.lll b/evmcc/test/ext/codecopy1.lll deleted file mode 100644 index 85a02b5d7..000000000 --- a/evmcc/test/ext/codecopy1.lll +++ /dev/null @@ -1,13 +0,0 @@ -(asm -20 ;; byte count -0 ;; source index in code array -10 ;; dest index in memory -CODECOPY - -0 -MLOAD ;; to dump memory - -10 -20 -RETURN -) \ No newline at end of file diff --git a/evmcc/test/ext/codecopy2.evm b/evmcc/test/ext/codecopy2.evm deleted file mode 100644 index 71cd92525..000000000 --- a/evmcc/test/ext/codecopy2.evm +++ /dev/null @@ -1 +0,0 @@ -606464e8d4a510006000396000536000600af2 diff --git a/evmcc/test/ext/codecopy2.lll b/evmcc/test/ext/codecopy2.lll deleted file mode 100644 index dcbbcaa46..000000000 --- a/evmcc/test/ext/codecopy2.lll +++ /dev/null @@ -1,13 +0,0 @@ -(asm -100 ;; byte count -1000000000000 ;; source index in code array -0 ;; dest index in memory -CODECOPY - -0 -MLOAD ;; to dump memory - -0 -10 -RETURN -) \ No newline at end of file diff --git a/evmcc/test/ext/codecopy3.evm b/evmcc/test/ext/codecopy3.evm deleted file mode 100644 index e4b6a9253..000000000 --- a/evmcc/test/ext/codecopy3.evm +++ /dev/null @@ -1 +0,0 @@ -3860006000396000536000600af2 diff --git a/evmcc/test/ext/codecopy3.lll b/evmcc/test/ext/codecopy3.lll deleted file mode 100644 index 80d9982c6..000000000 --- a/evmcc/test/ext/codecopy3.lll +++ /dev/null @@ -1,13 +0,0 @@ -(asm -CODESIZE ;; byte count -0 ;; source index in code array -0 ;; dest index in memory -CODECOPY - -0 -MLOAD ;; to dump memory - -0 -10 -RETURN -) \ No newline at end of file diff --git a/evmcc/test/ext/ext_test.evm b/evmcc/test/ext/ext_test.evm deleted file mode 100644 index 580bd9675..000000000 --- a/evmcc/test/ext/ext_test.evm +++ /dev/null @@ -1 +0,0 @@ -5a3031333234363a4041424344455a36600035602635601335387f1111222233334444555566667777888899990000aaaabbbbccccddddeeeeffff600054602060006000f06020600060206000600030610bb8f1600053611000545b60200260002030ff60016002f2 diff --git a/evmcc/test/ext/ext_test.lll b/evmcc/test/ext/ext_test.lll deleted file mode 100644 index 3287ae95f..000000000 --- a/evmcc/test/ext/ext_test.lll +++ /dev/null @@ -1,55 +0,0 @@ - -(asm -PC -ADDRESS -BALANCE -CALLER -ORIGIN -CALLVALUE -CALLDATASIZE -GASPRICE -PREVHASH -COINBASE -TIMESTAMP -NUMBER -DIFFICULTY -GASLIMIT -PC -CALLDATASIZE -0 -CALLDATALOAD -38 -CALLDATALOAD -19 -CALLDATALOAD -CODESIZE -0x1111222233334444555566667777888899990000aaaabbbbccccddddeeeeffff -0 -MSTORE -32 -0 -0 -CREATE -32 -0 -32 -0 -0 -ADDRESS -3000 -CALL -0 -MLOAD -4096 -MSTORE -MSIZE -32 -MUL -0 -SHA3 -ADDRESS -SUICIDE -1 -2 -RETURN -) \ No newline at end of file diff --git a/evmcc/test/ext/extcodecopy1.evm b/evmcc/test/ext/extcodecopy1.evm deleted file mode 100644 index 6132b52d8..000000000 --- a/evmcc/test/ext/extcodecopy1.evm +++ /dev/null @@ -1 +0,0 @@ -60c86000600a303c60005360006020f2 diff --git a/evmcc/test/ext/extcodecopy1.lll b/evmcc/test/ext/extcodecopy1.lll deleted file mode 100644 index c37054574..000000000 --- a/evmcc/test/ext/extcodecopy1.lll +++ /dev/null @@ -1,11 +0,0 @@ -(asm -200 ;; byte count -0 ;; source index in code array -10 ;; dest index in memory -ADDRESS -EXTCODECOPY - -0 MLOAD ;; to dump memory - -0 32 RETURN -) \ No newline at end of file diff --git a/evmcc/test/ext/store_delete.evm b/evmcc/test/ext/store_delete.evm deleted file mode 100644 index d6acae03d..000000000 --- a/evmcc/test/ext/store_delete.evm +++ /dev/null @@ -1 +0,0 @@ -6104d26063576000606357 diff --git a/evmcc/test/ext/store_delete.lll b/evmcc/test/ext/store_delete.lll deleted file mode 100644 index 3d8f0f23a..000000000 --- a/evmcc/test/ext/store_delete.lll +++ /dev/null @@ -1,9 +0,0 @@ - -(asm -1234 -99 -SSTORE -0 -99 -SSTORE -) \ No newline at end of file diff --git a/evmcc/test/ext/store_test.evm b/evmcc/test/ext/store_test.evm deleted file mode 100644 index 54c9419b5..000000000 --- a/evmcc/test/ext/store_test.evm +++ /dev/null @@ -1 +0,0 @@ -607b607c60015760005760015660005603 diff --git a/evmcc/test/ext/store_test.lll b/evmcc/test/ext/store_test.lll deleted file mode 100644 index c40471c40..000000000 --- a/evmcc/test/ext/store_test.lll +++ /dev/null @@ -1,14 +0,0 @@ - -(asm -123 -124 -1 -SSTORE -0 -SSTORE -1 -SLOAD -0 -SLOAD -SUB -) \ No newline at end of file diff --git a/evmcc/test/jump/ackermann.ethel b/evmcc/test/jump/ackermann.ethel deleted file mode 100644 index 971fd2b8d..000000000 --- a/evmcc/test/jump/ackermann.ethel +++ /dev/null @@ -1,7 +0,0 @@ -let A m n = - if m == 0 then n+1 - else if n == 0 then A (m-1) 1 - else A (m-1) (A (m) (n-1)) - -return A 3 8 - diff --git a/evmcc/test/jump/ackermann.evm b/evmcc/test/jump/ackermann.evm deleted file mode 100644 index 964844045..000000000 --- a/evmcc/test/jump/ackermann.evm +++ /dev/null @@ -1 +0,0 @@ -6009600360086012585d60005460206000f26000820e6047596000810e603859603460018303603084600185036012585d6012585d60445860436001830360016012585d604b5860018101905090509058 \ No newline at end of file diff --git a/evmcc/test/jump/badindirect1.evm b/evmcc/test/jump/badindirect1.evm deleted file mode 100644 index b2a8aad67..000000000 --- a/evmcc/test/jump/badindirect1.evm +++ /dev/null @@ -1 +0,0 @@ -601b602502585d diff --git a/evmcc/test/jump/badindirect1.lll b/evmcc/test/jump/badindirect1.lll deleted file mode 100644 index d6291be68..000000000 --- a/evmcc/test/jump/badindirect1.lll +++ /dev/null @@ -1,9 +0,0 @@ -;; Indirect jump out of code - -(asm -27 -37 -MUL -JUMP -JUMPDEST -) \ No newline at end of file diff --git a/evmcc/test/jump/badindirect2.evm b/evmcc/test/jump/badindirect2.evm deleted file mode 100644 index 22217523d..000000000 --- a/evmcc/test/jump/badindirect2.evm +++ /dev/null @@ -1 +0,0 @@ -60016003600302596000600058 diff --git a/evmcc/test/jump/badindirect2.lll b/evmcc/test/jump/badindirect2.lll deleted file mode 100644 index 53a6294f7..000000000 --- a/evmcc/test/jump/badindirect2.lll +++ /dev/null @@ -1,12 +0,0 @@ -;; Indirect jump into data - -(asm -1 ;; 0 -3 -3 -MUL ;; 6 -JUMPI ;; 7 -0 ;; 8 -0 -JUMP -) \ No newline at end of file diff --git a/evmcc/test/jump/badjump1.evm b/evmcc/test/jump/badjump1.evm deleted file mode 100644 index 5c11a8661..000000000 --- a/evmcc/test/jump/badjump1.evm +++ /dev/null @@ -1 +0,0 @@ -6103e758 diff --git a/evmcc/test/jump/badjump1.lll b/evmcc/test/jump/badjump1.lll deleted file mode 100644 index 1834a62ef..000000000 --- a/evmcc/test/jump/badjump1.lll +++ /dev/null @@ -1,6 +0,0 @@ -;; Direct jump out of code. - -(asm -999 -JUMP -) \ No newline at end of file diff --git a/evmcc/test/jump/badjump2.evm b/evmcc/test/jump/badjump2.evm deleted file mode 100644 index 900a1c15a..000000000 --- a/evmcc/test/jump/badjump2.evm +++ /dev/null @@ -1 +0,0 @@ -6004586000600058 diff --git a/evmcc/test/jump/badjump2.lll b/evmcc/test/jump/badjump2.lll deleted file mode 100644 index ce61276d7..000000000 --- a/evmcc/test/jump/badjump2.lll +++ /dev/null @@ -1,9 +0,0 @@ -;; Direct jump into data - -(asm -4 ;; 0 0-3 -JUMP ;; 2 -0 ;; 3 3-4 -0 ;; 5 4-7 -JUMP ;; 6 -) \ No newline at end of file diff --git a/evmcc/test/jump/call1.ethel b/evmcc/test/jump/call1.ethel deleted file mode 100644 index 414ad0124..000000000 --- a/evmcc/test/jump/call1.ethel +++ /dev/null @@ -1,5 +0,0 @@ -let f n = n + 1 - -return f 2 - - diff --git a/evmcc/test/jump/call1.evm b/evmcc/test/jump/call1.evm deleted file mode 100644 index 252aaf778..000000000 --- a/evmcc/test/jump/call1.evm +++ /dev/null @@ -1 +0,0 @@ -600760026010585d60005460206000f28060010190509058 \ No newline at end of file diff --git a/evmcc/test/jump/call2.ethel b/evmcc/test/jump/call2.ethel deleted file mode 100644 index bdeb9b734..000000000 --- a/evmcc/test/jump/call2.ethel +++ /dev/null @@ -1,5 +0,0 @@ -let f a b = a + b - -return f 2 3 - - diff --git a/evmcc/test/jump/call2.evm b/evmcc/test/jump/call2.evm deleted file mode 100644 index 6832e044d..000000000 --- a/evmcc/test/jump/call2.evm +++ /dev/null @@ -1 +0,0 @@ -6009600260036012585d60005460206000f2818101905090509058 \ No newline at end of file diff --git a/evmcc/test/jump/fac.ethel b/evmcc/test/jump/fac.ethel deleted file mode 100644 index 8bfe94dd6..000000000 --- a/evmcc/test/jump/fac.ethel +++ /dev/null @@ -1,5 +0,0 @@ -let fac n = - if n == 0 then 1 - else n * fac (n-1) - -return fac 60 \ No newline at end of file diff --git a/evmcc/test/jump/fac.evm b/evmcc/test/jump/fac.evm deleted file mode 100644 index 04cd3e4f4..000000000 --- a/evmcc/test/jump/fac.evm +++ /dev/null @@ -1 +0,0 @@ -6007603c6010585d60005460206000f26000810e6026596020600182036010585d8102602858600190509058 \ No newline at end of file diff --git a/evmcc/test/jump/fac_tail.ethel b/evmcc/test/jump/fac_tail.ethel deleted file mode 100644 index 9ce5ecac7..000000000 --- a/evmcc/test/jump/fac_tail.ethel +++ /dev/null @@ -1,5 +0,0 @@ -let fac a n = - if n == 0 then a - else fac (a*n) (n-1) - -return fac 1 60 \ No newline at end of file diff --git a/evmcc/test/jump/fac_tail.evm b/evmcc/test/jump/fac_tail.evm deleted file mode 100644 index 8384d94e4..000000000 --- a/evmcc/test/jump/fac_tail.evm +++ /dev/null @@ -1 +0,0 @@ -60096001603c6012585d60005460206000f26000810e6029596025818302600183036012585d602a5881905090509058 \ No newline at end of file diff --git a/evmcc/test/jump/fib1.ethel b/evmcc/test/jump/fib1.ethel deleted file mode 100644 index 81b869f41..000000000 --- a/evmcc/test/jump/fib1.ethel +++ /dev/null @@ -1,6 +0,0 @@ -let fib n = - if n < 3 then 1 - else fib (n-1) + fib (n-2) - -return fib 10 - diff --git a/evmcc/test/jump/fib1.evm b/evmcc/test/jump/fib1.evm deleted file mode 100644 index 5042a192f..000000000 --- a/evmcc/test/jump/fib1.evm +++ /dev/null @@ -1 +0,0 @@ -6007600a6010585d60005460206000f26003810a602f596020600282036010585d602a600183036010585d01603158600190509058 \ No newline at end of file diff --git a/evmcc/test/jump/for1.evm b/evmcc/test/jump/for1.evm deleted file mode 100644 index f8e65cbf2..000000000 --- a/evmcc/test/jump/for1.evm +++ /dev/null @@ -1 +0,0 @@ -600a60805460006080530b0f60255960a0536080530160a054600160805303608054600558 diff --git a/evmcc/test/jump/for1.lll b/evmcc/test/jump/for1.lll deleted file mode 100644 index 419fc9b54..000000000 --- a/evmcc/test/jump/for1.lll +++ /dev/null @@ -1,3 +0,0 @@ -(for [i]:10 (> @i 0) [i](- @i 1) - [j](+ @i @j) -) diff --git a/evmcc/test/jump/for2.evm b/evmcc/test/jump/for2.evm deleted file mode 100644 index 628297778..000000000 --- a/evmcc/test/jump/for2.evm +++ /dev/null @@ -1 +0,0 @@ -6000608054600a6080530a0f60255960a0536080530160a054600160805301608054600558 diff --git a/evmcc/test/jump/for2.lll b/evmcc/test/jump/for2.lll deleted file mode 100644 index de17d65ac..000000000 --- a/evmcc/test/jump/for2.lll +++ /dev/null @@ -1,3 +0,0 @@ -(for [i]:0 (< @i 10) [i](+ @i 1) - [j](+ @i @j) -) diff --git a/evmcc/test/jump/if1.ethel b/evmcc/test/jump/if1.ethel deleted file mode 100644 index 85c3e126b..000000000 --- a/evmcc/test/jump/if1.ethel +++ /dev/null @@ -1 +0,0 @@ -return if 0 then 1 else 2 \ No newline at end of file diff --git a/evmcc/test/jump/if1.evm b/evmcc/test/jump/if1.evm deleted file mode 100644 index 51fbe04bd..000000000 --- a/evmcc/test/jump/if1.evm +++ /dev/null @@ -1 +0,0 @@ -60006300000010596002630000001258600160005460206000f2 \ No newline at end of file diff --git a/evmcc/test/jump/if2.ethel b/evmcc/test/jump/if2.ethel deleted file mode 100644 index 2a58d6365..000000000 --- a/evmcc/test/jump/if2.ethel +++ /dev/null @@ -1 +0,0 @@ -return if 1 then 1 else 2 \ No newline at end of file diff --git a/evmcc/test/jump/if2.evm b/evmcc/test/jump/if2.evm deleted file mode 100644 index 6d823b374..000000000 --- a/evmcc/test/jump/if2.evm +++ /dev/null @@ -1 +0,0 @@ -60016300000010596002630000001258600160005460206000f2 \ No newline at end of file diff --git a/evmcc/test/jump/indirect1.evm b/evmcc/test/jump/indirect1.evm deleted file mode 100644 index ab6928304..000000000 --- a/evmcc/test/jump/indirect1.evm +++ /dev/null @@ -1 +0,0 @@ -600460030158005d6001600054 diff --git a/evmcc/test/jump/indirect1.lll b/evmcc/test/jump/indirect1.lll deleted file mode 100644 index 1ee7dc347..000000000 --- a/evmcc/test/jump/indirect1.lll +++ /dev/null @@ -1,13 +0,0 @@ -;; Indirect JUMP - -(asm -4 ;; 0 -3 ;; 2 -ADD ;; 4 -JUMP ;; 5 -STOP ;; 6 -JUMPDEST ;; 7 -1 -0 -MSTORE -) \ No newline at end of file diff --git a/evmcc/test/jump/indirect2.evm b/evmcc/test/jump/indirect2.evm deleted file mode 100644 index e9697eaa1..000000000 --- a/evmcc/test/jump/indirect2.evm +++ /dev/null @@ -1 +0,0 @@ -600860060158005d6001600054005d600260005400 diff --git a/evmcc/test/jump/indirect2.lll b/evmcc/test/jump/indirect2.lll deleted file mode 100644 index f2f068630..000000000 --- a/evmcc/test/jump/indirect2.lll +++ /dev/null @@ -1,19 +0,0 @@ -;; Indirect JUMP - -(asm -8 ;; 0 -6 ;; 2 -ADD ;; 4 -JUMP ;; 5 --> 14 -STOP ;; 6 -JUMPDEST ;; 7 -1 ;; 8 -0 ;; 10 -MSTORE ;; 12 -STOP ;; 13 -JUMPDEST ;; 14 -2 -0 -MSTORE -STOP -) \ No newline at end of file diff --git a/evmcc/test/jump/indirect3.evm b/evmcc/test/jump/indirect3.evm deleted file mode 100644 index 1fb0a356c..000000000 --- a/evmcc/test/jump/indirect3.evm +++ /dev/null @@ -1 +0,0 @@ -6001600460050159005d6001600054 diff --git a/evmcc/test/jump/indirect3.lll b/evmcc/test/jump/indirect3.lll deleted file mode 100644 index d6a679f9a..000000000 --- a/evmcc/test/jump/indirect3.lll +++ /dev/null @@ -1,14 +0,0 @@ -;; Indirect JUMP - -(asm -1 ;; 0 -4 ;; 2 -5 ;; 4 -ADD ;; 6 -JUMPI ;; 7 -STOP ;; 8 -JUMPDEST ;; 9 -1 -0 -MSTORE -) \ No newline at end of file diff --git a/evmcc/test/jump/indirect4.evm b/evmcc/test/jump/indirect4.evm deleted file mode 100644 index f0e31a8f4..000000000 --- a/evmcc/test/jump/indirect4.evm +++ /dev/null @@ -1 +0,0 @@ -60006007600501596001600054005d00 diff --git a/evmcc/test/jump/indirect4.lll b/evmcc/test/jump/indirect4.lll deleted file mode 100644 index 7fbe0b833..000000000 --- a/evmcc/test/jump/indirect4.lll +++ /dev/null @@ -1,15 +0,0 @@ -;; Indirect JUMP - -(asm -0 ;; 0 -7 ;; 2 -5 ;; 4 -ADD ;; 6 -JUMPI ;; 7 -1 ;; 8 -0 ;; 9 -MSTORE ;; 10 -STOP ;; 11 -JUMPDEST ;; 12 -STOP -) \ No newline at end of file diff --git a/evmcc/test/jump/jump1.evm b/evmcc/test/jump/jump1.evm deleted file mode 100644 index 0df9b4036..000000000 --- a/evmcc/test/jump/jump1.evm +++ /dev/null @@ -1 +0,0 @@ -600458006001600154 diff --git a/evmcc/test/jump/jump1.lll b/evmcc/test/jump/jump1.lll deleted file mode 100644 index 33119edb3..000000000 --- a/evmcc/test/jump/jump1.lll +++ /dev/null @@ -1,11 +0,0 @@ -;; Direct JUMP. -;; output: memory[1] == 1 - -(asm -4 ;; 0 -JUMP ;; 2 -STOP ;; 3 -1 ;; 4 -1 ;; 6 -MSTORE ;; 8 -) \ No newline at end of file diff --git a/evmcc/test/jump/jump2.evm b/evmcc/test/jump/jump2.evm deleted file mode 100644 index 35d75941d..000000000 --- a/evmcc/test/jump/jump2.evm +++ /dev/null @@ -1 +0,0 @@ -6008586001600154 diff --git a/evmcc/test/jump/jump2.lll b/evmcc/test/jump/jump2.lll deleted file mode 100644 index a70d50ecb..000000000 --- a/evmcc/test/jump/jump2.lll +++ /dev/null @@ -1,10 +0,0 @@ -;; Direct JUMP to the end of code. -;; output: memory should have size 0. - -(asm -8 ;; 0 -JUMP ;; 2 -1 ;; 3 -1 ;; 5 -MSTORE ;; 7 -) \ No newline at end of file diff --git a/evmcc/test/jump/jump3.evm b/evmcc/test/jump/jump3.evm deleted file mode 100644 index 599d4a764..000000000 --- a/evmcc/test/jump/jump3.evm +++ /dev/null @@ -1 +0,0 @@ -602a586001600154 diff --git a/evmcc/test/jump/jump3.lll b/evmcc/test/jump/jump3.lll deleted file mode 100644 index bc897e30c..000000000 --- a/evmcc/test/jump/jump3.lll +++ /dev/null @@ -1,10 +0,0 @@ -;; Direct JUMP past the end of code. -;; output: memory should have size 0. - -(asm -42 -JUMP -1 -1 -MSTORE -) \ No newline at end of file diff --git a/evmcc/test/jump/jump4.evm b/evmcc/test/jump/jump4.evm deleted file mode 100644 index 41713f43e..000000000 --- a/evmcc/test/jump/jump4.evm +++ /dev/null @@ -1 +0,0 @@ -600b6009580000600558005d6001600154 diff --git a/evmcc/test/jump/jump4.lll b/evmcc/test/jump/jump4.lll deleted file mode 100644 index 131baee2d..000000000 --- a/evmcc/test/jump/jump4.lll +++ /dev/null @@ -1,17 +0,0 @@ -;; Direct JUMP. -;; output: memory[1] = 1 - -(asm -11 ;; 0 -9 ;; 2 -JUMP ;; 4 --> 9 -STOP ;; 5 -STOP ;; 6 -5 ;; 7 -JUMP ;; 9 --> 11 -STOP ;; 10 -JUMPDEST -1 ;; 11 -1 -MSTORE -) \ No newline at end of file diff --git a/evmcc/test/jump/jump5.evm b/evmcc/test/jump/jump5.evm deleted file mode 100644 index c36d9615b..000000000 --- a/evmcc/test/jump/jump5.evm +++ /dev/null @@ -1 +0,0 @@ -6005600e585d600160015400600f5800 diff --git a/evmcc/test/jump/jump5.lll b/evmcc/test/jump/jump5.lll deleted file mode 100644 index d28b7d4ac..000000000 --- a/evmcc/test/jump/jump5.lll +++ /dev/null @@ -1,16 +0,0 @@ -;; Direct JUMP. -;; output: memory[1] = 1 - -(asm -5 ;; 0 -14 ;; 2 -JUMP ;; 4 --> 14 -JUMPDEST ;; 5 -1 ;; 6 -1 ;; 8 -MSTORE ;; 10 -STOP ;; 11 -15 ;; 12 -JUMP ;; 14 --> 5 -STOP ;; 15 -) \ No newline at end of file diff --git a/evmcc/test/jump/jump6.evm b/evmcc/test/jump/jump6.evm deleted file mode 100644 index 029db7191..000000000 --- a/evmcc/test/jump/jump6.evm +++ /dev/null @@ -1 +0,0 @@ -600358600f600d58006014600758005d6001600154005d600260025400 diff --git a/evmcc/test/jump/jump6.lll b/evmcc/test/jump/jump6.lll deleted file mode 100644 index 1116aa663..000000000 --- a/evmcc/test/jump/jump6.lll +++ /dev/null @@ -1,32 +0,0 @@ -;; Direct JUMP. -;; output: memory[1] = 1 - -;; 0, 2 --> 3 .. 7 --> 13 -*-> 15 .. 19 - -(asm -3 ;; 0 -JUMP ;; 2 - -15 ;; 3 <- start -13 ;; 5 -JUMP ;; 7 <- b -STOP ;; 8 - -20 ;; 9 -7 ;; 11 - -JUMP ;; 13 <- a -STOP ;; 14 - -JUMPDEST ;; 15 <- c -1 ;; 16 -1 ;; 18 -MSTORE ;; 19 -STOP ;; 20 - -JUMPDEST ;; 21 <- d -2 ;; 22 -2 ;; 24 -MSTORE ;; 26 -STOP ;; 27 -) \ No newline at end of file diff --git a/evmcc/test/jump/jumpi_at_the_end.evm b/evmcc/test/jump/jumpi_at_the_end.evm deleted file mode 100644 index 2d7411761..000000000 --- a/evmcc/test/jump/jumpi_at_the_end.evm +++ /dev/null @@ -1 +0,0 @@ -600a6000545d6000536001900380600054600659 diff --git a/evmcc/test/jump/jumpi_at_the_end.lll b/evmcc/test/jump/jumpi_at_the_end.lll deleted file mode 100644 index 263ada6a7..000000000 --- a/evmcc/test/jump/jumpi_at_the_end.lll +++ /dev/null @@ -1 +0,0 @@ -(asm 10 0 MSTORE JUMPDEST 0 MLOAD 1 SWAP1 SUB DUP1 0 MSTORE 6 JUMPI) \ No newline at end of file diff --git a/evmcc/test/jump/loop1.evm b/evmcc/test/jump/loop1.evm deleted file mode 100644 index 7724d6308..000000000 --- a/evmcc/test/jump/loop1.evm +++ /dev/null @@ -1 +0,0 @@ -600a600181038060025960005460015460025400 diff --git a/evmcc/test/jump/loop1.lll b/evmcc/test/jump/loop1.lll deleted file mode 100644 index 0044ec1fb..000000000 --- a/evmcc/test/jump/loop1.lll +++ /dev/null @@ -1,27 +0,0 @@ -;; Produces 1 2 3 4 5 6 7 8 9 10 on the stack and exits - -(asm -10 - -;; 2 -1 -DUP2 -SUB -DUP1 -2 -JUMPI - -;; stack = 1 2 3 4 5 6 7 8 9 10 -0 -MSTORE -1 -MSTORE -2 -MSTORE -;;3 -;;MSTORE - -STOP -) - - diff --git a/evmcc/test/jump/loop2.evm b/evmcc/test/jump/loop2.evm deleted file mode 100644 index faffa4e5b..000000000 --- a/evmcc/test/jump/loop2.evm +++ /dev/null @@ -1 +0,0 @@ -600a80600190038060025960005460015460025400 diff --git a/evmcc/test/jump/loop2.lll b/evmcc/test/jump/loop2.lll deleted file mode 100644 index 9996c52ba..000000000 --- a/evmcc/test/jump/loop2.lll +++ /dev/null @@ -1,28 +0,0 @@ -;; Produces 1 2 3 4 5 6 7 8 9 10 on the stack and exits - -(asm -10 - -;; 2 -DUP1 -1 -SWAP1 -SUB -DUP1 -2 -JUMPI - -;; stack = 1 2 3 4 5 6 7 8 9 10 -0 -MSTORE -1 -MSTORE -2 -MSTORE -;;3 -;;MSTORE - -STOP -) - - diff --git a/evmcc/test/jump/rec1.ethel b/evmcc/test/jump/rec1.ethel deleted file mode 100644 index f83c8e81e..000000000 --- a/evmcc/test/jump/rec1.ethel +++ /dev/null @@ -1,4 +0,0 @@ -let f n = - if n == 0 then 2 else f (n-1) - -return f 10 diff --git a/evmcc/test/jump/rec1.evm b/evmcc/test/jump/rec1.evm deleted file mode 100644 index 2ae62aff6..000000000 --- a/evmcc/test/jump/rec1.evm +++ /dev/null @@ -1 +0,0 @@ -6007600a6010585d60005460206000f26000810e6024596020600182036010585d602658600290509058 \ No newline at end of file diff --git a/evmcc/test/jump/when1.asm b/evmcc/test/jump/when1.asm deleted file mode 100644 index 01d41c266..000000000 --- a/evmcc/test/jump/when1.asm +++ /dev/null @@ -1,10 +0,0 @@ -.code: - PUSH 1 - NOT - PUSH [tag0] - JUMPI - PUSH 13 - PUSH 128 - MSTORE -tag0: - diff --git a/evmcc/test/jump/when1.evm b/evmcc/test/jump/when1.evm deleted file mode 100644 index 303b02623..000000000 --- a/evmcc/test/jump/when1.evm +++ /dev/null @@ -1 +0,0 @@ -60010f600b59600d608054 diff --git a/evmcc/test/jump/when1.lll b/evmcc/test/jump/when1.lll deleted file mode 100644 index 990a6e64a..000000000 --- a/evmcc/test/jump/when1.lll +++ /dev/null @@ -1,2 +0,0 @@ -(when (> 1 0) [i] 13) - \ No newline at end of file diff --git a/evmcc/test/kv.evm b/evmcc/test/kv.evm deleted file mode 100644 index 55141ea59..000000000 --- a/evmcc/test/kv.evm +++ /dev/null @@ -1 +0,0 @@ -33604557602a8060106000396000f200604556330e0f602a59366080530a0f602a59602060805301356080533557604060805301608054600958 diff --git a/evmcc/test/kv.lll b/evmcc/test/kv.lll deleted file mode 100644 index c62d9fa70..000000000 --- a/evmcc/test/kv.lll +++ /dev/null @@ -1,10 +0,0 @@ -{ - [[69]] (caller) - (return 0 (lll - (when (= (caller) @@69) - (for {} (< @i (calldatasize)) [i](+ @i 64) - [[ (calldataload @i) ]] (calldataload (+ @i 32)) - ) - ) - 0)) -} diff --git a/evmcc/test/mem/byte.evm b/evmcc/test/mem/byte.evm deleted file mode 100644 index ab63431ee..000000000 --- a/evmcc/test/mem/byte.evm +++ /dev/null @@ -1 +0,0 @@ -7f112233445566778899001122334455667788990011223344556677889900aabb6000137f112233445566778899001122334455667788990011223344556677889900aabb6001137f112233445566778899001122334455667788990011223344556677889900aabb6002137f112233445566778899001122334455667788990011223344556677889900aabb6003137f112233445566778899001122334455667788990011223344556677889900aabb6004137f112233445566778899001122334455667788990011223344556677889900aabb6005137f112233445566778899001122334455667788990011223344556677889900aabb6006137f112233445566778899001122334455667788990011223344556677889900aabb6007137f112233445566778899001122334455667788990011223344556677889900aabb6008137f112233445566778899001122334455667788990011223344556677889900aabb6009137f112233445566778899001122334455667788990011223344556677889900aabb600a137f112233445566778899001122334455667788990011223344556677889900aabb600b137f112233445566778899001122334455667788990011223344556677889900aabb600c137f112233445566778899001122334455667788990011223344556677889900aabb600d137f112233445566778899001122334455667788990011223344556677889900aabb600e137f112233445566778899001122334455667788990011223344556677889900aabb600f137f112233445566778899001122334455667788990011223344556677889900aabb6010137f112233445566778899001122334455667788990011223344556677889900aabb6011137f112233445566778899001122334455667788990011223344556677889900aabb6012137f112233445566778899001122334455667788990011223344556677889900aabb6013137f112233445566778899001122334455667788990011223344556677889900aabb6014137f112233445566778899001122334455667788990011223344556677889900aabb6015137f112233445566778899001122334455667788990011223344556677889900aabb6016137f112233445566778899001122334455667788990011223344556677889900aabb6017137f112233445566778899001122334455667788990011223344556677889900aabb6018137f112233445566778899001122334455667788990011223344556677889900aabb6019137f112233445566778899001122334455667788990011223344556677889900aabb601a137f112233445566778899001122334455667788990011223344556677889900aabb601b137f112233445566778899001122334455667788990011223344556677889900aabb601c137f112233445566778899001122334455667788990011223344556677889900aabb601d137f112233445566778899001122334455667788990011223344556677889900aabb601e137f112233445566778899001122334455667788990011223344556677889900aabb601f137f112233445566778899001122334455667788990011223344556677889900aabb6020137f112233445566778899001122334455667788990011223344556677889900aabb6107de13 diff --git a/evmcc/test/mem/byte.lll b/evmcc/test/mem/byte.lll deleted file mode 100644 index 95b0f99dc..000000000 --- a/evmcc/test/mem/byte.lll +++ /dev/null @@ -1,105 +0,0 @@ - -(asm -0x112233445566778899001122334455667788990011223344556677889900aabb -0 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -1 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -2 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -3 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -4 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -5 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -6 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -7 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -8 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -9 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -10 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -11 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -12 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -13 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -14 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -15 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -16 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -17 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -18 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -19 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -20 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -21 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -22 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -23 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -24 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -25 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -26 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -27 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -28 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -29 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -30 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -31 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -32 -BYTE -0x112233445566778899001122334455667788990011223344556677889900aabb -2014 -BYTE -) \ No newline at end of file diff --git a/evmcc/test/mem/mem2.evm b/evmcc/test/mem/mem2.evm deleted file mode 100644 index 49cc6e8b1..000000000 --- a/evmcc/test/mem/mem2.evm +++ /dev/null @@ -1 +0,0 @@ -6001610d805b01556504409585d6df620493e05462061a80535b01 diff --git a/evmcc/test/mem/mem2.lll b/evmcc/test/mem/mem2.lll deleted file mode 100644 index 5345ee47c..000000000 --- a/evmcc/test/mem/mem2.lll +++ /dev/null @@ -1,15 +0,0 @@ - -(asm ;; [] -1 -3456 -MSIZE -ADD -MSTORE8 ;; [02] -4675432994527 -300000 -MSTORE -400000 -MLOAD -MSIZE -ADD -) \ No newline at end of file diff --git a/evmcc/test/mem/memtest1.evm b/evmcc/test/mem/memtest1.evm deleted file mode 100644 index 0506bf928..000000000 --- a/evmcc/test/mem/memtest1.evm +++ /dev/null @@ -1 +0,0 @@ -6002600055600360015560005360015301600254 diff --git a/evmcc/test/mem/memtest1.lll b/evmcc/test/mem/memtest1.lll deleted file mode 100644 index 4b4389ad8..000000000 --- a/evmcc/test/mem/memtest1.lll +++ /dev/null @@ -1,18 +0,0 @@ - -(asm ;; [] -2 -0 -MSTORE8 ;; [02] -3 -1 -MSTORE8 ;; [02 03] -0 -MLOAD ;; [2 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] -1 -MLOAD ;; [2 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 - ;; 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] -ADD -2 -MSTORE ;; [2 3 5 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 - ;; 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] -) \ No newline at end of file diff --git a/evmcc/test/mem/mstore1.evm b/evmcc/test/mem/mstore1.evm deleted file mode 100644 index ba6141ab1..000000000 --- a/evmcc/test/mem/mstore1.evm +++ /dev/null @@ -1 +0,0 @@ -6001600054 diff --git a/evmcc/test/mem/mstore1.lll b/evmcc/test/mem/mstore1.lll deleted file mode 100644 index 2d2ca32b5..000000000 --- a/evmcc/test/mem/mstore1.lll +++ /dev/null @@ -1,6 +0,0 @@ - -(asm ;; [] -1 -0 -MSTORE ;; [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1] -) \ No newline at end of file diff --git a/evmcc/test/ret/return1.evm b/evmcc/test/ret/return1.evm deleted file mode 100644 index 8092cb007..000000000 --- a/evmcc/test/ret/return1.evm +++ /dev/null @@ -1 +0,0 @@ -600160805460006080530b601b59600160005460206000f2602a58602760005460206000f26002608054 diff --git a/evmcc/test/ret/return1.lll b/evmcc/test/ret/return1.lll deleted file mode 100644 index 159d15ca3..000000000 --- a/evmcc/test/ret/return1.lll +++ /dev/null @@ -1,6 +0,0 @@ -;; code should return 39 -;; i should remain 1 -{ - [i] 1 - ( if (> @i 0) { (return 39) [i] 2 } (return 1) ) -} \ No newline at end of file diff --git a/evmcc/test/ret/return2.evm b/evmcc/test/ret/return2.evm deleted file mode 100644 index e29da7664..000000000 --- a/evmcc/test/ret/return2.evm +++ /dev/null @@ -1 +0,0 @@ -6001620f4240f2 diff --git a/evmcc/test/ret/return2.lll b/evmcc/test/ret/return2.lll deleted file mode 100644 index f5ee68f6e..000000000 --- a/evmcc/test/ret/return2.lll +++ /dev/null @@ -1,6 +0,0 @@ - -(asm -1 -1000000 -RETURN ;; return 1 byte from index 1M -) \ No newline at end of file diff --git a/evmcc/test/ret/return_test.evm b/evmcc/test/ret/return_test.evm deleted file mode 100644 index 977cf7c19..000000000 --- a/evmcc/test/ret/return_test.evm +++ /dev/null @@ -1 +0,0 @@ -60016064546002608454600360a45460606064f2 diff --git a/evmcc/test/ret/return_test.lll b/evmcc/test/ret/return_test.lll deleted file mode 100644 index c87a2d812..000000000 --- a/evmcc/test/ret/return_test.lll +++ /dev/null @@ -1,15 +0,0 @@ - -(asm -1 -100 -MSTORE -2 -132 -MSTORE -3 -164 -MSTORE -96 -100 -RETURN -) \ No newline at end of file diff --git a/evmcc/test/stack/oos.evm b/evmcc/test/stack/oos.evm deleted file mode 100644 index ea2f1c890..000000000 --- a/evmcc/test/stack/oos.evm +++ /dev/null @@ -1 +0,0 @@ -60018194505050509150 diff --git a/evmcc/test/stack/oos.lll b/evmcc/test/stack/oos.lll deleted file mode 100644 index 5394b06ba..000000000 --- a/evmcc/test/stack/oos.lll +++ /dev/null @@ -1,11 +0,0 @@ -(asm ;; x . v y z -1 ;; 1 x . v y z -DUP2 ;; x 1 x . v y z -SWAP5 ;; y 1 x . v x z -POP ;; 1 x . v x z -POP ;; x . v x z -POP ;; . v x z -POP ;; v x z -SWAP2 ;; z x v -POP ;; x v -) diff --git a/evmcc/test/stack/push_test.evm b/evmcc/test/stack/push_test.evm deleted file mode 100644 index d624cee1d..000000000 --- a/evmcc/test/stack/push_test.evm +++ /dev/null @@ -1 +0,0 @@ -60656107d26204a0c763026921f4640bc5588eb165372d0f1dca6e661ba1d901961c71670c55f7bc23038e3868056bc75e2d630fffff69021e19e0c9bab24000016a085d1c6e8050f0ea1c71bd6b0688be36543f3c36e638e37a6c03d41f73d55d0d482ae55555376dc76810d0fe03c91964d31c71c6f46e615dd0360c07d931663b14e38e38b16f2da3f99955a3adcf27ebb1caaaaaaa6e7014ccba6a8bb1ed35bd86bf065c71c71c2b7109491c5d4781b79c9009de6bfb8e38e38de8720414a0f6fdec81304d4c563e740bffffffffa573118427b3b4a05bc8a8a4de8459868000000000017406eb15e7331e727940d4ac54b7cdca1c71c71c71bd750567a91c9fefc96ebaa626a22f98c5e638e38e38e37a76032abd16c5b68006e15d5aa307e383f4e55555555555377701a6427bdc4f0d58eab5f48a3ec67f64e21c71c71c71c6f478080dd0a0c9b9ff2c2a0c740b06853a0a980ee38e38e38e38b17903c679cb5e8f2f9cb3b5d6652b0e7334f746faaaaaaaaaaaaa6e7a01b873815917ebb2bf3b890a1af495d6235bae3c71c71c71c71c2b7b07ae4cca96e1a55dfa49c85ad3c3e60e426b92fb8e38e38e38e38de87c036018bf074e292bcc7d6c8bea0f9699443046178bffffffffffffffa57d0e7d34c64a9c85d4460dbbca87196b61618a4bd2168000000000000000017e05b901f48a5b994d6572502bc4ea43140486666416aa1c71c71c71c71c71bd7f047889870c178fc477414ea231d70467a388fffe31b4e638e38e38e38e38e37a diff --git a/evmcc/test/stack/push_test.lll b/evmcc/test/stack/push_test.lll deleted file mode 100644 index 832daaec1..000000000 --- a/evmcc/test/stack/push_test.lll +++ /dev/null @@ -1,35 +0,0 @@ - -(asm -101 ;; PUSH1 -2002 ;; PUSH2 -303303 ;; PUSH3 -40444404 ;; PUSH4 -50555555505 ;; PUSH5 -60666666666606 -7777777777777777 -888888888888888888 -99999999999999999999 -10000000000000000000001 -10111111111111111111111101 -2022222222222222222222222202 -303333333333333333333333333303 -4044444444444444444444444444444404 -505555555555555555555555555555555505 -60666666666666666666666666666666666606 -7077777777777777777777777777777777777707 -808888888888888888888888888888888888888808 -90999999999999999999999999999999999999999909 -100000000000000000000000000000000000000000000001 -10111111111111111111111111111111111111111111111101 -2022222222222222222222222222222222222222222222222202 -303333333333333333333333333333333333333333333333333303 -40444444444444444444444444444444444444444444444444444404 -50555555555555555555555555555555555555555555555555555555505 -6066666666666666666666666666666666666666666666666666666666606 -707777777777777777777777777777777777777777777777777777777777707 -808888888888888888888888888888888888888888888888888888888888888808 -90999999999999999999999999999999999999999999999999999999999999999909 -100000000000000000000000000000000000000000000000000000000000000000000001 -10111111111111111111111111111111111111111111111111111111111111111111111101 -2022222222222222222222222222222222222222222222222222222222222222222222222202 ;; PUSH32 -) \ No newline at end of file diff --git a/evmcc/test/stack/stack_test.evm b/evmcc/test/stack/stack_test.evm deleted file mode 100644 index 02417c967..000000000 --- a/evmcc/test/stack/stack_test.evm +++ /dev/null @@ -1 +0,0 @@ -65372d0f1dca6e661925338e3e5c2b808280848184505050505050506104576108ae81819290 diff --git a/evmcc/test/stack/stack_test.lll b/evmcc/test/stack/stack_test.lll deleted file mode 100644 index fdf83594c..000000000 --- a/evmcc/test/stack/stack_test.lll +++ /dev/null @@ -1,8 +0,0 @@ - -(asm -123 -SSTORE -SLOAD -123 -SUB -) \ No newline at end of file diff --git a/evmcc/test/stack/stackjump.evm b/evmcc/test/stack/stackjump.evm deleted file mode 100644 index baddec42e..000000000 --- a/evmcc/test/stack/stackjump.evm +++ /dev/null @@ -1 +0,0 @@ -600460066009601358600a036000545b6000f260005401600958 \ No newline at end of file diff --git a/evmcc/test/stack/stackjump.lll b/evmcc/test/stack/stackjump.lll deleted file mode 100644 index f5da5e733..000000000 --- a/evmcc/test/stack/stackjump.lll +++ /dev/null @@ -1,3 +0,0 @@ -(asm -0x4 0x6 0x9 0x13 JUMP 0xa SUB 0x0 MSTORE MSIZE 0x0 RETURN 0x0 MSTORE ADD 0x9 JUMP -) diff --git a/evmcc/test/stack/swap.evm b/evmcc/test/stack/swap.evm deleted file mode 100644 index d17f0ee09..000000000 --- a/evmcc/test/stack/swap.evm +++ /dev/null @@ -1 +0,0 @@ -600560026001600c59505000906001601559505000036000546001601ff2 diff --git a/evmcc/test/stack/swap.lll b/evmcc/test/stack/swap.lll deleted file mode 100644 index 90dee585d..000000000 --- a/evmcc/test/stack/swap.lll +++ /dev/null @@ -1,31 +0,0 @@ -(asm -5 ;; 0 -2 ;; 2 -1 ;; 4 -12 ;; 6 -JUMPI ;; 8 - -POP ;; 9 -POP ;; 10 -STOP ;; 11 - -;; stack = 2,1 -SWAP1 ;; 12 -1 ;; 13 -21 ;; 15 -JUMPI ;; 17 - -POP ;; 18 -POP ;; 19 -STOP ;; 20 - -;; stack = 1,2 -SUB ;; 21 -0 -MSTORE -1 -31 -RETURN ;; returns 03 -) - - diff --git a/evmcc/test/stack/swapswap.evm b/evmcc/test/stack/swapswap.evm deleted file mode 100644 index fb4f1bf75..000000000 --- a/evmcc/test/stack/swapswap.evm +++ /dev/null @@ -1 +0,0 @@ -600260056001600c5950500090906001601659505000036000546001601ff2 diff --git a/evmcc/test/stack/swapswap.lll b/evmcc/test/stack/swapswap.lll deleted file mode 100644 index 1fedf726e..000000000 --- a/evmcc/test/stack/swapswap.lll +++ /dev/null @@ -1,32 +0,0 @@ -(asm -2 ;; 0 -5 ;; 2 -1 ;; 4 -12 ;; 6 -JUMPI ;; 8 - -POP ;; 9 -POP ;; 10 -STOP ;; 11 - -;; stack = 2,1 -SWAP1 ;; 12 -SWAP1 ;; 13 -1 ;; 14 -22 ;; 16 -JUMPI ;; 18 - -POP ;; 19 -POP ;; 20 -STOP ;; 21 - -;; stack = 2,1 -SUB ;; 22 -0 -MSTORE -1 -31 -RETURN ;; returns 03 -) - - diff --git a/evmcc/test/stack/test.evm b/evmcc/test/stack/test.evm deleted file mode 100644 index ea2f1c890..000000000 --- a/evmcc/test/stack/test.evm +++ /dev/null @@ -1 +0,0 @@ -60018194505050509150 diff --git a/evmcc/test/vmtests/vmArithPerformanceTest.json b/evmcc/test/vmtests/vmArithPerformanceTest.json deleted file mode 100644 index d9017517f..000000000 --- a/evmcc/test/vmtests/vmArithPerformanceTest.json +++ /dev/null @@ -1,260 +0,0 @@ -{ - "arith-1" : { - "callcreates" : [ ], - "env" : { - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", - "currentDifficulty" : "256", - "currentGasLimit" : "10000000", - "currentNumber" : "0", - "currentTimestamp" : "1", - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" - }, - "exec" : { - "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "code" : "0x600a60005260005160105760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600556", - "data" : "0x", - "gas" : "1000000", - "gasPrice" : "100000000000000", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "value" : "1000000000000000000" - }, - "gas" : "999538", - "out" : "0x0000000000000000000000000000000000000000000000000000001b9c636491", - "post" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "code" : "0x600a60005260005160105760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600556", - "nonce" : "0", - "storage" : { - } - } - }, - "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "code" : "0x600a60005260005160105760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600556", - "nonce" : "0", - "storage" : { } - } - } - } - - , - - "arith-2" : { - "callcreates" : [ ], - "env" : { - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", - "currentDifficulty" : "256", - "currentGasLimit" : "10000000", - "currentNumber" : "0", - "currentTimestamp" : "1", - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" - }, - "exec" : { - "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "code" : "0x606460005260005160105760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600556", - "data" : "0x", - "gas" : "1000000", - "gasPrice" : "100000000000000", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "value" : "1000000000000000000" - }, - "gas" : "995488", - "out" : "0x0000000000000000000000000000000000000000000000000000001b9c636491", - "post" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "code" : "0x606460005260005160105760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600556", - "nonce" : "0", - "storage" : { - } - } - }, - "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "code" : "0x606460005260005160105760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600556", - "nonce" : "0", - "storage" : { } - } - } - } - - , - - "arith-3" : { - "callcreates" : [ ], - "env" : { - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", - "currentDifficulty" : "256", - "currentGasLimit" : "10000000", - "currentNumber" : "0", - "currentTimestamp" : "1", - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" - }, - "exec" : { - "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "code" : "0x6103e860005260005160115760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600656", - "data" : "0x", - "gas" : "1000000", - "gasPrice" : "100000000000000", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "value" : "1000000000000000000" - }, - "gas" : "954988", - "out" : "0x0000000000000000000000000000000000000000000000000000001b9c636491", - "post" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "code" : "0x6103e860005260005160115760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600656", - "nonce" : "0", - "storage" : { - } - } - }, - "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "code" : "0x6103e860005260005160115760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600656", - "nonce" : "0", - "storage" : { } - } - } - } - - , - - "arith-4" : { - "callcreates" : [ ], - "env" : { - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", - "currentDifficulty" : "256", - "currentGasLimit" : "10000000", - "currentNumber" : "0", - "currentTimestamp" : "1", - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" - }, - "exec" : { - "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "code" : "0x61271060005260005160115760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600656", - "data" : "0x", - "gas" : "1000000", - "gasPrice" : "100000000000000", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "value" : "1000000000000000000" - }, - "gas" : "549988", - "out" : "0x0000000000000000000000000000000000000000000000000000001b9c636491", - "post" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "code" : "0x61271060005260005160115760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600656", - "nonce" : "0", - "storage" : { - } - } - }, - "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "code" : "0x61271060005260005160115760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600656", - "nonce" : "0", - "storage" : { } - } - } - } - - - , - - - "arith-5" : { - "callcreates" : [ ], - "env" : { - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", - "currentDifficulty" : "256", - "currentGasLimit" : "10000000", - "currentNumber" : "0", - "currentTimestamp" : "1", - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" - }, - "exec" : { - "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "code" : "0x620186a060005260005160125760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600756", - "data" : "0x", - "gas" : "10000000", - "gasPrice" : "100000000000000", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "value" : "1000000000000000000" - }, - "gas" : "5499988", - "out" : "0x0000000000000000000000000000000000000000000000000000001b9c636491", - "post" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "code" : "0x620186a060005260005160125760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600756", - "nonce" : "0", - "storage" : { - } - } - }, - "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "code" : "0x620186a060005260005160125760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600756", - "nonce" : "0", - "storage" : { } - } - } - } - -, - - "arith-6" : { - "callcreates" : [ ], - "env" : { - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", - "currentDifficulty" : "256", - "currentGasLimit" : "100000000", - "currentNumber" : "0", - "currentTimestamp" : "1", - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" - }, - "exec" : { - "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "code" : "0x620f424060005260005160125760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600756", - "data" : "0x", - "gas" : "100000000", - "gasPrice" : "100000000000000", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "value" : "1000000000000000000" - }, - "gas" : "54999988", - "out" : "0x0000000000000000000000000000000000000000000000000000001b9c636491", - "post" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "code" : "0x620f424060005260005160125760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600756", - "nonce" : "0", - "storage" : { - } - } - }, - "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "code" : "0x620f424060005260005160125760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600756", - "nonce" : "0", - "storage" : { } - } - } - } - -} diff --git a/evmcc/test/vmtests/vmPerformanceTest.json b/evmcc/test/vmtests/vmPerformanceTest.json deleted file mode 100644 index 604e45993..000000000 --- a/evmcc/test/vmtests/vmPerformanceTest.json +++ /dev/null @@ -1,214 +0,0 @@ -{ - "mulmodloop" : { - "callcreates" : [ ], - "env" : { - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", - "currentDifficulty" : "256", - "currentGasLimit" : "10000000", - "currentNumber" : "0", - "currentTimestamp" : "1", - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" - }, - "exec" : { - "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "code" : "0x60015b68010000000000000000908060010109600356", - "data" : "0x", - "gas" : "10000000", - "gasPrice" : "100000000000000", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "value" : "1000000000000000000" - }, - "gas" : "0", - "out" : "0x0", - "post" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "code" : "0x60015b68010000000000000000908060010109600356", - "nonce" : "0", - "storage" : { - } - } - }, - "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "code" : "0x60015b68010000000000000000908060010109600356", - "nonce" : "0", - "storage" : { } - } - } - }, - - - "for-1e06" : { - "callcreates" : [ ], - "env" : { - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", - "currentDifficulty" : "256", - "currentGasLimit" : "100000000", - "currentNumber" : "0", - "currentTimestamp" : "1", - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" - }, - "exec" : { - "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "code" : "0x620f42406080525b6000608051111560285760a0516080510160a0526001608051036080526007565b", - "data" : "0x", - "gas" : "30000000", - "gasPrice" : "100000000000000", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "value" : "1000000000000000000" - }, - "gas" : "6999982", - "out" : "0x00", - "post" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "code" : "0x620f42406080525b6000608051111560285760a0516080510160a0526001608051036080526007565b", - "nonce" : "0", - "storage" : { - } - } - }, - "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "code" : "0x620f42406080525b6000608051111560285760a0516080510160a0526001608051036080526007565b", - "nonce" : "0", - "storage" : { } - } - } - }, - - "fib25" : { - "callcreates" : [ - ], - "env" : { - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", - "currentDifficulty" : "256", - "currentGasLimit" : "100000000", - "currentNumber" : "0", - "currentTimestamp" : "1", - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" - }, - "exec" : { - "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "code" : "0x6007601e6010565b60005260206000f25b600381106030576021600282036010565b602b600183036010565b016033565b60015b90509056", - "data" : "0x", - "gas" : "40000000", - "gasPrice" : "100000000000000", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "value" : "1000000000000000000" - }, - "gas" : "5886377", - "out" : "0x00000000000000000000000000000000000000000000000000000000000cb228", - "post" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "code" : "0x6007601e6010565b60005260206000f25b600381106030576021600282036010565b602b600183036010565b016033565b60015b90509056", - "nonce" : "0", - "storage" : { - } - } - }, - "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "code" : "0x6007601e6010565b60005260206000f25b600381106030576021600282036010565b602b600183036010565b016033565b60015b90509056", - "nonce" : "0", - "storage" : { - } - } - } - }, - - "ackermann37" : { - "callcreates" : [ - ], - "env" : { - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", - "currentDifficulty" : "256", - "currentGasLimit" : "20000000", - "currentNumber" : "0", - "currentTimestamp" : "1", - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" - }, - "exec" : { - "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "code" : "0x6009600360076012565b60005260206000f25b60008214604a5760008114603957603560018303603184600185036012565b6012565b6046565b60456001830360016012565b5b604f565b600181015b905090509056", - "data" : "0x", - "gas" : "20000000", - "gasPrice" : "100000000000000", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "value" : "1000000000000000000" - }, - "gas" : "913456", - "out" : "0x00000000000000000000000000000000000000000000000000000000000003fd", - "post" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "code" : "0x6009600360076012565b60005260206000f25b60008214604a5760008114603957603560018303603184600185036012565b6012565b6046565b60456001830360016012565b5b604f565b600181015b905090509056", - "nonce" : "0", - "storage" : { - } - } - }, - "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "code" : "0x6009600360076012565b60005260206000f25b60008214604a5760008114603957603560018303603184600185036012565b6012565b6046565b60456001830360016012565b5b604f565b600181015b905090509056", - "nonce" : "0", - "storage" : { - } - } - } - }, - - "jumptable100" : { - "callcreates" : [ - ], - "env" : { - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", - "currentDifficulty" : "256", - "currentGasLimit" : "10000000", - "currentNumber" : "0", - "currentTimestamp" : "1", - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" - }, - "exec" : { - "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "code" : "0x6103e85b60019003806000146104605761001a600160005256005b610025600260005256005b610030600360005256005b61003b600460005256005b610046600560005256005b610051600660005256005b61005c600760005256005b610067600860005256005b610072600960005256005b61007d600a60005256005b610088600b60005256005b610093600c60005256005b61009e600d60005256005b6100a9600e60005256005b6100b4600f60005256005b6100bf601060005256005b6100ca601160005256005b6100d5601260005256005b6100e0601360005256005b6100eb601460005256005b6100f6601560005256005b610101601660005256005b61010c601760005256005b610117601860005256005b610122601960005256005b61012d601a60005256005b610138601b60005256005b610143601c60005256005b61014e601d60005256005b610159601e60005256005b610164601f60005256005b61016f602060005256005b61017a602160005256005b610185602260005256005b610190602360005256005b61019b602460005256005b6101a6602560005256005b6101b1602660005256005b6101bc602760005256005b6101c7602860005256005b6101d2602960005256005b6101dd602a60005256005b6101e8602b60005256005b6101f3602c60005256005b6101fe602d60005256005b610209602e60005256005b610214602f60005256005b61021f603060005256005b61022a603160005256005b610235603260005256005b610240603360005256005b61024b603460005256005b610256603560005256005b610261603660005256005b61026c603760005256005b610277603860005256005b610282603960005256005b61028d603a60005256005b610298603b60005256005b6102a3603c60005256005b6102ae603d60005256005b6102b9603e60005256005b6102c4603f60005256005b6102cf604060005256005b6102da604160005256005b6102e5604260005256005b6102f0604360005256005b6102fb604460005256005b610306604560005256005b610311604660005256005b61031c604760005256005b610327604860005256005b610332604960005256005b61033d604a60005256005b610348604b60005256005b610353604c60005256005b61035e604d60005256005b610369604e60005256005b610374604f60005256005b61037f605060005256005b61038a605160005256005b610395605260005256005b6103a0605360005256005b6103ab605460005256005b6103b6605560005256005b6103c1605660005256005b6103cc605760005256005b6103d7605860005256005b6103e2605960005256005b6103ed605a60005256005b6103f8605b60005256005b610403605c60005256005b61040e605d60005256005b610419605e60005256005b610424605f60005256005b61042f606060005256005b61043a606160005256005b610445606260005256005b610450606360005256005b61045b606460005256005b610003565b60206000f2", - "data" : "0x", - "gas" : "1000000", - "gasPrice" : "100000000000000", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "value" : "1000000000000000000" - }, - "gas" : "389596", - "out" : "0x0000000000000000000000000000000000000000000000000000000000000064", - "post" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "code" : "0x6103e85b60019003806000146104605761001a600160005256005b610025600260005256005b610030600360005256005b61003b600460005256005b610046600560005256005b610051600660005256005b61005c600760005256005b610067600860005256005b610072600960005256005b61007d600a60005256005b610088600b60005256005b610093600c60005256005b61009e600d60005256005b6100a9600e60005256005b6100b4600f60005256005b6100bf601060005256005b6100ca601160005256005b6100d5601260005256005b6100e0601360005256005b6100eb601460005256005b6100f6601560005256005b610101601660005256005b61010c601760005256005b610117601860005256005b610122601960005256005b61012d601a60005256005b610138601b60005256005b610143601c60005256005b61014e601d60005256005b610159601e60005256005b610164601f60005256005b61016f602060005256005b61017a602160005256005b610185602260005256005b610190602360005256005b61019b602460005256005b6101a6602560005256005b6101b1602660005256005b6101bc602760005256005b6101c7602860005256005b6101d2602960005256005b6101dd602a60005256005b6101e8602b60005256005b6101f3602c60005256005b6101fe602d60005256005b610209602e60005256005b610214602f60005256005b61021f603060005256005b61022a603160005256005b610235603260005256005b610240603360005256005b61024b603460005256005b610256603560005256005b610261603660005256005b61026c603760005256005b610277603860005256005b610282603960005256005b61028d603a60005256005b610298603b60005256005b6102a3603c60005256005b6102ae603d60005256005b6102b9603e60005256005b6102c4603f60005256005b6102cf604060005256005b6102da604160005256005b6102e5604260005256005b6102f0604360005256005b6102fb604460005256005b610306604560005256005b610311604660005256005b61031c604760005256005b610327604860005256005b610332604960005256005b61033d604a60005256005b610348604b60005256005b610353604c60005256005b61035e604d60005256005b610369604e60005256005b610374604f60005256005b61037f605060005256005b61038a605160005256005b610395605260005256005b6103a0605360005256005b6103ab605460005256005b6103b6605560005256005b6103c1605660005256005b6103cc605760005256005b6103d7605860005256005b6103e2605960005256005b6103ed605a60005256005b6103f8605b60005256005b610403605c60005256005b61040e605d60005256005b610419605e60005256005b610424605f60005256005b61042f606060005256005b61043a606160005256005b610445606260005256005b610450606360005256005b61045b606460005256005b610003565b60206000f2", - "nonce" : "0", - "storage" : { - } - } - }, - "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "code" : "0x6103e85b60019003806000146104605761001a600160005256005b610025600260005256005b610030600360005256005b61003b600460005256005b610046600560005256005b610051600660005256005b61005c600760005256005b610067600860005256005b610072600960005256005b61007d600a60005256005b610088600b60005256005b610093600c60005256005b61009e600d60005256005b6100a9600e60005256005b6100b4600f60005256005b6100bf601060005256005b6100ca601160005256005b6100d5601260005256005b6100e0601360005256005b6100eb601460005256005b6100f6601560005256005b610101601660005256005b61010c601760005256005b610117601860005256005b610122601960005256005b61012d601a60005256005b610138601b60005256005b610143601c60005256005b61014e601d60005256005b610159601e60005256005b610164601f60005256005b61016f602060005256005b61017a602160005256005b610185602260005256005b610190602360005256005b61019b602460005256005b6101a6602560005256005b6101b1602660005256005b6101bc602760005256005b6101c7602860005256005b6101d2602960005256005b6101dd602a60005256005b6101e8602b60005256005b6101f3602c60005256005b6101fe602d60005256005b610209602e60005256005b610214602f60005256005b61021f603060005256005b61022a603160005256005b610235603260005256005b610240603360005256005b61024b603460005256005b610256603560005256005b610261603660005256005b61026c603760005256005b610277603860005256005b610282603960005256005b61028d603a60005256005b610298603b60005256005b6102a3603c60005256005b6102ae603d60005256005b6102b9603e60005256005b6102c4603f60005256005b6102cf604060005256005b6102da604160005256005b6102e5604260005256005b6102f0604360005256005b6102fb604460005256005b610306604560005256005b610311604660005256005b61031c604760005256005b610327604860005256005b610332604960005256005b61033d604a60005256005b610348604b60005256005b610353604c60005256005b61035e604d60005256005b610369604e60005256005b610374604f60005256005b61037f605060005256005b61038a605160005256005b610395605260005256005b6103a0605360005256005b6103ab605460005256005b6103b6605560005256005b6103c1605660005256005b6103cc605760005256005b6103d7605860005256005b6103e2605960005256005b6103ed605a60005256005b6103f8605b60005256005b610403605c60005256005b61040e605d60005256005b610419605e60005256005b610424605f60005256005b61042f606060005256005b61043a606160005256005b610445606260005256005b610450606360005256005b61045b606460005256005b610003565b60206000f2", - "nonce" : "0", - "storage" : { - } - } - } - }, - -} diff --git a/evmcc/test/vmtests/vm_jump.json b/evmcc/test/vmtests/vm_jump.json deleted file mode 100644 index 6b63edeae..000000000 --- a/evmcc/test/vmtests/vm_jump.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "jumpi_at_the_end" : { - "callcreates" : [ ], - "env" : { - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", - "currentDifficulty" : "256", - "currentGasLimit" : "10000000", - "currentNumber" : "0", - "currentTimestamp" : "1", - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" - }, - "exec" : { - "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "code" : "(asm 10 0 MSTORE JUMPDEST 0 MLOAD 1 SWAP1 SUB DUP1 0 MSTORE 6 JUMPI)", - "data" : "0x", - "gas" : "1000", - "gasPrice" : "100000000000000", - "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "value" : "1000000000000000000" - }, - "gas" : "895", - "out" : "0x0", - "pre" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "code" : "(asm 10 0 MSTORE JUMPDEST 0 MLOAD 1 SWAP1 SUB DUP1 0 MSTORE 6 JUMPI)", - "nonce" : "0", - "storage" : {} - } - }, - "post" : { - "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : "1000000000000000000", - "code" : "(asm 10 0 MSTORE JUMPDEST 0 MLOAD 1 SWAP1 SUB DUP1 0 MSTORE 6 JUMPI)", - "nonce" : "0", - "storage" : {} - } - } - } -} diff --git a/libevmjit-cpp/CMakeLists.txt b/libevmjit-cpp/CMakeLists.txt index 58375e4ee..53448332b 100644 --- a/libevmjit-cpp/CMakeLists.txt +++ b/libevmjit-cpp/CMakeLists.txt @@ -9,6 +9,11 @@ set(SOURCES ) source_group("" FILES ${SOURCES}) +if(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC") +else() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") # add PIC for archive +endif() + add_library(${TARGET_NAME} ${SOURCES}) set_property(TARGET ${TARGET_NAME} PROPERTY FOLDER "libs") diff --git a/libevmjit-cpp/Env.cpp b/libevmjit-cpp/Env.cpp index f89897792..11882d79d 100644 --- a/libevmjit-cpp/Env.cpp +++ b/libevmjit-cpp/Env.cpp @@ -1,4 +1,5 @@ +#pragma GCC diagnostic ignored "-Wconversion" #include #include #include @@ -46,23 +47,22 @@ extern "C" *o_hash = _env->blockhash(llvm2eth(*_number)); } - EXPORT void env_create(ExtVMFace* _env, i256* io_gas, i256* _endowment, byte* _initBeg, uint64_t _initSize, h256* o_address) + EXPORT void env_create(ExtVMFace* _env, int64_t* io_gas, i256* _endowment, byte* _initBeg, uint64_t _initSize, h256* o_address) { auto endowment = llvm2eth(*_endowment); if (_env->balance(_env->myAddress) >= endowment && _env->depth < 1024) { _env->subBalance(endowment); - auto gas = llvm2eth(*io_gas); - OnOpFunc onOp {}; // TODO: Handle that thing - h256 address(_env->create(endowment, gas, {_initBeg, _initSize}, onOp), h256::AlignRight); - *io_gas = eth2llvm(gas); + u256 gas = *io_gas; + h256 address(_env->create(endowment, gas, {_initBeg, _initSize}, {}), h256::AlignRight); + *io_gas = static_cast(gas); *o_address = address; } else *o_address = {}; } - EXPORT bool env_call(ExtVMFace* _env, i256* io_gas, h256* _receiveAddress, i256* _value, byte* _inBeg, uint64_t _inSize, byte* _outBeg, uint64_t _outSize, h256* _codeAddress) + EXPORT bool env_call(ExtVMFace* _env, int64_t* io_gas, h256* _receiveAddress, i256* _value, byte* _inBeg, uint64_t _inSize, byte* _outBeg, uint64_t _outSize, h256* _codeAddress) { auto value = llvm2eth(*_value); if (_env->balance(_env->myAddress) >= value && _env->depth < 1024) @@ -70,12 +70,11 @@ extern "C" _env->subBalance(value); auto receiveAddress = right160(*_receiveAddress); auto inRef = bytesConstRef{_inBeg, _inSize}; - auto outRef = bytesConstRef{_outBeg, _outSize}; - OnOpFunc onOp {}; // TODO: Handle that thing + auto outRef = bytesRef{_outBeg, _outSize}; auto codeAddress = right160(*_codeAddress); - auto gas = llvm2eth(*io_gas); - auto ret = _env->call(receiveAddress, value, inRef, gas, outRef, onOp, {}, codeAddress); - *io_gas = eth2llvm(gas); + u256 gas = *io_gas; + auto ret = _env->call(receiveAddress, value, inRef, gas, outRef, {}, {}, codeAddress); + *io_gas = static_cast(gas); return ret; } diff --git a/libevmjit-cpp/JitVM.cpp b/libevmjit-cpp/JitVM.cpp index 413525e5a..e28fcd39f 100644 --- a/libevmjit-cpp/JitVM.cpp +++ b/libevmjit-cpp/JitVM.cpp @@ -1,7 +1,14 @@ +#pragma GCC diagnostic ignored "-Wconversion" + #include "JitVM.h" + +#include +#include #include +#include #include + #include "Utils.h" namespace dev @@ -11,22 +18,27 @@ namespace eth extern "C" void env_sload(); // fake declaration for linker symbol stripping workaround, see a call below -bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const&, uint64_t) +bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step) { using namespace jit; - if (m_gas > std::numeric_limits::max()) - BOOST_THROW_EXCEPTION(OutOfGas()); // Do not accept requests with gas > 2^63 (int64 max) // TODO: Return "not accepted" exception to allow interpreted handle that - - if (_ext.gasPrice > std::numeric_limits::max()) - BOOST_THROW_EXCEPTION(OutOfGas()); - - if (_ext.currentBlock.number > std::numeric_limits::max()) - BOOST_THROW_EXCEPTION(OutOfGas()); - - if (_ext.currentBlock.timestamp > std::numeric_limits::max()) - BOOST_THROW_EXCEPTION(OutOfGas()); + auto rejected = false; + // TODO: Rejecting transactions with gas limit > 2^63 can be used by attacker to take JIT out of scope + rejected |= m_gas > std::numeric_limits::max(); // Do not accept requests with gas > 2^63 (int64 max) + rejected |= _ext.gasPrice > std::numeric_limits::max(); + rejected |= _ext.currentBlock.number > std::numeric_limits::max(); + rejected |= _ext.currentBlock.timestamp > std::numeric_limits::max(); + if (rejected) + { + cwarn << "Execution rejected by EVM JIT (gas limit: " << m_gas << "), executing with interpreter"; + VMFactory::setKind(VMKind::Interpreter); + m_fallbackVM = VMFactory::create(m_gas); + VMFactory::setKind(VMKind::JIT); + auto&& output = m_fallbackVM->go(_ext, _onOp, _step); + m_gas = m_fallbackVM->gas(); // copy remaining gas, Executive expects it + return output; + } m_data.gas = static_cast(m_gas); m_data.gasPrice = static_cast(_ext.gasPrice); @@ -43,9 +55,10 @@ bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const&, uint64_t) m_data.timestamp = static_cast(_ext.currentBlock.timestamp); m_data.code = _ext.code.data(); m_data.codeSize = _ext.code.size(); + m_data.codeHash = eth2llvm(sha3(_ext.code)); auto env = reinterpret_cast(&_ext); - auto exitCode = m_engine.run(_ext.code, &m_data, env); + auto exitCode = m_engine.run(&m_data, env); switch (exitCode) { case ReturnCode::Suicide: diff --git a/libevmjit-cpp/JitVM.h b/libevmjit-cpp/JitVM.h index 90855127e..58caa3648 100644 --- a/libevmjit-cpp/JitVM.h +++ b/libevmjit-cpp/JitVM.h @@ -12,15 +12,13 @@ class JitVM: public VMFace { virtual bytesConstRef go(ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) override final; - enum Kind: bool { Interpreter, JIT }; - static std::unique_ptr create(Kind, u256 _gas = 0); - private: friend class VMFactory; explicit JitVM(u256 _gas = 0) : VMFace(_gas) {} jit::RuntimeData m_data; jit::ExecutionEngine m_engine; + std::unique_ptr m_fallbackVM; ///< VM used in case of input data rejected by JIT }; diff --git a/libevmjit/Arith256.cpp b/libevmjit/Arith256.cpp index 2ec227dcc..b67b157a6 100644 --- a/libevmjit/Arith256.cpp +++ b/libevmjit/Arith256.cpp @@ -1,11 +1,15 @@ #include "Arith256.h" -#include "Runtime.h" -#include "Type.h" -#include "Endianness.h" -#include -#include #include +#include + +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + +#include "Type.h" +#include "Endianness.h" +#include "Utils.h" namespace dev { @@ -16,29 +20,102 @@ namespace jit Arith256::Arith256(llvm::IRBuilder<>& _builder) : CompilerHelper(_builder) -{ - using namespace llvm; +{} - m_result = m_builder.CreateAlloca(Type::Word, nullptr, "arith.result"); - m_arg1 = m_builder.CreateAlloca(Type::Word, nullptr, "arith.arg1"); - m_arg2 = m_builder.CreateAlloca(Type::Word, nullptr, "arith.arg2"); - m_arg3 = m_builder.CreateAlloca(Type::Word, nullptr, "arith.arg3"); +void Arith256::debug(llvm::Value* _value, char _c) +{ + if (!m_debug) + { + llvm::Type* argTypes[] = {Type::Word, m_builder.getInt8Ty()}; + m_debug = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::ExternalLinkage, "debug", getModule()); + } + createCall(m_debug, {m_builder.CreateZExtOrTrunc(_value, Type::Word), m_builder.getInt8(_c)}); +} - using Linkage = GlobalValue::LinkageTypes; +llvm::Function* Arith256::getMulFunc() +{ + auto& func = m_mul; + if (!func) + { + llvm::Type* argTypes[] = {Type::Word, Type::Word}; + func = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "mul", getModule()); - llvm::Type* arg2Types[] = {Type::WordPtr, Type::WordPtr, Type::WordPtr}; + auto x = &func->getArgumentList().front(); + x->setName("x"); + auto y = x->getNextNode(); + y->setName("y"); - m_mul = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_mul", getModule()); + InsertPointGuard guard{m_builder}; + auto bb = llvm::BasicBlock::Create(m_builder.getContext(), {}, func); + m_builder.SetInsertPoint(bb); + auto i64 = Type::Size; + auto i128 = m_builder.getIntNTy(128); + auto i256 = Type::Word; + auto x_lo = m_builder.CreateTrunc(x, i64, "x.lo"); + auto y_lo = m_builder.CreateTrunc(y, i64, "y.lo"); + auto x_mi = m_builder.CreateTrunc(m_builder.CreateLShr(x, Constant::get(64)), i64); + auto y_mi = m_builder.CreateTrunc(m_builder.CreateLShr(y, Constant::get(64)), i64); + auto x_hi = m_builder.CreateTrunc(m_builder.CreateLShr(x, Constant::get(128)), i128); + auto y_hi = m_builder.CreateTrunc(m_builder.CreateLShr(y, Constant::get(128)), i128); + + auto t1 = m_builder.CreateMul(m_builder.CreateZExt(x_lo, i128), m_builder.CreateZExt(y_lo, i128)); + auto t2 = m_builder.CreateMul(m_builder.CreateZExt(x_lo, i128), m_builder.CreateZExt(y_mi, i128)); + auto t3 = m_builder.CreateMul(m_builder.CreateZExt(x_lo, i128), y_hi); + auto t4 = m_builder.CreateMul(m_builder.CreateZExt(x_mi, i128), m_builder.CreateZExt(y_lo, i128)); + auto t5 = m_builder.CreateMul(m_builder.CreateZExt(x_mi, i128), m_builder.CreateZExt(y_mi, i128)); + auto t6 = m_builder.CreateMul(m_builder.CreateZExt(x_mi, i128), y_hi); + auto t7 = m_builder.CreateMul(x_hi, m_builder.CreateZExt(y_lo, i128)); + auto t8 = m_builder.CreateMul(x_hi, m_builder.CreateZExt(y_mi, i128)); + + auto p = m_builder.CreateZExt(t1, i256); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t2, i256), Constant::get(64))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t3, i256), Constant::get(128))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t4, i256), Constant::get(64))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t5, i256), Constant::get(128))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t6, i256), Constant::get(192))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t7, i256), Constant::get(128))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t8, i256), Constant::get(192))); + m_builder.CreateRet(p); + } + return func; } -void Arith256::debug(llvm::Value* _value, char _c) +llvm::Function* Arith256::getMul512Func() { - if (!m_debug) + auto& func = m_mul512; + if (!func) { - llvm::Type* argTypes[] = {Type::Word, m_builder.getInt8Ty()}; - m_debug = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::ExternalLinkage, "debug", getModule()); + auto i512 = m_builder.getIntNTy(512); + llvm::Type* argTypes[] = {Type::Word, Type::Word}; + func = llvm::Function::Create(llvm::FunctionType::get(i512, argTypes, false), llvm::Function::PrivateLinkage, "mul512", getModule()); + + auto x = &func->getArgumentList().front(); + x->setName("x"); + auto y = x->getNextNode(); + y->setName("y"); + + InsertPointGuard guard{m_builder}; + auto bb = llvm::BasicBlock::Create(m_builder.getContext(), {}, func); + m_builder.SetInsertPoint(bb); + auto i128 = m_builder.getIntNTy(128); + auto i256 = Type::Word; + auto x_lo = m_builder.CreateZExt(m_builder.CreateTrunc(x, i128, "x.lo"), i256); + auto y_lo = m_builder.CreateZExt(m_builder.CreateTrunc(y, i128, "y.lo"), i256); + auto x_hi = m_builder.CreateZExt(m_builder.CreateTrunc(m_builder.CreateLShr(x, Constant::get(128)), i128, "x.hi"), i256); + auto y_hi = m_builder.CreateZExt(m_builder.CreateTrunc(m_builder.CreateLShr(y, Constant::get(128)), i128, "y.hi"), i256); + + auto t1 = createCall(getMulFunc(), {x_lo, y_lo}); + auto t2 = createCall(getMulFunc(), {x_lo, y_hi}); + auto t3 = createCall(getMulFunc(), {x_hi, y_lo}); + auto t4 = createCall(getMulFunc(), {x_hi, y_hi}); + + auto p = m_builder.CreateZExt(t1, i512); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t2, i512), m_builder.getIntN(512, 128))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t3, i512), m_builder.getIntN(512, 128))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t4, i512), m_builder.getIntN(512, 256))); + m_builder.CreateRet(p); } - createCall(m_debug, {_value, m_builder.getInt8(_c)}); + return func; } llvm::Function* Arith256::getDivFunc(llvm::Type* _type) @@ -85,6 +162,15 @@ llvm::Function* Arith256::getDivFunc(llvm::Type* _type) auto i0 = m_builder.CreateNUWSub(yLz, rLz, "i0"); auto shlBy0 = m_builder.CreateICmpEQ(i0, zero); auto y0 = m_builder.CreateShl(yArg, i0); + if (_type == m_builder.getIntNTy(512)) // Workaround for shl bug for long shifts + { + const auto treshold = m_builder.getIntN(512, 128); + auto highShift = m_builder.CreateICmpUGT(i0, treshold); + auto s = m_builder.CreateNUWSub(i0, treshold); + auto yhs = m_builder.CreateShl(yArg, treshold); + yhs = m_builder.CreateShl(yhs, s); + y0 = m_builder.CreateSelect(highShift, yhs, y0); + } y0 = m_builder.CreateSelect(shlBy0, yArg, y0, "y0"); // Workaround for LLVM bug: shl by 0 produces wrong result m_builder.CreateBr(loopBB); @@ -135,7 +221,7 @@ llvm::Function* Arith256::getExpFunc() if (!m_exp) { llvm::Type* argTypes[] = {Type::Word, Type::Word}; - m_exp = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "arith.exp", getModule()); + m_exp = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "exp", getModule()); auto base = &m_exp->getArgumentList().front(); base->setName("base"); @@ -159,9 +245,6 @@ llvm::Function* Arith256::getExpFunc() auto returnBB = llvm::BasicBlock::Create(m_builder.getContext(), "Return", m_exp); m_builder.SetInsertPoint(entryBB); - auto a1 = m_builder.CreateAlloca(Type::Word, nullptr, "a1"); - auto a2 = m_builder.CreateAlloca(Type::Word, nullptr, "a2"); - auto a3 = m_builder.CreateAlloca(Type::Word, nullptr, "a3"); m_builder.CreateBr(headerBB); m_builder.SetInsertPoint(headerBB); @@ -176,20 +259,14 @@ llvm::Function* Arith256::getExpFunc() m_builder.CreateCondBr(eOdd, updateBB, continueBB); m_builder.SetInsertPoint(updateBB); - m_builder.CreateStore(r, a1); - m_builder.CreateStore(b, a2); - createCall(m_mul, {a1, a2, a3}); - auto r0 = m_builder.CreateLoad(a3, "r0"); + auto r0 = createCall(getMulFunc(), {r, b}); m_builder.CreateBr(continueBB); m_builder.SetInsertPoint(continueBB); auto r1 = m_builder.CreatePHI(Type::Word, 2, "r1"); r1->addIncoming(r, bodyBB); r1->addIncoming(r0, updateBB); - m_builder.CreateStore(b, a1); - m_builder.CreateStore(b, a2); - createCall(m_mul, {a1, a2, a3}); - auto b1 = m_builder.CreateLoad(a3, "b1"); + auto b1 = createCall(getMulFunc(), {b, b}); auto e1 = m_builder.CreateLShr(e, Constant::get(1), "e1"); m_builder.CreateBr(headerBB); @@ -244,9 +321,6 @@ llvm::Function* Arith256::getMulModFunc() m_mulmod = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "mulmod", getModule()); auto i512Ty = m_builder.getIntNTy(512); - llvm::Type* mul512ArgTypes[] = {Type::WordPtr, Type::WordPtr, i512Ty->getPointerTo()}; - auto mul512 = llvm::Function::Create(llvm::FunctionType::get(Type::Void, mul512ArgTypes, false), llvm::Function::ExternalLinkage, "arith_mul512", getModule()); - auto x = &m_mulmod->getArgumentList().front(); x->setName("x"); auto y = x->getNextNode(); @@ -258,32 +332,19 @@ llvm::Function* Arith256::getMulModFunc() auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), {}, m_mulmod); m_builder.SetInsertPoint(entryBB); - auto a1 = m_builder.CreateAlloca(Type::Word); - auto a2 = m_builder.CreateAlloca(Type::Word); - auto a3 = m_builder.CreateAlloca(i512Ty); - m_builder.CreateStore(x, a1); - m_builder.CreateStore(y, a2); - createCall(mul512, {a1, a2, a3}); - auto p = m_builder.CreateLoad(a3, "p"); + auto p = createCall(getMul512Func(), {x, y}); auto m = m_builder.CreateZExt(mod, i512Ty, "m"); auto d = createCall(getDivFunc(i512Ty), {p, m}); auto r = m_builder.CreateExtractValue(d, 1, "r"); - m_builder.CreateRet(m_builder.CreateTrunc(r, Type::Word)); + r = m_builder.CreateTrunc(r, Type::Word); + m_builder.CreateRet(r); } return m_mulmod; } -llvm::Value* Arith256::binaryOp(llvm::Function* _op, llvm::Value* _arg1, llvm::Value* _arg2) -{ - m_builder.CreateStore(_arg1, m_arg1); - m_builder.CreateStore(_arg2, m_arg2); - m_builder.CreateCall3(_op, m_arg1, m_arg2, m_result); - return m_builder.CreateLoad(m_result); -} - llvm::Value* Arith256::mul(llvm::Value* _arg1, llvm::Value* _arg2) { - return binaryOp(m_mul, _arg1, _arg2); + return createCall(getMulFunc(), {_arg1, _arg2}); } std::pair Arith256::div(llvm::Value* _arg1, llvm::Value* _arg2) @@ -331,157 +392,6 @@ llvm::Value* Arith256::mulmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Valu return createCall(getMulModFunc(), {_arg1, _arg2, _arg3}); } -namespace -{ -#ifdef __SIZEOF_INT128__ - using uint128 = __uint128_t; -#else - struct uint128 - { - uint64_t lo = 0; - uint64_t hi = 0; - - uint128(uint64_t lo) : lo(lo) {} - - uint128 operator+(uint128 a) - { - uint128 r = 0; - bool overflow = lo > std::numeric_limits::max() - a.lo; - r.lo = lo + a.lo; - r.hi = hi + a.hi + overflow; - return r; - } - - uint128 operator>>(int s) - { - assert(s == 64); - return hi; - } - - uint128 operator<<(int s) - { - assert(s == 64); - uint128 r = 0; - r.hi = lo; - return r; - } - - explicit operator uint64_t() { return lo; } - - static uint128 mul(uint64_t a, uint64_t b) - { - auto x_lo = 0xFFFFFFFF & a; - auto y_lo = 0xFFFFFFFF & b; - auto x_hi = a >> 32; - auto y_hi = b >> 32; - - auto t1 = x_lo * y_lo; - auto t2 = x_lo * y_hi; - auto t3 = x_hi * y_lo; - auto t4 = x_hi * y_hi; - - auto lo = (uint32_t)t1; - auto mid = (uint64_t)(t1 >> 32) + (uint32_t)t2 + (uint32_t)t3; - auto hi = (uint64_t)(t2 >> 32) + (t3 >> 32) + t4 + (mid >> 32); - - uint128 r = 0; - r.lo = (uint64_t)lo + (mid << 32); - r.hi = hi; - return r; - } - - uint128 operator*(uint128 a) - { - auto t1 = mul(lo, a.lo); - auto t2 = mul(lo, a.hi); - auto t3 = mul(hi, a.lo); - return t1 + (t2 << 64) + (t3 << 64); - } - }; -#endif - - struct uint256 - { - uint64_t lo = 0; - uint64_t mid = 0; - uint128 hi = 0; - - uint256(uint64_t lo, uint64_t mid, uint128 hi): lo(lo), mid(mid), hi(hi) {} - uint256(uint128 n) - { - lo = (uint64_t) n; - mid = (uint64_t) (n >> 64); - } - - explicit operator uint128() - { - uint128 r = lo; - r |= ((uint128) mid) << 64; - return r; - } - - uint256 operator+(uint256 a) - { - auto _lo = (uint128) lo + a.lo; - auto _mid = (uint128) mid + a.mid + (_lo >> 64); - auto _hi = hi + a.hi + (_mid >> 64); - return {(uint64_t)_lo, (uint64_t)_mid, _hi}; - } - - uint256 lo2hi() - { - hi = (uint128)*this; - lo = 0; - mid = 0; - return *this; - } - }; - - struct uint512 - { - uint128 lo; - uint128 mid; - uint256 hi; - }; - - uint256 mul(uint256 x, uint256 y) - { - auto t1 = (uint128) x.lo * y.lo; - auto t2 = (uint128) x.lo * y.mid; - auto t3 = (uint128) x.lo * y.hi; - auto t4 = (uint128) x.mid * y.lo; - auto t5 = (uint128) x.mid * y.mid; - auto t6 = (uint128) x.mid * y.hi; - auto t7 = x.hi * y.lo; - auto t8 = x.hi * y.mid; - - auto lo = (uint64_t) t1; - auto m1 = (t1 >> 64) + (uint64_t) t2; - auto m2 = (uint64_t) m1; - auto mid = (uint128) m2 + (uint64_t) t4; - auto hi = (t2 >> 64) + t3 + (t4 >> 64) + t5 + (t6 << 64) + t7 - + (t8 << 64) + (m1 >> 64) + (mid >> 64); - - return {lo, (uint64_t)mid, hi}; - } - - uint512 mul512(uint256 x, uint256 y) - { - auto x_lo = (uint128) x; - auto y_lo = (uint128) y; - - auto t1 = mul(x_lo, y_lo); - auto t2 = mul(x_lo, y.hi); - auto t3 = mul(x.hi, y_lo); - auto t4 = mul(x.hi, y.hi); - - auto lo = (uint128) t1; - auto mid = (uint256) t1.hi + (uint128) t2 + (uint128) t3; - auto hi = (uint256)t2.hi + t3.hi + t4 + mid.hi; - - return {lo, (uint128)mid, hi}; - } -} } } @@ -489,20 +399,9 @@ namespace extern "C" { - using namespace dev::eth::jit; - EXPORT void debug(uint64_t a, uint64_t b, uint64_t c, uint64_t d, char z) { - std::cerr << "DEBUG " << z << ": " << d << c << b << a << std::endl; - } - - EXPORT void arith_mul(uint256* _arg1, uint256* _arg2, uint256* o_result) - { - *o_result = mul(*_arg1, *_arg2); - } - - EXPORT void arith_mul512(uint256* _arg1, uint256* _arg2, uint512* o_result) - { - *o_result = mul512(*_arg1, *_arg2); + DLOG(JIT) << "DEBUG " << std::dec << z << ": " //<< d << c << b << a + << " [" << std::hex << std::setfill('0') << std::setw(16) << d << std::setw(16) << c << std::setw(16) << b << std::setw(16) << a << "]\n"; } } diff --git a/libevmjit/Arith256.h b/libevmjit/Arith256.h index 5852137f8..2513ca568 100644 --- a/libevmjit/Arith256.h +++ b/libevmjit/Arith256.h @@ -24,26 +24,21 @@ public: void debug(llvm::Value* _value, char _c); private: + llvm::Function* getMulFunc(); + llvm::Function* getMul512Func(); llvm::Function* getDivFunc(llvm::Type* _type); llvm::Function* getExpFunc(); llvm::Function* getAddModFunc(); llvm::Function* getMulModFunc(); - llvm::Value* binaryOp(llvm::Function* _op, llvm::Value* _arg1, llvm::Value* _arg2); - - llvm::Function* m_mul; - + llvm::Function* m_mul = nullptr; + llvm::Function* m_mul512 = nullptr; llvm::Function* m_div = nullptr; llvm::Function* m_div512 = nullptr; llvm::Function* m_exp = nullptr; llvm::Function* m_addmod = nullptr; llvm::Function* m_mulmod = nullptr; llvm::Function* m_debug = nullptr; - - llvm::Value* m_arg1; - llvm::Value* m_arg2; - llvm::Value* m_arg3; - llvm::Value* m_result; }; diff --git a/libevmjit/BasicBlock.cpp b/libevmjit/BasicBlock.cpp index 5868c0f43..3338db23d 100644 --- a/libevmjit/BasicBlock.cpp +++ b/libevmjit/BasicBlock.cpp @@ -1,15 +1,17 @@ - #include "BasicBlock.h" #include +#include "preprocessor/llvm_includes_start.h" #include #include #include #include #include +#include "preprocessor/llvm_includes_end.h" #include "Type.h" +#include "Utils.h" namespace dev { @@ -18,13 +20,14 @@ namespace eth namespace jit { -const char* BasicBlock::NamePrefix = "Instr."; +static const char* jumpDestName = "JmpDst."; +static const char* basicBlockName = "Instr."; -BasicBlock::BasicBlock(bytes::const_iterator _begin, bytes::const_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest) : +BasicBlock::BasicBlock(instr_idx _firstInstrIdx, code_iterator _begin, code_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest) : + m_firstInstrIdx{_firstInstrIdx}, m_begin(_begin), m_end(_end), - // TODO: Add begin index to name - m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), NamePrefix, _mainFunc)), + m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), {isJumpDest ? jumpDestName : basicBlockName, std::to_string(_firstInstrIdx)}, _mainFunc)), m_stack(*this), m_builder(_builder), m_isJumpDest(isJumpDest) @@ -43,6 +46,7 @@ BasicBlock::LocalStack::LocalStack(BasicBlock& _owner) : void BasicBlock::LocalStack::push(llvm::Value* _value) { + assert(_value->getType() == Type::Word); m_bblock.m_currentStack.push_back(_value); m_bblock.m_tosOffset += 1; } @@ -139,7 +143,7 @@ void BasicBlock::synchronizeLocalStack(Stack& _evmStack) auto endIter = m_currentStack.end(); // Update (emit set()) changed values - for (int idx = m_currentStack.size() - 1 - m_tosOffset; + for (int idx = (int)m_currentStack.size() - 1 - m_tosOffset; currIter < endIter && idx >= 0; ++currIter, --idx) { @@ -239,13 +243,12 @@ void BasicBlock::linkLocalStacks(std::vector basicBlocks, llvm::IRB bool valuesChanged = true; while (valuesChanged) { - if (getenv("EVMCC_DEBUG_BLOCKS")) + for (auto& pair : cfg) { - for (auto& pair : cfg) - std::cerr << pair.second.bblock.llvm()->getName().str() - << ": in " << pair.second.inputItems - << ", out " << pair.second.outputItems - << "\n"; + DLOG(bb) << pair.second.bblock.llvm()->getName().str() + << ": in " << pair.second.inputItems + << ", out " << pair.second.outputItems + << "\n"; } valuesChanged = false; @@ -306,7 +309,7 @@ void BasicBlock::linkLocalStacks(std::vector basicBlocks, llvm::IRB auto& initialStack = bblock.m_initialStack; initialStack.erase(initialStack.begin(), initialStack.begin() + info.inputItems); // Initial stack shrinks, so the size difference grows: - bblock.m_tosOffset += info.inputItems; + bblock.m_tosOffset += (int)info.inputItems; } // We must account for the items that were pushed directly to successor @@ -319,7 +322,7 @@ void BasicBlock::linkLocalStacks(std::vector basicBlocks, llvm::IRB auto& exitStack = bblock.m_currentStack; exitStack.erase(exitStack.end() - info.outputItems, exitStack.end()); - bblock.m_tosOffset -= info.outputItems; + bblock.m_tosOffset -= (int)info.outputItems; // FIXME: Fix types } } @@ -337,6 +340,8 @@ void BasicBlock::dump(std::ostream& _out, bool _dotOutput) { if (val == nullptr) out << " ?"; + else if (llvm::isa(val)) + out << " " << val->getName(); else if (llvm::isa(val)) out << *val; else @@ -346,8 +351,8 @@ void BasicBlock::dump(std::ostream& _out, bool _dotOutput) } out << (_dotOutput ? "| " : "Instructions:\n"); - for (auto ins = m_llvmBB->begin(); ins != m_llvmBB->end(); ++ins) - out << *ins << (_dotOutput ? "\\l" : "\n"); + //for (auto ins = m_llvmBB->begin(); ins != m_llvmBB->end(); ++ins) + // out << *ins << (_dotOutput ? "\\l" : "\n"); if (! _dotOutput) out << "Current stack (offset = " << m_tosOffset << "):\n"; @@ -358,6 +363,8 @@ void BasicBlock::dump(std::ostream& _out, bool _dotOutput) { if (*val == nullptr) out << " ?"; + else if (llvm::isa(*val)) + out << " " << (*val)->getName(); else if (llvm::isa(*val)) out << **val; else diff --git a/libevmjit/BasicBlock.h b/libevmjit/BasicBlock.h index cda4f89bd..7469b7b69 100644 --- a/libevmjit/BasicBlock.h +++ b/libevmjit/BasicBlock.h @@ -1,6 +1,7 @@ #pragma once + #include -#include + #include "Common.h" #include "Stack.h" @@ -11,7 +12,7 @@ namespace eth namespace jit { -using ProgramCounter = uint64_t; // TODO: Rename +using instr_idx = uint64_t; class BasicBlock { @@ -50,10 +51,7 @@ public: BasicBlock& m_bblock; }; - /// Basic block name prefix. The rest is instruction index. - static const char* NamePrefix; - - explicit BasicBlock(bytes::const_iterator _begin, bytes::const_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest); + explicit BasicBlock(instr_idx _firstInstrIdx, code_iterator _begin, code_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest); explicit BasicBlock(std::string _name, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest); BasicBlock(const BasicBlock&) = delete; @@ -61,8 +59,9 @@ public: llvm::BasicBlock* llvm() { return m_llvmBB; } - bytes::const_iterator begin() { return m_begin; } - bytes::const_iterator end() { return m_end; } + instr_idx firstInstrIdx() const { return m_firstInstrIdx; } + code_iterator begin() const { return m_begin; } + code_iterator end() const { return m_end; } bool isJumpDest() const { return m_isJumpDest; } @@ -84,8 +83,9 @@ public: void dump(std::ostream& os, bool _dotOutput = false); private: - bytes::const_iterator const m_begin; - bytes::const_iterator const m_end; + instr_idx const m_firstInstrIdx = 0; ///< Code index of first instruction in the block + code_iterator const m_begin = {}; ///< Iterator pointing code beginning of the block + code_iterator const m_end = {}; ///< Iterator pointing code end of the block llvm::BasicBlock* const m_llvmBB; diff --git a/libevmjit/BuildInfo.h.in b/libevmjit/BuildInfo.h.in new file mode 100644 index 000000000..204b4d89b --- /dev/null +++ b/libevmjit/BuildInfo.h.in @@ -0,0 +1,10 @@ + +#define EVMJIT_VERSION "${EVMJIT_VERSION}" +#define EVMJIT_VERSION_MAJOR ${EVMJIT_VERSION_MAJOR} +#define EVMJIT_VERSION_MINOR ${EVMJIT_VERSION_MINOR} +#define EVMJIT_VERSION_PATCH ${EVMJIT_VERSION_PATCH} +#define EVMJIT_VERSION_PRERELEASE "${EVMJIT_VERSION_PRERELEASE}" +#define EVMJIT_VERSION_FULL "${EVMJIT_VERSION_FULL}" + +#define LLVM_VERSION "${LLVM_PACKAGE_VERSION}" +#define LLVM_ASSERTIONS "${LLVM_ENABLE_ASSERTIONS}" diff --git a/libevmjit/CMakeLists.txt b/libevmjit/CMakeLists.txt index 545e55344..943c64e42 100644 --- a/libevmjit/CMakeLists.txt +++ b/libevmjit/CMakeLists.txt @@ -6,30 +6,63 @@ set(INTERFACE_HEADERS interface.h) source_group("" FILES ${HEADERS}) source_group("" FILES ${SOURCES}) -if (NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") - # Disable rtti for Cache as LLVM has no rtti - set_source_files_properties(Cache.cpp PROPERTIES COMPILE_FLAGS -fno-rtti) +if(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC") +else() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") endif() -find_package(Git) -if(GIT_FOUND) - execute_process(COMMAND ${GIT_EXECUTABLE} -C ${CMAKE_CURRENT_SOURCE_DIR} describe --dirty --always - OUTPUT_VARIABLE EVMJIT_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) + +set(EVMJIT_VERSION "0.0.0") +set(EVMJIT_VERSION_MAJOR 0) +set(EVMJIT_VERSION_MINOR 0) +set(EVMJIT_VERSION_PATCH 0) +set(EVMJIT_VERSION_FULL "v0.0.0-nogit") + +find_package(Git) +if(GIT_FOUND) + execute_process(COMMAND ${GIT_EXECUTABLE} -C ${CMAKE_CURRENT_SOURCE_DIR} describe --dirty --always --match v* + OUTPUT_VARIABLE EVMJIT_VERSION_FULL OUTPUT_STRIP_TRAILING_WHITESPACE) +endif() + +if(${EVMJIT_VERSION_FULL} MATCHES "^v[0-9]+\\.[0-9]+") + string(SUBSTRING ${EVMJIT_VERSION_FULL} 1 -1 EVMJIT_VERSION_FULL) # skip "v" + string(REPLACE "-" ";" VERSION_COMPONENTS ${EVMJIT_VERSION_FULL}) + list(LENGTH VERSION_COMPONENTS NUM_VERSION_COMPONENTS) + list(GET VERSION_COMPONENTS 0 EVMJIT_VERSION) + string(REPLACE "." ";" VERSION_NUMBERS ${EVMJIT_VERSION}) + list(LENGTH VERSION_NUMBERS NUM_VERSION_NUMBERS) + list(GET VERSION_NUMBERS 0 EVMJIT_VERSION_MAJOR) + list(GET VERSION_NUMBERS 1 EVMJIT_VERSION_MINOR) + if(${NUM_VERSION_NUMBERS} GREATER 2) + list(GET VERSION_NUMBERS 2 EVMJIT_VERSION_PATCH) # patch number is optional + endif() + if(${NUM_VERSION_COMPONENTS} GREATER 1) + list(GET VERSION_COMPONENTS 1 VERSION_PRERELEASE_CANDIDATE) + string(REGEX MATCH "^[a-zA-Z]+.*" EVMJIT_VERSION_PRERELEASE ${VERSION_PRERELEASE_CANDIDATE}) # prerelease starts with letter + endif() endif() -if(NOT EVMJIT_VERSION) - set(EVMJIT_VERSION "unknown") + +if(${EVMJIT_VERSION_MAJOR} EQUAL 0) + set(EVMJIT_SOVERSION "0.${EVMJIT_VERSION_MINOR}") +else() + set(EVMJIT_SOVERSION ${EVMJIT_VERSION_MAJOR}) endif() -message("EVM JIT version: ${EVMJIT_VERSION}") +configure_file(BuildInfo.h.in ${CMAKE_CURRENT_BINARY_DIR}/gen/BuildInfo.gen.h) + +message(STATUS "EVM JIT version: ${EVMJIT_VERSION_MAJOR}.${EVMJIT_VERSION_MINOR}.${EVMJIT_VERSION_PATCH} ${EVMJIT_VERSION_PRERELEASE} (${EVMJIT_VERSION_FULL})") -add_library(${TARGET_NAME} SHARED ${SOURCES} ${HEADERS}) -set_target_properties(${TARGET_NAME} PROPERTIES VERSION ${EVMJIT_VERSION} FOLDER "libs") +add_library(${TARGET_NAME} SHARED ${SOURCES} ${HEADERS} gen/BuildInfo.gen.h) +set_target_properties(${TARGET_NAME} PROPERTIES + VERSION ${EVMJIT_VERSION} SOVERSION ${EVMJIT_SOVERSION} + FOLDER "libs") include_directories(${LLVM_INCLUDE_DIRS}) +include_directories(${CMAKE_CURRENT_BINARY_DIR}/gen) target_link_libraries(${TARGET_NAME} PRIVATE ${LLVM_LIBS}) #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") install(TARGETS ${TARGET_NAME} LIBRARY DESTINATION lib ARCHIVE DESTINATION lib RUNTIME DESTINATION bin) -#install(FILES ${INTERFACE_HEADERS} DESTINATION include/${TARGET_NAME}) +#install(FILES ${INTERFACE_HEADERS} DESTINATION include/${TARGET_NAME}) \ No newline at end of file diff --git a/libevmjit/Cache.cpp b/libevmjit/Cache.cpp index 0e6fb517a..4dbcd281d 100644 --- a/libevmjit/Cache.cpp +++ b/libevmjit/Cache.cpp @@ -1,12 +1,16 @@ #include "Cache.h" -#include -#include -#include + +#include "preprocessor/llvm_includes_start.h" #include #include +#include #include #include #include +#include "preprocessor/llvm_includes_end.h" + +#include "ExecutionEngine.h" +#include "Utils.h" namespace dev { @@ -15,23 +19,28 @@ namespace eth namespace jit { -//#define LOG(...) std::cerr << "CACHE " -#define LOG(...) std::ostream(nullptr) - -ObjectCache* Cache::getObjectCache() +namespace { - static ObjectCache objectCache; - return &objectCache; + llvm::MemoryBuffer* g_lastObject; + ExecutionEngineListener* g_listener; } -namespace +ObjectCache* Cache::getObjectCache(ExecutionEngineListener* _listener) { - llvm::MemoryBuffer* lastObject; + static ObjectCache objectCache; + g_listener = _listener; + return &objectCache; } std::unique_ptr Cache::getObject(std::string const& id) { - assert(!lastObject); + if (g_listener) + g_listener->stateChanged(ExecState::CacheLoad); + + DLOG(cache) << id << ": search\n"; + if (!CHECK(!g_lastObject)) + g_lastObject = nullptr; + llvm::SmallString<256> cachePath; llvm::sys::path::system_temp_directory(false, cachePath); llvm::sys::path::append(cachePath, "evm_objs", id); @@ -51,22 +60,31 @@ std::unique_ptr Cache::getObject(std::string const& id) #endif if (auto r = llvm::MemoryBuffer::getFile(cachePath.str(), -1, false)) - lastObject = llvm::MemoryBuffer::getMemBufferCopy(r.get()->getBuffer()); + g_lastObject = llvm::MemoryBuffer::getMemBufferCopy(r.get()->getBuffer()); else if (r.getError() != std::make_error_code(std::errc::no_such_file_or_directory)) std::cerr << r.getError().message(); // TODO: Add log - if (lastObject) // if object found create fake module + if (g_lastObject) // if object found create fake module { - auto module = std::unique_ptr(new llvm::Module(id, llvm::getGlobalContext())); - auto mainFuncType = llvm::FunctionType::get(llvm::IntegerType::get(llvm::getGlobalContext(), 32), {}, false); - llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, id, module.get()); + DLOG(cache) << id << ": found\n"; + auto&& context = llvm::getGlobalContext(); + auto module = std::unique_ptr(new llvm::Module(id, context)); + auto mainFuncType = llvm::FunctionType::get(llvm::Type::getVoidTy(context), {}, false); + auto mainFunc = llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, id, module.get()); + auto bb = llvm::BasicBlock::Create(context, {}, mainFunc); + bb->getInstList().push_back(new llvm::UnreachableInst{context}); + return module; } + DLOG(cache) << id << ": not found\n"; return nullptr; } void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::MemoryBuffer const* _object) { + if (g_listener) + g_listener->stateChanged(ExecState::CacheWrite); + auto&& id = _module->getModuleIdentifier(); llvm::SmallString<256> cachePath; llvm::sys::path::system_temp_directory(false, cachePath); @@ -77,15 +95,17 @@ void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::Memory llvm::sys::path::append(cachePath, id); + DLOG(cache) << id << ": write\n"; std::string error; llvm::raw_fd_ostream cacheFile(cachePath.c_str(), error, llvm::sys::fs::F_None); cacheFile << _object->getBuffer(); } -llvm::MemoryBuffer* ObjectCache::getObject(llvm::Module const*) +llvm::MemoryBuffer* ObjectCache::getObject(llvm::Module const* _module) { - auto o = lastObject; - lastObject = nullptr; + DLOG(cache) << _module->getModuleIdentifier() << ": use\n"; + auto o = g_lastObject; + g_lastObject = nullptr; return o; } diff --git a/libevmjit/Cache.h b/libevmjit/Cache.h index 1cad537cd..e8f01d38d 100644 --- a/libevmjit/Cache.h +++ b/libevmjit/Cache.h @@ -1,9 +1,8 @@ #pragma once #include -#include -#include +#include namespace dev { @@ -11,6 +10,7 @@ namespace eth { namespace jit { +class ExecutionEngineListener; class ObjectCache : public llvm::ObjectCache { @@ -23,16 +23,13 @@ public: /// not available. The caller owns both the MemoryBuffer returned by this /// and the memory it references. virtual llvm::MemoryBuffer* getObject(llvm::Module const* _module) final override; - -private: - std::unordered_map> m_map; }; class Cache { public: - static ObjectCache* getObjectCache(); + static ObjectCache* getObjectCache(ExecutionEngineListener* _listener); static std::unique_ptr getObject(std::string const& id); }; diff --git a/libevmjit/Common.h b/libevmjit/Common.h index d629f25ad..cd0523b12 100644 --- a/libevmjit/Common.h +++ b/libevmjit/Common.h @@ -20,25 +20,28 @@ namespace jit using byte = uint8_t; using bytes = std::vector; using bytes_ref = std::tuple; - -struct NoteChannel {}; // FIXME: Use some log library? +using code_iterator = byte const*; enum class ReturnCode { - Stop = 0, - Return = 1, + // Success codes + Stop = 0, + Return = 1, Suicide = 2, - OutOfGas = -1, - BadJumpDestination = -2, - StackTooSmall = -3, - BadInstruction = -4, + // Standard error codes + OutOfGas = -1, + StackTooSmall = -2, + BadJumpDestination = -3, + BadInstruction = -4, + Rejected = -5, ///< Input data (code, gas, block info, etc.) does not meet JIT requirement and execution request has been rejected - LLVMConfigError = -5, - LLVMCompileError = -6, - LLVMLinkError = -7, + // Internal error codes + LLVMConfigError = -101, + LLVMCompileError = -102, + LLVMLinkError = -103, - UnexpectedException = -8, + UnexpectedException = -111, LinkerWorkaround = -299, }; diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index ad8a14fc7..8e8641ea3 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -1,4 +1,3 @@ - #include "Compiler.h" #include @@ -6,13 +5,12 @@ #include #include -#include +#include "preprocessor/llvm_includes_start.h" #include #include #include - -#include -#include +#include +#include "preprocessor/llvm_includes_end.h" #include "Instruction.h" #include "Type.h" @@ -39,10 +37,10 @@ Compiler::Compiler(Options const& _options): Type::init(m_builder.getContext()); } -void Compiler::createBasicBlocks(bytes const& _bytecode) +void Compiler::createBasicBlocks(code_iterator _codeBegin, code_iterator _codeEnd) { /// Helper function that skips push data and finds next iterator (can be the end) - auto skipPushDataAndGetNext = [](bytes::const_iterator _curr, bytes::const_iterator _end) + auto skipPushDataAndGetNext = [](code_iterator _curr, code_iterator _end) { static const auto push1 = static_cast(Instruction::PUSH1); static const auto push32 = static_cast(Instruction::PUSH32); @@ -52,11 +50,11 @@ void Compiler::createBasicBlocks(bytes const& _bytecode) return _curr + offset; }; - auto begin = _bytecode.begin(); + auto begin = _codeBegin; // begin of current block bool nextJumpDest = false; - for (auto curr = begin, next = begin; curr != _bytecode.end(); curr = next) + for (auto curr = begin, next = begin; curr != _codeEnd; curr = next) { - next = skipPushDataAndGetNext(curr, _bytecode.end()); + next = skipPushDataAndGetNext(curr, _codeEnd); bool isEnd = false; switch (Instruction(*curr)) @@ -77,25 +75,22 @@ void Compiler::createBasicBlocks(bytes const& _bytecode) break; } - assert(next <= _bytecode.end()); - if (next == _bytecode.end() || Instruction(*next) == Instruction::JUMPDEST) + assert(next <= _codeEnd); + if (next == _codeEnd || Instruction(*next) == Instruction::JUMPDEST) isEnd = true; if (isEnd) { - auto beginIdx = begin - _bytecode.begin(); + auto beginIdx = begin - _codeBegin; m_basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginIdx), - std::forward_as_tuple(begin, next, m_mainFunc, m_builder, nextJumpDest)); + std::forward_as_tuple(beginIdx, begin, next, m_mainFunc, m_builder, nextJumpDest)); nextJumpDest = false; begin = next; } } - - // TODO: Create Stop basic block on demand - m_stopBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Stop", m_mainFunc); } -llvm::BasicBlock* Compiler::getJumpTableBlock() +llvm::BasicBlock* Compiler::getJumpTableBlock(RuntimeManager& _runtimeManager) { if (!m_jumpTableBlock) { @@ -103,7 +98,7 @@ llvm::BasicBlock* Compiler::getJumpTableBlock() InsertPointGuard g{m_builder}; m_builder.SetInsertPoint(m_jumpTableBlock->llvm()); auto dest = m_builder.CreatePHI(Type::Word, 8, "target"); - auto switchInstr = m_builder.CreateSwitch(dest, getBadJumpBlock()); + auto switchInstr = m_builder.CreateSwitch(dest, getBadJumpBlock(_runtimeManager)); for (auto&& p : m_basicBlocks) { if (p.second.isJumpDest()) @@ -113,21 +108,20 @@ llvm::BasicBlock* Compiler::getJumpTableBlock() return m_jumpTableBlock->llvm(); } -llvm::BasicBlock* Compiler::getBadJumpBlock() +llvm::BasicBlock* Compiler::getBadJumpBlock(RuntimeManager& _runtimeManager) { if (!m_badJumpBlock) { m_badJumpBlock.reset(new BasicBlock("BadJump", m_mainFunc, m_builder, true)); InsertPointGuard g{m_builder}; m_builder.SetInsertPoint(m_badJumpBlock->llvm()); - m_builder.CreateRet(Constant::get(ReturnCode::BadJumpDestination)); + _runtimeManager.exit(ReturnCode::BadJumpDestination); } return m_badJumpBlock->llvm(); } -std::unique_ptr Compiler::compile(bytes const& _bytecode, std::string const& _id) +std::unique_ptr Compiler::compile(code_iterator _begin, code_iterator _end, std::string const& _id) { - auto compilationStartTime = std::chrono::high_resolution_clock::now(); auto module = std::unique_ptr(new llvm::Module(_id, m_builder.getContext())); // Create main function @@ -135,21 +129,41 @@ std::unique_ptr Compiler::compile(bytes const& _bytecode, std::str m_mainFunc = llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, _id, module.get()); m_mainFunc->getArgumentList().front().setName("rt"); - // Create the basic blocks. - auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), "entry", m_mainFunc); + // Create entry basic block + auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), {}, m_mainFunc); m_builder.SetInsertPoint(entryBlock); - createBasicBlocks(_bytecode); + auto jmpBufWords = m_builder.CreateAlloca(Type::BytePtr, m_builder.getInt64(3), "jmpBuf.words"); + auto frameaddress = llvm::Intrinsic::getDeclaration(module.get(), llvm::Intrinsic::frameaddress); + auto fp = m_builder.CreateCall(frameaddress, m_builder.getInt32(0), "fp"); + m_builder.CreateStore(fp, jmpBufWords); + auto stacksave = llvm::Intrinsic::getDeclaration(module.get(), llvm::Intrinsic::stacksave); + auto sp = m_builder.CreateCall(stacksave, "sp"); + auto jmpBufSp = m_builder.CreateConstInBoundsGEP1_64(jmpBufWords, 2, "jmpBuf.sp"); + m_builder.CreateStore(sp, jmpBufSp); + auto setjmp = llvm::Intrinsic::getDeclaration(module.get(), llvm::Intrinsic::eh_sjlj_setjmp); + auto jmpBuf = m_builder.CreateBitCast(jmpBufWords, Type::BytePtr, "jmpBuf"); + auto r = m_builder.CreateCall(setjmp, jmpBuf); + auto normalFlow = m_builder.CreateICmpEQ(r, m_builder.getInt32(0)); + + createBasicBlocks(_begin, _end); // Init runtime structures. - RuntimeManager runtimeManager(m_builder); + RuntimeManager runtimeManager(m_builder, jmpBuf, _begin, _end); GasMeter gasMeter(m_builder, runtimeManager); Memory memory(runtimeManager, gasMeter); Ext ext(runtimeManager, memory); Stack stack(m_builder, runtimeManager); + runtimeManager.setStack(stack); // Runtime Manager will free stack memory Arith256 arith(m_builder); - m_builder.CreateBr(m_basicBlocks.empty() ? m_stopBB : m_basicBlocks.begin()->second.llvm()); + // TODO: Create Stop basic block on demand + m_stopBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Stop", m_mainFunc); + auto abortBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Abort", m_mainFunc); + + auto firstBB = m_basicBlocks.empty() ? m_stopBB : m_basicBlocks.begin()->second.llvm(); + auto expectTrue = llvm::MDBuilder{m_builder.getContext()}.createBranchWeights(1, 0); + m_builder.CreateCondBr(normalFlow, firstBB, abortBB, expectTrue); for (auto basicBlockPairIt = m_basicBlocks.begin(); basicBlockPairIt != m_basicBlocks.end(); ++basicBlockPairIt) { @@ -157,13 +171,16 @@ std::unique_ptr Compiler::compile(bytes const& _bytecode, std::str auto iterCopy = basicBlockPairIt; ++iterCopy; auto nextBasicBlock = (iterCopy != m_basicBlocks.end()) ? iterCopy->second.llvm() : nullptr; - compileBasicBlock(basicBlock, _bytecode, runtimeManager, arith, memory, ext, gasMeter, nextBasicBlock); + compileBasicBlock(basicBlock, runtimeManager, arith, memory, ext, gasMeter, nextBasicBlock); } // Code for special blocks: // TODO: move to separate function. m_builder.SetInsertPoint(m_stopBB); - m_builder.CreateRet(Constant::get(ReturnCode::Stop)); + runtimeManager.exit(ReturnCode::Stop); + + m_builder.SetInsertPoint(abortBB); + runtimeManager.exit(ReturnCode::OutOfGas); removeDeadBlocks(); @@ -210,21 +227,11 @@ std::unique_ptr Compiler::compile(bytes const& _bytecode, std::str dumpCFGifRequired("blocks-sync.dot"); - if (m_jumpTableBlock && m_options.rewriteSwitchToBranches) - { - llvm::FunctionPassManager fpManager(module.get()); - fpManager.add(llvm::createLowerSwitchPass()); - fpManager.doInitialization(); - fpManager.run(*m_mainFunc); - } - - auto compilationEndTime = std::chrono::high_resolution_clock::now(); - clog(JIT) << "JIT: " << std::chrono::duration_cast(compilationEndTime - compilationStartTime).count(); return module; } -void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode, RuntimeManager& _runtimeManager, +void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runtimeManager, Arith256& _arith, Memory& _memory, Ext& _ext, GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock) { if (!_nextBasicBlock) // this is the last block in the code @@ -580,7 +587,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode auto&& c = constant->getValue(); auto targetIdx = c.getActiveBits() <= 64 ? c.getZExtValue() : -1; auto it = m_basicBlocks.find(targetIdx); - targetBlock = (it != m_basicBlocks.end() && it->second.isJumpDest()) ? it->second.llvm() : getBadJumpBlock(); + targetBlock = (it != m_basicBlocks.end() && it->second.isJumpDest()) ? it->second.llvm() : getBadJumpBlock(_runtimeManager); } // TODO: Improve; check for constants @@ -593,7 +600,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode else { _basicBlock.setJumpTarget(target); - m_builder.CreateBr(getJumpTableBlock()); + m_builder.CreateBr(getJumpTableBlock(_runtimeManager)); } } else // JUMPI @@ -609,7 +616,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode else { _basicBlock.setJumpTarget(target); - m_builder.CreateCondBr(cond, getJumpTableBlock(), _nextBasicBlock); + m_builder.CreateCondBr(cond, getJumpTableBlock(_runtimeManager), _nextBasicBlock); } } break; @@ -623,7 +630,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode case Instruction::PC: { - auto value = Constant::get(it - _bytecode.begin()); + auto value = Constant::get(it - _basicBlock.begin() + _basicBlock.firstInstrIdx()); stack.push(value); break; } @@ -631,7 +638,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode case Instruction::GAS: { _gasMeter.commitCostBlock(); - stack.push(_runtimeManager.getGas()); + stack.push(m_builder.CreateZExt(_runtimeManager.getGas(), Type::Word)); break; } @@ -741,10 +748,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode _memory.require(initOff, initSize); _gasMeter.commitCostBlock(); - - auto gas = _runtimeManager.getGas(); - auto address = _ext.create(gas, endowment, initOff, initSize); - _runtimeManager.setGas(gas); + auto address = _ext.create(endowment, initOff, initSize); stack.push(address); break; } @@ -752,7 +756,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode case Instruction::CALL: case Instruction::CALLCODE: { - auto gas = stack.pop(); + auto callGas256 = stack.pop(); auto codeAddress = stack.pop(); auto value = stack.pop(); auto inOff = stack.pop(); @@ -770,9 +774,13 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode if (inst == Instruction::CALLCODE) receiveAddress = _runtimeManager.get(RuntimeData::Address); - _gasMeter.count(gas); - auto ret = _ext.call(gas, receiveAddress, value, inOff, inSize, outOff, outSize, codeAddress); - _gasMeter.giveBack(gas); + auto gas = _runtimeManager.getGas(); + _gasMeter.count(callGas256); + auto callGas = m_builder.CreateTrunc(callGas256, Type::Gas); + auto gasLeft = m_builder.CreateNSWSub(gas, callGas); + _runtimeManager.setGas(callGas); + auto ret = _ext.call(receiveAddress, value, inOff, inSize, outOff, outSize, codeAddress); + _gasMeter.giveBack(gasLeft); stack.push(ret); break; } @@ -785,14 +793,14 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode _memory.require(index, size); _runtimeManager.registerReturnData(index, size); - m_builder.CreateRet(Constant::get(ReturnCode::Return)); + _runtimeManager.exit(ReturnCode::Return); break; } case Instruction::SUICIDE: { _runtimeManager.registerSuicide(stack.pop()); - m_builder.CreateRet(Constant::get(ReturnCode::Suicide)); + _runtimeManager.exit(ReturnCode::Suicide); break; } @@ -825,12 +833,9 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode break; } - default: // Invalid instruction - runtime exception - { - // TODO: Replace with return statement - _runtimeManager.raiseException(ReturnCode::BadInstruction); - } - + default: // Invalid instruction - abort + m_builder.CreateRet(Constant::get(ReturnCode::BadInstruction)); + it = _basicBlock.end() - 1; // finish block compilation } } diff --git a/libevmjit/Compiler.h b/libevmjit/Compiler.h index 720a48cf9..4469389bb 100644 --- a/libevmjit/Compiler.h +++ b/libevmjit/Compiler.h @@ -1,8 +1,5 @@ - #pragma once -#include - #include "Common.h" #include "BasicBlock.h" @@ -33,17 +30,17 @@ public: Compiler(Options const& _options); - std::unique_ptr compile(bytes const& _bytecode, std::string const& _id); + std::unique_ptr compile(code_iterator _begin, code_iterator _end, std::string const& _id); private: - void createBasicBlocks(bytes const& _bytecode); + void createBasicBlocks(code_iterator _begin, code_iterator _end); - void compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode, class RuntimeManager& _runtimeManager, class Arith256& _arith, class Memory& _memory, class Ext& _ext, class GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock); + void compileBasicBlock(BasicBlock& _basicBlock, class RuntimeManager& _runtimeManager, class Arith256& _arith, class Memory& _memory, class Ext& _ext, class GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock); - llvm::BasicBlock* getJumpTableBlock(); + llvm::BasicBlock* getJumpTableBlock(RuntimeManager& _runtimeManager); - llvm::BasicBlock* getBadJumpBlock(); + llvm::BasicBlock* getBadJumpBlock(RuntimeManager& _runtimeManager); void removeDeadBlocks(); diff --git a/libevmjit/CompilerHelper.cpp b/libevmjit/CompilerHelper.cpp index 9cccecd79..5c8ee8574 100644 --- a/libevmjit/CompilerHelper.cpp +++ b/libevmjit/CompilerHelper.cpp @@ -1,8 +1,8 @@ - #include "CompilerHelper.h" -#include +#include "preprocessor/llvm_includes_start.h" #include +#include "preprocessor/llvm_includes_end.h" #include "RuntimeManager.h" diff --git a/libevmjit/CompilerHelper.h b/libevmjit/CompilerHelper.h index 62733ca72..cd6d09a58 100644 --- a/libevmjit/CompilerHelper.h +++ b/libevmjit/CompilerHelper.h @@ -1,7 +1,8 @@ - #pragma once +#include "preprocessor/llvm_includes_start.h" #include +#include "preprocessor/llvm_includes_end.h" namespace dev @@ -19,7 +20,7 @@ protected: CompilerHelper(llvm::IRBuilder<>& _builder); CompilerHelper(const CompilerHelper&) = delete; - void operator=(CompilerHelper) = delete; + CompilerHelper& operator=(CompilerHelper) = delete; /// Reference to the IR module being compiled llvm::Module* getModule(); diff --git a/libevmjit/Endianness.cpp b/libevmjit/Endianness.cpp index db7edfdc9..d36f4b7fa 100644 --- a/libevmjit/Endianness.cpp +++ b/libevmjit/Endianness.cpp @@ -1,7 +1,9 @@ - #include "Endianness.h" +#include "preprocessor/llvm_includes_start.h" #include +#include +#include "preprocessor/llvm_includes_end.h" #include "Type.h" @@ -14,13 +16,7 @@ namespace jit llvm::Value* Endianness::bswapIfLE(llvm::IRBuilder<>& _builder, llvm::Value* _word) { - union tester - { - unsigned int x; - unsigned char isLE; - }; - - if (tester{1}.isLE) + if (llvm::sys::IsLittleEndianHost) { // FIXME: Disabled because of problems with BYTE //if (auto constant = llvm::dyn_cast(_word)) diff --git a/libevmjit/Endianness.h b/libevmjit/Endianness.h index 8a1f41085..19fd8fc58 100644 --- a/libevmjit/Endianness.h +++ b/libevmjit/Endianness.h @@ -1,7 +1,8 @@ - #pragma once +#include "preprocessor/llvm_includes_start.h" #include +#include "preprocessor/llvm_includes_end.h" namespace dev { diff --git a/libevmjit/ExecStats.cpp b/libevmjit/ExecStats.cpp new file mode 100644 index 000000000..ff8c05307 --- /dev/null +++ b/libevmjit/ExecStats.cpp @@ -0,0 +1,98 @@ +#include "ExecStats.h" + +#include +#include +#include + +#include "Utils.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +void ExecStats::stateChanged(ExecState _state) +{ + if (!CHECK(m_state != ExecState::Finished)) + return; + + auto now = clock::now(); + if (_state != ExecState::Started) + { + assert(time[(int)m_state] == ExecStats::duration::zero()); + time[(int)m_state] = now - m_tp; + } + m_state = _state; + m_tp = now; +} + +namespace +{ +struct StatsAgg +{ + using unit = std::chrono::microseconds; + ExecStats::duration tot = ExecStats::duration::zero(); + ExecStats::duration min = ExecStats::duration::max(); + ExecStats::duration max = ExecStats::duration::zero(); + size_t count = 0; + + void update(ExecStats::duration _d) + { + ++count; + tot += _d; + min = _d < min ? _d : min; + max = _d > max ? _d : max; + } + + void output(char const* _name, std::ostream& _os) + { + auto avg = tot / count; + _os << std::setfill(' ') + << std::setw(12) << std::left << _name + << std::setw(10) << std::right << std::chrono::duration_cast(tot).count() + << std::setw(10) << std::right << std::chrono::duration_cast(avg).count() + << std::setw(10) << std::right << std::chrono::duration_cast(min).count() + << std::setw(10) << std::right << std::chrono::duration_cast(max).count() + << std::endl; + } +}; + +char const* getExecStateName(ExecState _state) +{ + switch (_state) + { + case ExecState::Started: return "Start"; + case ExecState::CacheLoad: return "CacheLoad"; + case ExecState::CacheWrite: return "CacheWrite"; + case ExecState::Compilation: return "Compilation"; + case ExecState::Optimization: return "Optimization"; + case ExecState::CodeGen: return "CodeGen"; + case ExecState::Execution: return "Execution"; + case ExecState::Return: return "Return"; + case ExecState::Finished: return "Finish"; + } + return nullptr; +} +} + +StatsCollector::~StatsCollector() +{ + if (stats.empty()) + return; + + std::cout << " [us] total avg min max\n"; + for (int i = 0; i < (int)ExecState::Finished; ++i) + { + StatsAgg agg; + for (auto&& s : stats) + agg.update(s->time[i]); + + agg.output(getExecStateName(ExecState(i)), std::cout); + } +} + +} +} +} diff --git a/libevmjit/ExecStats.h b/libevmjit/ExecStats.h new file mode 100644 index 000000000..1ac9b6995 --- /dev/null +++ b/libevmjit/ExecStats.h @@ -0,0 +1,44 @@ +#pragma once + +#include +#include + +#include "ExecutionEngine.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +class ExecStats : public ExecutionEngineListener +{ +public: + using clock = std::chrono::high_resolution_clock; + using duration = clock::duration; + using time_point = clock::time_point; + + std::string id; + duration time[(int)ExecState::Finished] = {}; + + void stateChanged(ExecState _state) override; + +private: + ExecState m_state = {}; + time_point m_tp = {}; + +}; + + +class StatsCollector +{ +public: + std::vector> stats; + + ~StatsCollector(); +}; + +} +} +} diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 2db125c2d..dd8fb7e62 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -1,24 +1,28 @@ #include "ExecutionEngine.h" -#include -#include // env options +#include +#include +#include +#include "preprocessor/llvm_includes_start.h" #include #include -#pragma warning(push) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-parameter" #include #include -#pragma warning(pop) -#pragma GCC diagnostic pop #include #include #include +#include +#include +#include "preprocessor/llvm_includes_end.h" #include "Runtime.h" #include "Compiler.h" +#include "Optimizer.h" #include "Cache.h" +#include "ExecStats.h" +#include "Utils.h" +#include "BuildInfo.gen.h" namespace dev { @@ -29,122 +33,132 @@ namespace jit namespace { -typedef ReturnCode(*EntryFuncPtr)(Runtime*); +using EntryFuncPtr = ReturnCode(*)(Runtime*); -ReturnCode runEntryFunc(EntryFuncPtr _mainFunc, Runtime* _runtime) +std::string codeHash(i256 const& _hash) { - // That function uses long jumps to handle "execeptions". - // Do not create any non-POD objects here - - ReturnCode returnCode{}; - auto sj = setjmp(_runtime->getJmpBuf()); - if (sj == 0) - returnCode = _mainFunc(_runtime); - else - returnCode = static_cast(sj); - - return returnCode; + static const auto size = sizeof(_hash); + static const auto hexChars = "0123456789abcdef"; + std::string str; + str.resize(size * 2); + auto outIt = str.rbegin(); // reverse for BE + auto& arr = *(std::array*)&_hash; + for (auto b : arr) + { + *(outIt++) = hexChars[b & 0xf]; + *(outIt++) = hexChars[b >> 4]; + } + return str; } -std::string codeHash(bytes const& _code) +void printVersion() { - uint32_t hash = 0; - for (auto b : _code) - { - hash += b; - hash += (hash << 10); - hash ^= (hash >> 6); - } - hash += (hash << 3); - hash ^= (hash >> 11); - hash += (hash << 15); - return std::to_string(hash); + std::cout << "Ethereum EVM JIT Compiler (http://github.com/ethereum/evmjit):\n" + << " EVMJIT version " << EVMJIT_VERSION << "\n" +#ifdef NDEBUG + << " Optimized build, " EVMJIT_VERSION_FULL "\n" +#else + << " DEBUG build, " EVMJIT_VERSION_FULL "\n" +#endif + << " Built " << __DATE__ << " (" << __TIME__ << ")\n" + << std::endl; } -bool getEnvOption(char const* _name, bool _default) +namespace cl = llvm::cl; +cl::opt g_optimize{"O", cl::desc{"Optimize"}}; +cl::opt g_cache{"cache", cl::desc{"Cache compiled EVM code on disk"}, cl::init(true)}; +cl::opt g_stats{"st", cl::desc{"Statistics"}}; +cl::opt g_dump{"dump", cl::desc{"Dump LLVM IR module"}}; + +void parseOptions() { - auto var = std::getenv(_name); - if (!var) - return _default; - return std::strtol(var, nullptr, 10) != 0; + static llvm::llvm_shutdown_obj shutdownObj{}; + cl::AddExtraVersionPrinter(printVersion); + cl::ParseEnvironmentOptions("evmjit", "EVMJIT", "Ethereum EVM JIT Compiler"); } } -ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _env) + +ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) { - static std::unique_ptr ee; // TODO: Use Managed Objects from LLVM? - static auto debugDumpModule = getEnvOption("EVMJIT_DUMP", false); - static auto objectCacheEnabled = getEnvOption("EVMJIT_CACHE", true); + static std::once_flag flag; + std::call_once(flag, parseOptions); - auto mainFuncName = codeHash(_code); - EntryFuncPtr entryFuncPtr{}; - Runtime runtime(_data, _env); // TODO: I don't know why but it must be created before getFunctionAddress() calls + std::unique_ptr listener{new ExecStats}; + listener->stateChanged(ExecState::Started); + + auto objectCache = g_cache ? Cache::getObjectCache(listener.get()) : nullptr; - if (ee && (entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName))) + static std::unique_ptr ee; + if (!ee) { + llvm::InitializeNativeTarget(); + llvm::InitializeNativeTargetAsmPrinter(); + + auto module = std::unique_ptr(new llvm::Module({}, llvm::getGlobalContext())); + llvm::EngineBuilder builder(module.get()); + builder.setEngineKind(llvm::EngineKind::JIT); + builder.setUseMCJIT(true); + builder.setOptLevel(g_optimize ? llvm::CodeGenOpt::Default : llvm::CodeGenOpt::None); + + auto triple = llvm::Triple(llvm::sys::getProcessTriple()); + if (triple.getOS() == llvm::Triple::OSType::Win32) + triple.setObjectFormat(llvm::Triple::ObjectFormatType::ELF); // MCJIT does not support COFF format + module->setTargetTriple(triple.str()); + + ee.reset(builder.create()); + if (!CHECK(ee)) + return ReturnCode::LLVMConfigError; + module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module + ee->setObjectCache(objectCache); } - else + + static StatsCollector statsCollector; + + auto mainFuncName = codeHash(_data->codeHash); + Runtime runtime(_data, _env); // TODO: I don't know why but it must be created before getFunctionAddress() calls + + auto entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); + if (!entryFuncPtr) { - auto objectCache = objectCacheEnabled ? Cache::getObjectCache() : nullptr; - std::unique_ptr module; - if (objectCache) - module = Cache::getObject(mainFuncName); + auto module = objectCache ? Cache::getObject(mainFuncName) : nullptr; if (!module) - module = Compiler({}).compile(_code, mainFuncName); - if (debugDumpModule) - module->dump(); - if (!ee) { - llvm::InitializeNativeTarget(); - llvm::InitializeNativeTargetAsmPrinter(); - - llvm::EngineBuilder builder(module.get()); - builder.setEngineKind(llvm::EngineKind::JIT); - builder.setUseMCJIT(true); - std::unique_ptr memoryManager(new llvm::SectionMemoryManager); - builder.setMCJITMemoryManager(memoryManager.get()); - builder.setOptLevel(llvm::CodeGenOpt::None); - - auto triple = llvm::Triple(llvm::sys::getProcessTriple()); - if (triple.getOS() == llvm::Triple::OSType::Win32) - triple.setObjectFormat(llvm::Triple::ObjectFormatType::ELF); // MCJIT does not support COFF format - module->setTargetTriple(triple.str()); - - ee.reset(builder.create()); - if (!ee) - return ReturnCode::LLVMConfigError; - - module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module - memoryManager.release(); // and memory manager - - if (objectCache) - ee->setObjectCache(objectCache); - entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); - } - else - { - if (!entryFuncPtr) + listener->stateChanged(ExecState::Compilation); + assert(_data->code || !_data->codeSize); //TODO: Is it good idea to execute empty code? + module = Compiler{{}}.compile(_data->code, _data->code + _data->codeSize, mainFuncName); + + if (g_optimize) { - ee->addModule(module.get()); - module.release(); - entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); + listener->stateChanged(ExecState::Optimization); + optimize(*module); } } + if (g_dump) + module->dump(); + + ee->addModule(module.get()); + module.release(); + listener->stateChanged(ExecState::CodeGen); + entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); } - assert(entryFuncPtr); + if (!CHECK(entryFuncPtr)) + return ReturnCode::LLVMLinkError; - auto executionStartTime = std::chrono::high_resolution_clock::now(); + listener->stateChanged(ExecState::Execution); + auto returnCode = entryFuncPtr(&runtime); + listener->stateChanged(ExecState::Return); - auto returnCode = runEntryFunc(entryFuncPtr, &runtime); if (returnCode == ReturnCode::Return) { returnData = runtime.getReturnData(); // Save reference to return data std::swap(m_memory, runtime.getMemory()); // Take ownership of memory } + listener->stateChanged(ExecState::Finished); - auto executionEndTime = std::chrono::high_resolution_clock::now(); - clog(JIT) << " + " << std::chrono::duration_cast(executionEndTime - executionStartTime).count() << " ms\n"; + if (g_stats) + statsCollector.stats.push_back(std::move(listener)); return returnCode; } diff --git a/libevmjit/ExecutionEngine.h b/libevmjit/ExecutionEngine.h index e8d1e1c05..c0567828c 100644 --- a/libevmjit/ExecutionEngine.h +++ b/libevmjit/ExecutionEngine.h @@ -1,5 +1,7 @@ #pragma once +#include + #include "RuntimeData.h" namespace dev @@ -9,14 +11,41 @@ namespace eth namespace jit { +enum class ExecState +{ + Started, + CacheLoad, + CacheWrite, + Compilation, + Optimization, + CodeGen, + Execution, + Return, + Finished +}; + +class ExecutionEngineListener +{ +public: + ExecutionEngineListener() = default; + ExecutionEngineListener(ExecutionEngineListener const&) = delete; + ExecutionEngineListener& operator=(ExecutionEngineListener) = delete; + virtual ~ExecutionEngineListener() {} + + virtual void executionStarted() {} + virtual void executionEnded() {} + + virtual void stateChanged(ExecState) {} +}; + class ExecutionEngine { public: ExecutionEngine() = default; ExecutionEngine(ExecutionEngine const&) = delete; - void operator=(ExecutionEngine) = delete; + ExecutionEngine& operator=(ExecutionEngine) = delete; - EXPORT ReturnCode run(bytes const& _code, RuntimeData* _data, Env* _env); + EXPORT ReturnCode run(RuntimeData* _data, Env* _env); /// Reference to returned data (RETURN opcode used) bytes_ref returnData; diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index a37a6fe99..38deef214 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -1,9 +1,8 @@ - #include "Ext.h" -#include -#include +#include "preprocessor/llvm_includes_start.h" #include +#include "preprocessor/llvm_includes_end.h" #include "RuntimeManager.h" #include "Memory.h" @@ -41,8 +40,8 @@ std::array::value> const& getEnvFuncDescs() FuncDesc{"env_sstore", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})}, FuncDesc{"env_sha3", getFunctionType(Type::Void, {Type::BytePtr, Type::Size, Type::WordPtr})}, FuncDesc{"env_balance", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})}, - FuncDesc{"env_create", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::WordPtr})}, - FuncDesc{"env_call", getFunctionType(Type::Bool, {Type::EnvPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::BytePtr, Type::Size, Type::WordPtr})}, + FuncDesc{"env_create", getFunctionType(Type::Void, {Type::EnvPtr, Type::GasPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::WordPtr})}, + FuncDesc{"env_call", getFunctionType(Type::Bool, {Type::EnvPtr, Type::GasPtr, Type::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::BytePtr, Type::Size, Type::WordPtr})}, FuncDesc{"env_log", getFunctionType(Type::Void, {Type::EnvPtr, Type::BytePtr, Type::Size, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr})}, FuncDesc{"env_blockhash", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})}, FuncDesc{"env_extcode", getFunctionType(Type::BytePtr, {Type::EnvPtr, Type::WordPtr, Type::Size->getPointerTo()})}, @@ -60,14 +59,16 @@ llvm::Function* createFunc(EnvFunc _id, llvm::Module* _module) llvm::Value* Ext::getArgAlloca() { - auto& a = m_argAllocas[m_argCounter++]; + auto& a = m_argAllocas[m_argCounter]; if (!a) { - // FIXME: Improve order and names InsertPointGuard g{getBuilder()}; - getBuilder().SetInsertPoint(getMainFunction()->front().getFirstNonPHI()); - a = getBuilder().CreateAlloca(Type::Word, nullptr, "arg"); + auto allocaIt = getMainFunction()->front().begin(); + std::advance(allocaIt, m_argCounter); // Skip already created allocas + getBuilder().SetInsertPoint(allocaIt); + a = getBuilder().CreateAlloca(Type::Word, nullptr, {"a.", std::to_string(m_argCounter)}); } + ++m_argCounter; return a; } @@ -124,30 +125,26 @@ llvm::Value* Ext::blockhash(llvm::Value* _number) return Endianness::toNative(getBuilder(), hash); } -llvm::Value* Ext::create(llvm::Value*& _gas, llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize) +llvm::Value* Ext::create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize) { - auto gas = byPtr(_gas); auto ret = getArgAlloca(); auto begin = m_memoryMan.getBytePtr(_initOff); auto size = m_builder.CreateTrunc(_initSize, Type::Size, "size"); - createCall(EnvFunc::create, {getRuntimeManager().getEnvPtr(), gas, byPtr(_endowment), begin, size, ret}); - _gas = m_builder.CreateLoad(gas); // Return gas + createCall(EnvFunc::create, {getRuntimeManager().getEnvPtr(), getRuntimeManager().getGasPtr(), byPtr(_endowment), begin, size, ret}); llvm::Value* address = m_builder.CreateLoad(ret); address = Endianness::toNative(m_builder, address); return address; } -llvm::Value* Ext::call(llvm::Value*& _gas, llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize, llvm::Value* _codeAddress) +llvm::Value* Ext::call(llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize, llvm::Value* _codeAddress) { - auto gas = byPtr(_gas); auto receiveAddress = Endianness::toBE(m_builder, _receiveAddress); auto inBeg = m_memoryMan.getBytePtr(_inOff); auto inSize = m_builder.CreateTrunc(_inSize, Type::Size, "in.size"); auto outBeg = m_memoryMan.getBytePtr(_outOff); auto outSize = m_builder.CreateTrunc(_outSize, Type::Size, "out.size"); auto codeAddress = Endianness::toBE(m_builder, _codeAddress); - auto ret = createCall(EnvFunc::call, {getRuntimeManager().getEnvPtr(), gas, byPtr(receiveAddress), byPtr(_value), inBeg, inSize, outBeg, outSize, byPtr(codeAddress)}); - _gas = m_builder.CreateLoad(gas); // Return gas + auto ret = createCall(EnvFunc::call, {getRuntimeManager().getEnvPtr(), getRuntimeManager().getGasPtr(), byPtr(receiveAddress), byPtr(_value), inBeg, inSize, outBeg, outSize, byPtr(codeAddress)}); return m_builder.CreateZExt(ret, Type::Word, "ret"); } diff --git a/libevmjit/Ext.h b/libevmjit/Ext.h index 2601d32ab..1c0c0fc56 100644 --- a/libevmjit/Ext.h +++ b/libevmjit/Ext.h @@ -1,7 +1,7 @@ - #pragma once #include + #include "CompilerHelper.h" namespace dev @@ -50,8 +50,8 @@ public: llvm::Value* balance(llvm::Value* _address); llvm::Value* calldataload(llvm::Value* _index); - llvm::Value* create(llvm::Value*& _gas, llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize); - llvm::Value* call(llvm::Value*& _gas, llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize, llvm::Value* _codeAddress); + llvm::Value* create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize); + llvm::Value* call(llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize, llvm::Value* _codeAddress); llvm::Value* blockhash(llvm::Value* _number); llvm::Value* sha3(llvm::Value* _inOff, llvm::Value* _inSize); diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index 4aa6a738d..ca21714e0 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -1,11 +1,9 @@ - #include "GasMeter.h" -#include -#include +#include "preprocessor/llvm_includes_start.h" #include +#include "preprocessor/llvm_includes_end.h" -#include "Type.h" #include "Ext.h" #include "RuntimeManager.h" @@ -19,29 +17,29 @@ namespace jit namespace // Helper functions { -uint64_t const c_stepGas = 1; -uint64_t const c_balanceGas = 20; -uint64_t const c_sha3Gas = 10; -uint64_t const c_sha3WordGas = 10; -uint64_t const c_sloadGas = 20; -uint64_t const c_sstoreSetGas = 300; -uint64_t const c_sstoreResetGas = 100; -uint64_t const c_sstoreRefundGas = 100; -uint64_t const c_createGas = 100; -uint64_t const c_createDataGas = 5; -uint64_t const c_callGas = 20; -uint64_t const c_expGas = 1; -uint64_t const c_expByteGas = 1; -uint64_t const c_memoryGas = 1; -uint64_t const c_txDataZeroGas = 1; -uint64_t const c_txDataNonZeroGas = 5; -uint64_t const c_txGas = 500; -uint64_t const c_logGas = 32; -uint64_t const c_logDataGas = 1; -uint64_t const c_logTopicGas = 32; -uint64_t const c_copyGas = 1; - -uint64_t getStepCost(Instruction inst) +int64_t const c_stepGas = 1; +int64_t const c_balanceGas = 20; +int64_t const c_sha3Gas = 10; +int64_t const c_sha3WordGas = 10; +int64_t const c_sloadGas = 20; +int64_t const c_sstoreSetGas = 300; +int64_t const c_sstoreResetGas = 100; +int64_t const c_sstoreRefundGas = 100; +int64_t const c_createGas = 100; +int64_t const c_createDataGas = 5; +int64_t const c_callGas = 20; +int64_t const c_expGas = 1; +int64_t const c_expByteGas = 1; +int64_t const c_memoryGas = 1; +int64_t const c_txDataZeroGas = 1; +int64_t const c_txDataNonZeroGas = 5; +int64_t const c_txGas = 500; +int64_t const c_logGas = 32; +int64_t const c_logDataGas = 1; +int64_t const c_logTopicGas = 32; +int64_t const c_copyGas = 1; + +int64_t getStepCost(Instruction inst) { switch (inst) { @@ -72,7 +70,7 @@ uint64_t getStepCost(Instruction inst) case Instruction::LOG3: case Instruction::LOG4: { - auto numTopics = static_cast(inst) - static_cast(Instruction::LOG0); + auto numTopics = static_cast(inst) - static_cast(Instruction::LOG0); return c_logGas + numTopics * c_logTopicGas; } } @@ -86,7 +84,7 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) { auto module = getModule(); - llvm::Type* gasCheckArgs[] = {Type::RuntimePtr, Type::Word}; + llvm::Type* gasCheckArgs[] = {Type::RuntimePtr, Type::Gas}; m_gasCheckFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, gasCheckArgs, false), llvm::Function::PrivateLinkage, "gas.check", module); InsertPointGuard guard(m_builder); @@ -94,22 +92,22 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) auto outOfGasBB = llvm::BasicBlock::Create(_builder.getContext(), "OutOfGas", m_gasCheckFunc); auto updateBB = llvm::BasicBlock::Create(_builder.getContext(), "Update", m_gasCheckFunc); + auto rt = &m_gasCheckFunc->getArgumentList().front(); + rt->setName("rt"); + auto cost = rt->getNextNode(); + cost->setName("cost"); + m_builder.SetInsertPoint(checkBB); - auto arg = m_gasCheckFunc->arg_begin(); - arg->setName("rt"); - ++arg; - arg->setName("cost"); - auto cost = arg; auto gas = m_runtimeManager.getGas(); - auto isOutOfGas = m_builder.CreateICmpUGT(cost, gas, "isOutOfGas"); + gas = m_builder.CreateNSWSub(gas, cost, "gasUpdated"); + auto isOutOfGas = m_builder.CreateICmpSLT(gas, m_builder.getInt64(0), "isOutOfGas"); // gas < 0, with gas == 0 we can still do 0 cost instructions m_builder.CreateCondBr(isOutOfGas, outOfGasBB, updateBB); m_builder.SetInsertPoint(outOfGasBB); - m_runtimeManager.raiseException(ReturnCode::OutOfGas); + m_runtimeManager.abort(); m_builder.CreateUnreachable(); m_builder.SetInsertPoint(updateBB); - gas = m_builder.CreateSub(gas, cost); m_runtimeManager.setGas(gas); m_builder.CreateRetVoid(); } @@ -119,7 +117,7 @@ void GasMeter::count(Instruction _inst) if (!m_checkCall) { // Create gas check call with mocked block cost at begining of current cost-block - m_checkCall = createCall(m_gasCheckFunc, {m_runtimeManager.getRuntimePtr(), llvm::UndefValue::get(Type::Word)}); + m_checkCall = createCall(m_gasCheckFunc, {m_runtimeManager.getRuntimePtr(), llvm::UndefValue::get(Type::Gas)}); } m_blockCost += getStepCost(_inst); @@ -127,6 +125,15 @@ void GasMeter::count(Instruction _inst) void GasMeter::count(llvm::Value* _cost) { + if (_cost->getType() == Type::Word) + { + auto gasMax256 = m_builder.CreateZExt(Constant::gasMax, Type::Word); + auto tooHigh = m_builder.CreateICmpUGT(_cost, gasMax256, "costTooHigh"); + auto cost64 = m_builder.CreateTrunc(_cost, Type::Gas); + _cost = m_builder.CreateSelect(tooHigh, Constant::gasMax, cost64, "cost"); + } + + assert(_cost->getType() == Type::Gas); createCall(m_gasCheckFunc, {m_runtimeManager.getRuntimePtr(), _cost}); } @@ -136,12 +143,13 @@ void GasMeter::countExp(llvm::Value* _exponent) // lz - leading zeros // cost = ((256 - lz) + 7) / 8 - // OPT: All calculations can be done on 32/64 bits + // OPT: Can gas update be done in exp algorithm? auto ctlz = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::ctlz, Type::Word); - auto lz = m_builder.CreateCall2(ctlz, _exponent, m_builder.getInt1(false)); - auto sigBits = m_builder.CreateSub(Constant::get(256), lz); - auto sigBytes = m_builder.CreateUDiv(m_builder.CreateAdd(sigBits, Constant::get(7)), Constant::get(8)); + auto lz256 = m_builder.CreateCall2(ctlz, _exponent, m_builder.getInt1(false)); + auto lz = m_builder.CreateTrunc(lz256, Type::Gas, "lz"); + auto sigBits = m_builder.CreateSub(m_builder.getInt64(256), lz, "sigBits"); + auto sigBytes = m_builder.CreateUDiv(m_builder.CreateAdd(sigBits, m_builder.getInt64(7)), m_builder.getInt64(8)); count(sigBytes); } @@ -154,8 +162,8 @@ void GasMeter::countSStore(Ext& _ext, llvm::Value* _index, llvm::Value* _newValu auto newValueIsntZero = m_builder.CreateICmpNE(_newValue, Constant::get(0), "newValueIsntZero"); auto isInsert = m_builder.CreateAnd(oldValueIsZero, newValueIsntZero, "isInsert"); auto isDelete = m_builder.CreateAnd(oldValueIsntZero, newValueIsZero, "isDelete"); - auto cost = m_builder.CreateSelect(isInsert, Constant::get(c_sstoreSetGas), Constant::get(c_sstoreResetGas), "cost"); - cost = m_builder.CreateSelect(isDelete, Constant::get(0), cost, "cost"); + auto cost = m_builder.CreateSelect(isInsert, m_builder.getInt64(c_sstoreSetGas), m_builder.getInt64(c_sstoreResetGas), "cost"); + cost = m_builder.CreateSelect(isDelete, m_builder.getInt64(0), cost, "cost"); count(cost); } @@ -173,17 +181,16 @@ void GasMeter::countSha3Data(llvm::Value* _dataLength) assert(m_blockCost > 0); // SHA3 instruction is already counted // TODO: This round ups to 32 happens in many places - // FIXME: 64-bit arith used, but not verified static_assert(c_sha3WordGas != 1, "SHA3 data cost has changed. Update GasMeter"); - auto dataLength64 = getBuilder().CreateTrunc(_dataLength, Type::lowPrecision); - auto words64 = m_builder.CreateUDiv(m_builder.CreateAdd(dataLength64, getBuilder().getInt64(31)), getBuilder().getInt64(32)); + auto dataLength64 = getBuilder().CreateTrunc(_dataLength, Type::Gas); + auto words64 = m_builder.CreateUDiv(m_builder.CreateNUWAdd(dataLength64, getBuilder().getInt64(31)), getBuilder().getInt64(32)); auto cost64 = m_builder.CreateNUWMul(getBuilder().getInt64(c_sha3WordGas), words64); - auto cost = getBuilder().CreateZExt(cost64, Type::Word); - count(cost); + count(cost64); } void GasMeter::giveBack(llvm::Value* _gas) { + assert(_gas->getType() == Type::Gas); m_runtimeManager.setGas(m_builder.CreateAdd(m_runtimeManager.getGas(), _gas)); } @@ -199,7 +206,7 @@ void GasMeter::commitCostBlock() return; } - m_checkCall->setArgOperand(1, Constant::get(m_blockCost)); // Update block cost in gas check call + m_checkCall->setArgOperand(1, m_builder.getInt64(m_blockCost)); // Update block cost in gas check call m_checkCall = nullptr; // End cost-block m_blockCost = 0; } diff --git a/libevmjit/GasMeter.h b/libevmjit/GasMeter.h index 56da6eb9f..4056cd64d 100644 --- a/libevmjit/GasMeter.h +++ b/libevmjit/GasMeter.h @@ -1,4 +1,3 @@ - #pragma once #include "CompilerHelper.h" @@ -50,7 +49,7 @@ public: private: /// Cumulative gas cost of a block of instructions /// @TODO Handle overflow - uint64_t m_blockCost = 0; + int64_t m_blockCost = 0; llvm::CallInst* m_checkCall = nullptr; llvm::Function* m_gasCheckFunc = nullptr; diff --git a/libevmjit/Instruction.cpp b/libevmjit/Instruction.cpp index fdc40d043..f70b020f8 100644 --- a/libevmjit/Instruction.cpp +++ b/libevmjit/Instruction.cpp @@ -1,6 +1,8 @@ - #include "Instruction.h" + +#include "preprocessor/llvm_includes_start.h" #include +#include "preprocessor/llvm_includes_end.h" namespace dev { @@ -9,7 +11,7 @@ namespace eth namespace jit { -llvm::APInt readPushData(bytes::const_iterator& _curr, bytes::const_iterator _end) +llvm::APInt readPushData(code_iterator& _curr, code_iterator _end) { auto pushInst = *_curr; assert(Instruction(pushInst) >= Instruction::PUSH1 && Instruction(pushInst) <= Instruction::PUSH32); @@ -26,7 +28,7 @@ llvm::APInt readPushData(bytes::const_iterator& _curr, bytes::const_iterator _en return value; } -void skipPushData(bytes::const_iterator& _curr, bytes::const_iterator _end) +void skipPushData(code_iterator& _curr, code_iterator _end) { auto pushInst = *_curr; assert(Instruction(pushInst) >= Instruction::PUSH1 && Instruction(pushInst) <= Instruction::PUSH32); diff --git a/libevmjit/Instruction.h b/libevmjit/Instruction.h index 158490dee..6785213d6 100644 --- a/libevmjit/Instruction.h +++ b/libevmjit/Instruction.h @@ -161,11 +161,11 @@ enum class Instruction: uint8_t /// Reads PUSH data from pointed fragment of bytecode and constructs number out of it /// Reading out of bytecode means reading 0 /// @param _curr is updated and points the last real byte read -llvm::APInt readPushData(bytes::const_iterator& _curr, bytes::const_iterator _end); +llvm::APInt readPushData(code_iterator& _curr, code_iterator _end); /// Skips PUSH data in pointed fragment of bytecode. /// @param _curr is updated and points the last real byte skipped -void skipPushData(bytes::const_iterator& _curr, bytes::const_iterator _end); +void skipPushData(code_iterator& _curr, code_iterator _end); #define ANY_PUSH PUSH1: \ case Instruction::PUSH2: \ diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp index c6f8a9ec0..647c5f26a 100644 --- a/libevmjit/Memory.cpp +++ b/libevmjit/Memory.cpp @@ -1,239 +1,260 @@ -#include "Memory.h" - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "Type.h" -#include "Runtime.h" -#include "GasMeter.h" -#include "Endianness.h" -#include "RuntimeManager.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter): - RuntimeHelper(_runtimeManager), // TODO: RuntimeHelper not needed - m_gasMeter(_gasMeter) -{ - llvm::Type* resizeArgs[] = {Type::RuntimePtr, Type::WordPtr}; - m_resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, resizeArgs, false), llvm::Function::ExternalLinkage, "mem_resize", getModule()); - llvm::AttrBuilder attrBuilder; - attrBuilder.addAttribute(llvm::Attribute::NoAlias).addAttribute(llvm::Attribute::NoCapture).addAttribute(llvm::Attribute::NonNull).addAttribute(llvm::Attribute::ReadOnly); - m_resize->setAttributes(llvm::AttributeSet::get(m_resize->getContext(), 1, attrBuilder)); - - m_require = createRequireFunc(_gasMeter); - m_loadWord = createFunc(false, Type::Word, _gasMeter); - m_storeWord = createFunc(true, Type::Word, _gasMeter); - m_storeByte = createFunc(true, Type::Byte, _gasMeter); -} - -llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter) -{ - llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Word, Type::Word}; - auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "mem.require", getModule()); - auto rt = func->arg_begin(); - rt->setName("rt"); - auto offset = rt->getNextNode(); - offset->setName("offset"); - auto size = offset->getNextNode(); - size->setName("size"); - - auto preBB = llvm::BasicBlock::Create(func->getContext(), "Pre", func); - auto checkBB = llvm::BasicBlock::Create(func->getContext(), "Check", func); - auto resizeBB = llvm::BasicBlock::Create(func->getContext(), "Resize", func); - auto returnBB = llvm::BasicBlock::Create(func->getContext(), "Return", func); - - InsertPointGuard guard(m_builder); // Restores insert point at function exit - - // BB "Pre": Ignore checks with size 0 - m_builder.SetInsertPoint(preBB); - auto sizeIsZero = m_builder.CreateICmpEQ(size, Constant::get(0)); - m_builder.CreateCondBr(sizeIsZero, returnBB, checkBB); - - // BB "Check" - m_builder.SetInsertPoint(checkBB); - auto uaddWO = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::uadd_with_overflow, Type::Word); - auto uaddRes = m_builder.CreateCall2(uaddWO, offset, size, "res"); - auto sizeRequired = m_builder.CreateExtractValue(uaddRes, 0, "sizeReq"); - auto overflow1 = m_builder.CreateExtractValue(uaddRes, 1, "overflow1"); - auto rtPtr = getRuntimeManager().getRuntimePtr(); - auto sizePtr = m_builder.CreateStructGEP(rtPtr, 4); - auto currSize = m_builder.CreateLoad(sizePtr, "currSize"); - auto tooSmall = m_builder.CreateICmpULE(currSize, sizeRequired, "tooSmall"); - auto resizeNeeded = m_builder.CreateOr(tooSmall, overflow1, "resizeNeeded"); - m_builder.CreateCondBr(resizeNeeded, resizeBB, returnBB); // OPT branch weights? - - // BB "Resize" - m_builder.SetInsertPoint(resizeBB); - // Check gas first - uaddRes = m_builder.CreateCall2(uaddWO, sizeRequired, Constant::get(31), "res"); - auto wordsRequired = m_builder.CreateExtractValue(uaddRes, 0); - auto overflow2 = m_builder.CreateExtractValue(uaddRes, 1, "overflow2"); - auto overflow = m_builder.CreateOr(overflow1, overflow2, "overflow"); - wordsRequired = m_builder.CreateSelect(overflow, Constant::get(-1), wordsRequired); - wordsRequired = m_builder.CreateUDiv(wordsRequired, Constant::get(32), "wordsReq"); - sizeRequired = m_builder.CreateMul(wordsRequired, Constant::get(32), "roundedSizeReq"); - auto words = m_builder.CreateUDiv(currSize, Constant::get(32), "words"); // size is always 32*k - auto newWords = m_builder.CreateSub(wordsRequired, words, "addtionalWords"); - _gasMeter.countMemory(newWords); - // Resize - m_builder.CreateStore(sizeRequired, sizePtr); - auto newData = m_builder.CreateCall2(m_resize, rt, sizePtr, "newData"); - auto dataPtr = m_builder.CreateStructGEP(rtPtr, 3); - m_builder.CreateStore(newData, dataPtr); - m_builder.CreateBr(returnBB); - - // BB "Return" - m_builder.SetInsertPoint(returnBB); - m_builder.CreateRetVoid(); - return func; -} - -llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, GasMeter&) -{ - auto isWord = _valueType == Type::Word; - - llvm::Type* storeArgs[] = {Type::RuntimePtr, Type::Word, _valueType}; - llvm::Type* loadArgs[] = {Type::RuntimePtr, Type::Word}; - auto name = _isStore ? isWord ? "mstore" : "mstore8" : "mload"; - auto funcType = _isStore ? llvm::FunctionType::get(Type::Void, storeArgs, false) : llvm::FunctionType::get(Type::Word, loadArgs, false); - auto func = llvm::Function::Create(funcType, llvm::Function::PrivateLinkage, name, getModule()); - - InsertPointGuard guard(m_builder); // Restores insert point at function exit - - m_builder.SetInsertPoint(llvm::BasicBlock::Create(func->getContext(), {}, func)); - auto rt = func->arg_begin(); - rt->setName("rt"); - auto index = rt->getNextNode(); - index->setName("index"); - - auto valueSize = _valueType->getPrimitiveSizeInBits() / 8; - this->require(index, Constant::get(valueSize)); - auto ptr = getBytePtr(index); - if (isWord) - ptr = m_builder.CreateBitCast(ptr, Type::WordPtr, "wordPtr"); - if (_isStore) - { - llvm::Value* value = index->getNextNode(); - value->setName("value"); - if (isWord) - value = Endianness::toBE(m_builder, value); - m_builder.CreateStore(value, ptr); - m_builder.CreateRetVoid(); - } - else - { - llvm::Value* ret = m_builder.CreateLoad(ptr); - ret = Endianness::toNative(m_builder, ret); - m_builder.CreateRet(ret); - } - - return func; -} - - -llvm::Value* Memory::loadWord(llvm::Value* _addr) -{ - return createCall(m_loadWord, {getRuntimeManager().getRuntimePtr(), _addr}); -} - -void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word) -{ - createCall(m_storeWord, {getRuntimeManager().getRuntimePtr(), _addr, _word}); -} - -void Memory::storeByte(llvm::Value* _addr, llvm::Value* _word) -{ - auto byte = m_builder.CreateTrunc(_word, Type::Byte, "byte"); - createCall(m_storeByte, {getRuntimeManager().getRuntimePtr(), _addr, byte}); -} - -llvm::Value* Memory::getData() -{ - auto rtPtr = getRuntimeManager().getRuntimePtr(); - auto dataPtr = m_builder.CreateStructGEP(rtPtr, 3); - return m_builder.CreateLoad(dataPtr, "data"); -} - -llvm::Value* Memory::getSize() -{ - auto rtPtr = getRuntimeManager().getRuntimePtr(); - auto sizePtr = m_builder.CreateStructGEP(rtPtr, 4); - return m_builder.CreateLoad(sizePtr, "size"); -} - -llvm::Value* Memory::getBytePtr(llvm::Value* _index) -{ - auto idx = m_builder.CreateTrunc(_index, Type::Size, "idx"); // Never allow memory index be a type bigger than i64 - return m_builder.CreateGEP(getData(), idx, "ptr"); -} - -void Memory::require(llvm::Value* _offset, llvm::Value* _size) -{ - createCall(m_require, {getRuntimeManager().getRuntimePtr(), _offset, _size}); -} - -void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIdx, - llvm::Value* _destMemIdx, llvm::Value* _reqBytes) -{ - require(_destMemIdx, _reqBytes); - - // Additional copy cost - // TODO: This round ups to 32 happens in many places - auto copyWords = m_builder.CreateUDiv(m_builder.CreateAdd(_reqBytes, Constant::get(31)), Constant::get(32)); - m_gasMeter.countCopy(copyWords); - - // Algorithm: - // isOutsideData = idx256 >= size256 - // idx64 = trunc idx256 - // size64 = trunc size256 - // dataLeftSize = size64 - idx64 // safe if not isOutsideData - // reqBytes64 = trunc _reqBytes // require() handles large values - // bytesToCopy0 = select(reqBytes64 > dataLeftSize, dataSizeLeft, reqBytes64) // min - // bytesToCopy = select(isOutsideData, 0, bytesToCopy0) - - auto isOutsideData = m_builder.CreateICmpUGE(_srcIdx, _srcSize); - auto idx64 = m_builder.CreateTrunc(_srcIdx, Type::lowPrecision); - auto size64 = m_builder.CreateTrunc(_srcSize, Type::lowPrecision); - auto dataLeftSize = m_builder.CreateNUWSub(size64, idx64); - auto reqBytes64 = m_builder.CreateTrunc(_reqBytes, Type::lowPrecision); - auto outOfBound = m_builder.CreateICmpUGT(reqBytes64, dataLeftSize); - auto bytesToCopyInner = m_builder.CreateSelect(outOfBound, dataLeftSize, reqBytes64); - auto zero64 = llvm::ConstantInt::get(Type::lowPrecision, 0); // TODO: Cache common constants - auto bytesToCopy = m_builder.CreateSelect(isOutsideData, zero64, bytesToCopyInner); - - auto src = m_builder.CreateGEP(_srcPtr, idx64, "src"); - auto dstIdx = m_builder.CreateTrunc(_destMemIdx, Type::Size, "dstIdx"); // Never allow memory index be a type bigger than i64 - auto dst = m_builder.CreateGEP(getData(), dstIdx, "dst"); - m_builder.CreateMemCpy(dst, src, bytesToCopy, 0); -} - -} -} -} - - -extern "C" -{ - using namespace dev::eth::jit; - - EXPORT byte* mem_resize(Runtime* _rt, i256* _size) // TODO: Use uint64 as size OR use realloc in LLVM IR - { - auto size = _size->a; // Trunc to 64-bit - auto& memory = _rt->getMemory(); - memory.resize(size); - return memory.data(); - } -} +#include "Memory.h" + +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + +#include "Type.h" +#include "Runtime.h" +#include "GasMeter.h" +#include "Endianness.h" +#include "RuntimeManager.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter): + RuntimeHelper(_runtimeManager), // TODO: RuntimeHelper not needed + m_gasMeter(_gasMeter) +{} + +llvm::Function* Memory::getRequireFunc() +{ + auto& func = m_require; + if (!func) + { + llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Word, Type::Word}; + func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "mem.require", getModule()); + auto rt = func->arg_begin(); + rt->setName("rt"); + auto offset = rt->getNextNode(); + offset->setName("offset"); + auto size = offset->getNextNode(); + size->setName("size"); + + llvm::Type* resizeArgs[] = {Type::RuntimePtr, Type::WordPtr}; + auto resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, resizeArgs, false), llvm::Function::ExternalLinkage, "mem_resize", getModule()); + llvm::AttrBuilder attrBuilder; + attrBuilder.addAttribute(llvm::Attribute::NoAlias).addAttribute(llvm::Attribute::NoCapture).addAttribute(llvm::Attribute::NonNull).addAttribute(llvm::Attribute::ReadOnly); + resize->setAttributes(llvm::AttributeSet::get(resize->getContext(), 1, attrBuilder)); + + auto preBB = llvm::BasicBlock::Create(func->getContext(), "Pre", func); + auto checkBB = llvm::BasicBlock::Create(func->getContext(), "Check", func); + auto resizeBB = llvm::BasicBlock::Create(func->getContext(), "Resize", func); + auto returnBB = llvm::BasicBlock::Create(func->getContext(), "Return", func); + + InsertPointGuard guard(m_builder); // Restores insert point at function exit + + // BB "Pre": Ignore checks with size 0 + m_builder.SetInsertPoint(preBB); + auto sizeIsZero = m_builder.CreateICmpEQ(size, Constant::get(0)); + m_builder.CreateCondBr(sizeIsZero, returnBB, checkBB); + + // BB "Check" + m_builder.SetInsertPoint(checkBB); + auto uaddWO = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::uadd_with_overflow, Type::Word); + auto uaddRes = m_builder.CreateCall2(uaddWO, offset, size, "res"); + auto sizeRequired = m_builder.CreateExtractValue(uaddRes, 0, "sizeReq"); + auto overflow1 = m_builder.CreateExtractValue(uaddRes, 1, "overflow1"); + auto rtPtr = getRuntimeManager().getRuntimePtr(); + auto sizePtr = m_builder.CreateStructGEP(rtPtr, 4); + auto currSize = m_builder.CreateLoad(sizePtr, "currSize"); + auto tooSmall = m_builder.CreateICmpULE(currSize, sizeRequired, "tooSmall"); + auto resizeNeeded = m_builder.CreateOr(tooSmall, overflow1, "resizeNeeded"); + m_builder.CreateCondBr(resizeNeeded, resizeBB, returnBB); // OPT branch weights? + + // BB "Resize" + m_builder.SetInsertPoint(resizeBB); + // Check gas first + uaddRes = m_builder.CreateCall2(uaddWO, sizeRequired, Constant::get(31), "res"); + auto wordsRequired = m_builder.CreateExtractValue(uaddRes, 0); + auto overflow2 = m_builder.CreateExtractValue(uaddRes, 1, "overflow2"); + auto overflow = m_builder.CreateOr(overflow1, overflow2, "overflow"); + wordsRequired = m_builder.CreateSelect(overflow, Constant::get(-1), wordsRequired); + wordsRequired = m_builder.CreateUDiv(wordsRequired, Constant::get(32), "wordsReq"); + sizeRequired = m_builder.CreateMul(wordsRequired, Constant::get(32), "roundedSizeReq"); + auto words = m_builder.CreateUDiv(currSize, Constant::get(32), "words"); // size is always 32*k + auto newWords = m_builder.CreateSub(wordsRequired, words, "addtionalWords"); + m_gasMeter.countMemory(newWords); + // Resize + m_builder.CreateStore(sizeRequired, sizePtr); + auto newData = m_builder.CreateCall2(resize, rt, sizePtr, "newData"); + auto dataPtr = m_builder.CreateStructGEP(rtPtr, 3); + m_builder.CreateStore(newData, dataPtr); + m_builder.CreateBr(returnBB); + + // BB "Return" + m_builder.SetInsertPoint(returnBB); + m_builder.CreateRetVoid(); + } + return func; +} + +llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, GasMeter&) +{ + auto isWord = _valueType == Type::Word; + + llvm::Type* storeArgs[] = {Type::RuntimePtr, Type::Word, _valueType}; + llvm::Type* loadArgs[] = {Type::RuntimePtr, Type::Word}; + auto name = _isStore ? isWord ? "mstore" : "mstore8" : "mload"; + auto funcType = _isStore ? llvm::FunctionType::get(Type::Void, storeArgs, false) : llvm::FunctionType::get(Type::Word, loadArgs, false); + auto func = llvm::Function::Create(funcType, llvm::Function::PrivateLinkage, name, getModule()); + + InsertPointGuard guard(m_builder); // Restores insert point at function exit + + m_builder.SetInsertPoint(llvm::BasicBlock::Create(func->getContext(), {}, func)); + auto rt = func->arg_begin(); + rt->setName("rt"); + auto index = rt->getNextNode(); + index->setName("index"); + + auto valueSize = _valueType->getPrimitiveSizeInBits() / 8; + this->require(index, Constant::get(valueSize)); + auto ptr = getBytePtr(index); + if (isWord) + ptr = m_builder.CreateBitCast(ptr, Type::WordPtr, "wordPtr"); + if (_isStore) + { + llvm::Value* value = index->getNextNode(); + value->setName("value"); + if (isWord) + value = Endianness::toBE(m_builder, value); + m_builder.CreateStore(value, ptr); + m_builder.CreateRetVoid(); + } + else + { + llvm::Value* ret = m_builder.CreateLoad(ptr); + ret = Endianness::toNative(m_builder, ret); + m_builder.CreateRet(ret); + } + + return func; +} + +llvm::Function* Memory::getLoadWordFunc() +{ + auto& func = m_loadWord; + if (!func) + func = createFunc(false, Type::Word, m_gasMeter); + return func; +} + +llvm::Function* Memory::getStoreWordFunc() +{ + auto& func = m_storeWord; + if (!func) + func = createFunc(true, Type::Word, m_gasMeter); + return func; +} + +llvm::Function* Memory::getStoreByteFunc() +{ + auto& func = m_storeByte; + if (!func) + func = createFunc(true, Type::Byte, m_gasMeter); + return func; +} + + +llvm::Value* Memory::loadWord(llvm::Value* _addr) +{ + return createCall(getLoadWordFunc(), {getRuntimeManager().getRuntimePtr(), _addr}); +} + +void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word) +{ + createCall(getStoreWordFunc(), {getRuntimeManager().getRuntimePtr(), _addr, _word}); +} + +void Memory::storeByte(llvm::Value* _addr, llvm::Value* _word) +{ + auto byte = m_builder.CreateTrunc(_word, Type::Byte, "byte"); + createCall(getStoreByteFunc(), {getRuntimeManager().getRuntimePtr(), _addr, byte}); +} + +llvm::Value* Memory::getData() +{ + auto rtPtr = getRuntimeManager().getRuntimePtr(); + auto dataPtr = m_builder.CreateStructGEP(rtPtr, 3); + return m_builder.CreateLoad(dataPtr, "data"); +} + +llvm::Value* Memory::getSize() +{ + auto rtPtr = getRuntimeManager().getRuntimePtr(); + auto sizePtr = m_builder.CreateStructGEP(rtPtr, 4); + return m_builder.CreateLoad(sizePtr, "size"); +} + +llvm::Value* Memory::getBytePtr(llvm::Value* _index) +{ + auto idx = m_builder.CreateTrunc(_index, Type::Size, "idx"); // Never allow memory index be a type bigger than i64 + return m_builder.CreateGEP(getData(), idx, "ptr"); +} + +void Memory::require(llvm::Value* _offset, llvm::Value* _size) +{ + if (auto constant = llvm::dyn_cast(_size)) + { + if (!constant->getValue()) + return; + } + createCall(getRequireFunc(), {getRuntimeManager().getRuntimePtr(), _offset, _size}); +} + +void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIdx, + llvm::Value* _destMemIdx, llvm::Value* _reqBytes) +{ + require(_destMemIdx, _reqBytes); + + // Additional copy cost + // TODO: This round ups to 32 happens in many places + auto reqBytes = m_builder.CreateTrunc(_reqBytes, Type::Gas); + auto copyWords = m_builder.CreateUDiv(m_builder.CreateNUWAdd(reqBytes, m_builder.getInt64(31)), m_builder.getInt64(32)); + m_gasMeter.countCopy(copyWords); + + // Algorithm: + // isOutsideData = idx256 >= size256 + // idx64 = trunc idx256 + // size64 = trunc size256 + // dataLeftSize = size64 - idx64 // safe if not isOutsideData + // reqBytes64 = trunc _reqBytes // require() handles large values + // bytesToCopy0 = select(reqBytes64 > dataLeftSize, dataSizeLeft, reqBytes64) // min + // bytesToCopy = select(isOutsideData, 0, bytesToCopy0) + + auto isOutsideData = m_builder.CreateICmpUGE(_srcIdx, _srcSize); + auto idx64 = m_builder.CreateTrunc(_srcIdx, Type::Size); + auto size64 = m_builder.CreateTrunc(_srcSize, Type::Size); + auto dataLeftSize = m_builder.CreateNUWSub(size64, idx64); + auto outOfBound = m_builder.CreateICmpUGT(reqBytes, dataLeftSize); + auto bytesToCopyInner = m_builder.CreateSelect(outOfBound, dataLeftSize, reqBytes); + auto bytesToCopy = m_builder.CreateSelect(isOutsideData, m_builder.getInt64(0), bytesToCopyInner); + + auto src = m_builder.CreateGEP(_srcPtr, idx64, "src"); + auto dstIdx = m_builder.CreateTrunc(_destMemIdx, Type::Size, "dstIdx"); // Never allow memory index be a type bigger than i64 + auto dst = m_builder.CreateGEP(getData(), dstIdx, "dst"); + m_builder.CreateMemCpy(dst, src, bytesToCopy, 0); +} + +} +} +} + + +extern "C" +{ + using namespace dev::eth::jit; + + EXPORT byte* mem_resize(Runtime* _rt, i256* _size) // TODO: Use uint64 as size OR use realloc in LLVM IR + { + auto size = _size->a; // Trunc to 64-bit + auto& memory = _rt->getMemory(); + memory.resize(size); + return memory.data(); + } +} diff --git a/libevmjit/Memory.h b/libevmjit/Memory.h index ed9c51805..e8edce735 100644 --- a/libevmjit/Memory.h +++ b/libevmjit/Memory.h @@ -31,13 +31,16 @@ private: GasMeter& m_gasMeter; llvm::Function* createFunc(bool _isStore, llvm::Type* _type, GasMeter& _gasMeter); - llvm::Function* createRequireFunc(GasMeter& _gasMeter); - llvm::Function* m_resize; - llvm::Function* m_require; - llvm::Function* m_loadWord; - llvm::Function* m_storeWord; - llvm::Function* m_storeByte; + llvm::Function* getRequireFunc(); + llvm::Function* getLoadWordFunc(); + llvm::Function* getStoreWordFunc(); + llvm::Function* getStoreByteFunc(); + + llvm::Function* m_require = nullptr; + llvm::Function* m_loadWord = nullptr; + llvm::Function* m_storeWord = nullptr; + llvm::Function* m_storeByte = nullptr; }; } diff --git a/libevmjit/Optimizer.cpp b/libevmjit/Optimizer.cpp new file mode 100644 index 000000000..84a7c3a6a --- /dev/null +++ b/libevmjit/Optimizer.cpp @@ -0,0 +1,29 @@ +#include "Optimizer.h" + +#include "preprocessor/llvm_includes_start.h" +#include +#include +#include +#include "preprocessor/llvm_includes_end.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +bool optimize(llvm::Module& _module) +{ + auto pm = llvm::PassManager{}; + //pm.add(llvm::createFunctionInliningPass(2, 2)); // Produces invalid IR + pm.add(llvm::createCFGSimplificationPass()); + //pm.add(llvm::createInstructionCombiningPass()); // Produces invalid runtime results + pm.add(llvm::createAggressiveDCEPass()); + pm.add(llvm::createLowerSwitchPass()); + return pm.run(_module); +} + +} +} +} diff --git a/libevmjit/Optimizer.h b/libevmjit/Optimizer.h new file mode 100644 index 000000000..4a3147a7f --- /dev/null +++ b/libevmjit/Optimizer.h @@ -0,0 +1,19 @@ +#pragma once + +namespace llvm +{ + class Module; +} + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +bool optimize(llvm::Module& _module); + +} +} +} diff --git a/libevmjit/Runtime.cpp b/libevmjit/Runtime.cpp index eb70e01d1..69937368c 100644 --- a/libevmjit/Runtime.cpp +++ b/libevmjit/Runtime.cpp @@ -1,9 +1,6 @@ - #include "Runtime.h" -#include -#include -#include +#include namespace dev { @@ -14,8 +11,7 @@ namespace jit Runtime::Runtime(RuntimeData* _data, Env* _env) : m_data(*_data), - m_env(*_env), - m_currJmpBuf(m_jmpBuf) + m_env(*_env) {} bytes_ref Runtime::getReturnData() const diff --git a/libevmjit/Runtime.h b/libevmjit/Runtime.h index 20cf56984..69f2788a4 100644 --- a/libevmjit/Runtime.h +++ b/libevmjit/Runtime.h @@ -1,46 +1,36 @@ - -#pragma once - -#include -#include "RuntimeData.h" - -namespace dev -{ -namespace eth -{ -namespace jit -{ - -using StackImpl = std::vector; -using MemoryImpl = bytes; -using jmp_buf_ref = decltype(&std::jmp_buf{}[0]); - -class Runtime -{ -public: - Runtime(RuntimeData* _data, Env* _env); - - Runtime(const Runtime&) = delete; - Runtime& operator=(const Runtime&) = delete; - - StackImpl& getStack() { return m_stack; } - MemoryImpl& getMemory() { return m_memory; } - Env* getEnvPtr() { return &m_env; } - - bytes_ref getReturnData() const; - jmp_buf_ref getJmpBuf() { return m_jmpBuf; } - -private: - RuntimeData& m_data; ///< Pointer to data. Expected by compiled contract. - Env& m_env; ///< Pointer to environment proxy. Expected by compiled contract. - jmp_buf_ref m_currJmpBuf; ///< Pointer to jump buffer. Expected by compiled contract. - byte* m_memoryData = nullptr; - i256 m_memorySize; - std::jmp_buf m_jmpBuf; - StackImpl m_stack; - MemoryImpl m_memory; -}; - -} -} -} +#pragma once + +#include "RuntimeData.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ +using MemoryImpl = bytes; + +class Runtime +{ +public: + Runtime(RuntimeData* _data, Env* _env); + + Runtime(const Runtime&) = delete; + Runtime& operator=(const Runtime&) = delete; + + MemoryImpl& getMemory() { return m_memory; } + + bytes_ref getReturnData() const; + +private: + RuntimeData& m_data; ///< Pointer to data. Expected by compiled contract. + Env& m_env; ///< Pointer to environment proxy. Expected by compiled contract. + void* m_currJmpBuf = nullptr; ///< Pointer to jump buffer. Expected by compiled contract. + byte* m_memoryData = nullptr; + i256 m_memorySize; + MemoryImpl m_memory; +}; + +} +} +} diff --git a/libevmjit/RuntimeData.h b/libevmjit/RuntimeData.h index 58d68db8a..cc081cc58 100644 --- a/libevmjit/RuntimeData.h +++ b/libevmjit/RuntimeData.h @@ -1,7 +1,6 @@ #pragma once -#include "Utils.h" - +#include "Common.h" namespace dev { @@ -50,6 +49,7 @@ struct RuntimeData int64_t timestamp = 0; byte const* code = nullptr; uint64_t codeSize = 0; + i256 codeHash; }; /// VM Environment (ExtVM) opaque type diff --git a/libevmjit/RuntimeManager.cpp b/libevmjit/RuntimeManager.cpp index 408f2dee3..62c24326e 100644 --- a/libevmjit/RuntimeManager.cpp +++ b/libevmjit/RuntimeManager.cpp @@ -1,12 +1,10 @@ - #include "RuntimeManager.h" -#include -#include -#include +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" -#include "RuntimeData.h" -#include "Instruction.h" +#include "Stack.h" namespace dev { @@ -87,9 +85,17 @@ llvm::Twine getName(RuntimeData::Index _index) } } -RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder): CompilerHelper(_builder) +RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder, llvm::Value* _jmpBuf, code_iterator _codeBegin, code_iterator _codeEnd): + CompilerHelper(_builder), + m_jmpBuf(_jmpBuf), + m_codeBegin(_codeBegin), + m_codeEnd(_codeEnd) { - m_longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::longjmp); + m_longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::eh_sjlj_longjmp); + + // save jmpBuf to be used in helper functions + auto ptr = m_builder.CreateStructGEP(getRuntimePtr(), 2); + m_builder.CreateStore(m_jmpBuf, ptr); // Unpack data auto rtPtr = getRuntimePtr(); @@ -161,9 +167,18 @@ void RuntimeManager::registerSuicide(llvm::Value* _balanceAddress) set(RuntimeData::SuicideDestAddress, _balanceAddress); } -void RuntimeManager::raiseException(ReturnCode _returnCode) +void RuntimeManager::exit(ReturnCode _returnCode) { - m_builder.CreateCall2(m_longjmp, getJmpBuf(), Constant::get(_returnCode)); + if (m_stack) + m_stack->free(); + + m_builder.CreateRet(Constant::get(_returnCode)); +} + +void RuntimeManager::abort(llvm::Value* _jmpBuf) +{ + auto longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::eh_sjlj_longjmp); + createCall(longjmp, {_jmpBuf}); } llvm::Value* RuntimeManager::get(Instruction _inst) @@ -191,14 +206,14 @@ llvm::Value* RuntimeManager::getCallData() llvm::Value* RuntimeManager::getCode() { - return get(RuntimeData::Code); + // OPT Check what is faster + //return get(RuntimeData::Code); + return m_builder.CreateGlobalStringPtr({reinterpret_cast(m_codeBegin), static_cast(m_codeEnd - m_codeBegin)}, "code"); } llvm::Value* RuntimeManager::getCodeSize() { - auto value = get(RuntimeData::CodeSize); - assert(value->getType() == Type::Size); - return getBuilder().CreateZExt(value, Type::Word); + return Constant::get(m_codeEnd - m_codeBegin); } llvm::Value* RuntimeManager::getCallDataSize() @@ -208,23 +223,28 @@ llvm::Value* RuntimeManager::getCallDataSize() return getBuilder().CreateZExt(value, Type::Word); } -llvm::Value* RuntimeManager::getJmpBuf() +llvm::Value* RuntimeManager::getJmpBufExt() { - auto ptr = getBuilder().CreateStructGEP(getRuntimePtr(), 2, "jmpbufPtr"); - return getBuilder().CreateLoad(ptr, "jmpbuf"); + auto ptr = getBuilder().CreateStructGEP(getRuntimePtr(), 2); + return getBuilder().CreateLoad(ptr, "jmpBufExt"); } llvm::Value* RuntimeManager::getGas() { - auto value = get(RuntimeData::Gas); - assert(value->getType() == Type::Size); - return getBuilder().CreateZExt(value, Type::Word); + auto gas = get(RuntimeData::Gas); + assert(gas->getType() == Type::Gas); + return gas; +} + +llvm::Value* RuntimeManager::getGasPtr() +{ + return getPtr(RuntimeData::Gas); } void RuntimeManager::setGas(llvm::Value* _gas) { - auto newGas = getBuilder().CreateTrunc(_gas, Type::Size); - set(RuntimeData::Gas, newGas); + assert(_gas->getType() == Type::Gas); + set(RuntimeData::Gas, _gas); } } diff --git a/libevmjit/RuntimeManager.h b/libevmjit/RuntimeManager.h index b5f3ca657..2f1fb390a 100644 --- a/libevmjit/RuntimeManager.h +++ b/libevmjit/RuntimeManager.h @@ -11,29 +11,37 @@ namespace eth { namespace jit { +class Stack; class RuntimeManager: public CompilerHelper { public: - RuntimeManager(llvm::IRBuilder<>& _builder); + RuntimeManager(llvm::IRBuilder<>& _builder, llvm::Value* _jmpBuf, code_iterator _codeBegin, code_iterator _codeEnd); llvm::Value* getRuntimePtr(); llvm::Value* getDataPtr(); - llvm::Value* getEnvPtr(); // TODO: Can we make it const? + llvm::Value* getEnvPtr(); llvm::Value* get(RuntimeData::Index _index); llvm::Value* get(Instruction _inst); - llvm::Value* getGas(); // TODO: Remove + llvm::Value* getGas(); + llvm::Value* getGasPtr(); llvm::Value* getCallData(); llvm::Value* getCode(); llvm::Value* getCodeSize(); llvm::Value* getCallDataSize(); + llvm::Value* getJmpBuf() { return m_jmpBuf; } void setGas(llvm::Value* _gas); void registerReturnData(llvm::Value* _index, llvm::Value* _size); void registerSuicide(llvm::Value* _balanceAddress); - void raiseException(ReturnCode _returnCode); + void exit(ReturnCode _returnCode); + + void abort(llvm::Value* _jmpBuf); + void abort() { abort(getJmpBufExt()); } + + void setStack(Stack& _stack) { m_stack = &_stack; } static llvm::StructType* getRuntimeType(); static llvm::StructType* getRuntimeDataType(); @@ -41,11 +49,17 @@ public: private: llvm::Value* getPtr(RuntimeData::Index _index); void set(RuntimeData::Index _index, llvm::Value* _value); - llvm::Value* getJmpBuf(); + llvm::Value* getJmpBufExt(); llvm::Function* m_longjmp = nullptr; + llvm::Value* const m_jmpBuf; llvm::Value* m_dataPtr = nullptr; llvm::Value* m_envPtr = nullptr; + + code_iterator m_codeBegin = {}; + code_iterator m_codeEnd = {}; + + Stack* m_stack = nullptr; }; } diff --git a/libevmjit/Stack.cpp b/libevmjit/Stack.cpp index 44f1c21c1..dd279ec7b 100644 --- a/libevmjit/Stack.cpp +++ b/libevmjit/Stack.cpp @@ -1,10 +1,14 @@ #include "Stack.h" + +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + #include "RuntimeManager.h" #include "Runtime.h" -#include "Type.h" +#include "Utils.h" -#include -#include +#include // DEBUG only namespace dev { @@ -13,99 +17,352 @@ namespace eth namespace jit { -Stack::Stack(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager): - CompilerHelper(_builder), - m_runtimeManager(_runtimeManager) +static const auto c_reallocStep = 1; +static const auto c_reallocMultipier = 2; + +llvm::Value* LazyFunction::call(llvm::IRBuilder<>& _builder, std::initializer_list const& _args) { - m_arg = m_builder.CreateAlloca(Type::Word, nullptr, "stack.arg"); + if (!m_func) + m_func = m_creator(); + + return _builder.CreateCall(m_func, {_args.begin(), _args.size()}); +} - using namespace llvm; - using Linkage = GlobalValue::LinkageTypes; +llvm::Function* Array::createArrayPushFunc() +{ + llvm::Type* argTypes[] = {m_array->getType(), Type::Word}; + auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "array.push", getModule()); + func->setDoesNotThrow(); + func->setDoesNotCapture(1); - auto module = getModule(); + llvm::Type* reallocArgTypes[] = {Type::BytePtr, Type::Size}; + auto reallocFunc = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, reallocArgTypes, false), llvm::Function::ExternalLinkage, "ext_realloc", getModule()); + reallocFunc->setDoesNotThrow(); + reallocFunc->setDoesNotAlias(0); + reallocFunc->setDoesNotCapture(1); - llvm::Type* pushArgTypes[] = {Type::RuntimePtr, Type::WordPtr}; - m_push = Function::Create(FunctionType::get(Type::Void, pushArgTypes, false), Linkage::ExternalLinkage, "stack_push", module); + auto arrayPtr = &func->getArgumentList().front(); + arrayPtr->setName("arrayPtr"); + auto value = arrayPtr->getNextNode(); + value->setName("value"); - llvm::Type* popArgTypes[] = {Type::RuntimePtr, Type::Size}; - m_pop = Function::Create(FunctionType::get(Type::Void, popArgTypes, false), Linkage::ExternalLinkage, "stack_pop", module); + InsertPointGuard guard{m_builder}; + auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), "Entry", func); + auto reallocBB = llvm::BasicBlock::Create(m_builder.getContext(), "Realloc", func); + auto pushBB = llvm::BasicBlock::Create(m_builder.getContext(), "Push", func); - llvm::Type* getSetArgTypes[] = {Type::RuntimePtr, Type::Size, Type::WordPtr}; - m_get = Function::Create(FunctionType::get(Type::Void, getSetArgTypes, false), Linkage::ExternalLinkage, "stack_get", module); - m_set = Function::Create(FunctionType::get(Type::Void, getSetArgTypes, false), Linkage::ExternalLinkage, "stack_set", module); -} + m_builder.SetInsertPoint(entryBB); + auto dataPtr = m_builder.CreateStructGEP(arrayPtr, 0, "dataPtr"); + auto sizePtr = m_builder.CreateStructGEP(arrayPtr, 1, "sizePtr"); + auto capPtr = m_builder.CreateStructGEP(arrayPtr, 2, "capPtr"); + auto data = m_builder.CreateLoad(dataPtr, "data"); + auto size = m_builder.CreateLoad(sizePtr, "size"); + auto cap = m_builder.CreateLoad(capPtr, "cap"); + auto reallocReq = m_builder.CreateICmpEQ(cap, size, "reallocReq"); + m_builder.CreateCondBr(reallocReq, reallocBB, pushBB); -llvm::Value* Stack::get(size_t _index) -{ - m_builder.CreateCall3(m_get, m_runtimeManager.getRuntimePtr(), llvm::ConstantInt::get(Type::Size, _index, false), m_arg); - return m_builder.CreateLoad(m_arg); + m_builder.SetInsertPoint(reallocBB); + auto newCap = m_builder.CreateNUWAdd(cap, m_builder.getInt64(c_reallocStep), "newCap"); + //newCap = m_builder.CreateNUWMul(newCap, m_builder.getInt64(c_reallocMultipier)); + auto reallocSize = m_builder.CreateShl(newCap, 5, "reallocSize"); // size in bytes: newCap * 32 + auto bytes = m_builder.CreateBitCast(data, Type::BytePtr, "bytes"); + auto newBytes = m_builder.CreateCall2(reallocFunc, bytes, reallocSize, "newBytes"); + auto newData = m_builder.CreateBitCast(newBytes, Type::WordPtr, "newData"); + m_builder.CreateStore(newData, dataPtr); + m_builder.CreateStore(newCap, capPtr); + m_builder.CreateBr(pushBB); + + m_builder.SetInsertPoint(pushBB); + auto dataPhi = m_builder.CreatePHI(Type::WordPtr, 2, "dataPhi"); + dataPhi->addIncoming(data, entryBB); + dataPhi->addIncoming(newData, reallocBB); + auto newElemPtr = m_builder.CreateGEP(dataPhi, size, "newElemPtr"); + m_builder.CreateStore(value, newElemPtr); + auto newSize = m_builder.CreateNUWAdd(size, m_builder.getInt64(1), "newSize"); + m_builder.CreateStore(newSize, sizePtr); + m_builder.CreateRetVoid(); + + return func; } -void Stack::set(size_t _index, llvm::Value* _value) +llvm::Function* Array::createArraySetFunc() { - m_builder.CreateStore(_value, m_arg); - m_builder.CreateCall3(m_set, m_runtimeManager.getRuntimePtr(), llvm::ConstantInt::get(Type::Size, _index, false), m_arg); + llvm::Type* argTypes[] = {m_array->getType(), Type::Size, Type::Word}; + auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "array.set", getModule()); + func->setDoesNotThrow(); + func->setDoesNotCapture(1); + + auto arrayPtr = &func->getArgumentList().front(); + arrayPtr->setName("arrayPtr"); + auto index = arrayPtr->getNextNode(); + index->setName("index"); + auto value = index->getNextNode(); + value->setName("value"); + + InsertPointGuard guard{m_builder}; + m_builder.SetInsertPoint(llvm::BasicBlock::Create(m_builder.getContext(), {}, func)); + auto dataPtr = m_builder.CreateStructGEP(arrayPtr, 0, "dataPtr"); + auto data = m_builder.CreateLoad(dataPtr, "data"); + auto valuePtr = m_builder.CreateGEP(data, index, "valuePtr"); + m_builder.CreateStore(value, valuePtr); + m_builder.CreateRetVoid(); + return func; } -void Stack::pop(size_t _count) +llvm::Function* Array::createArrayGetFunc() { - m_builder.CreateCall2(m_pop, m_runtimeManager.getRuntimePtr(), llvm::ConstantInt::get(Type::Size, _count, false)); + llvm::Type* argTypes[] = {m_array->getType(), Type::Size}; + auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "array.get", getModule()); + func->setDoesNotThrow(); + func->setDoesNotCapture(1); + + auto arrayPtr = &func->getArgumentList().front(); + arrayPtr->setName("arrayPtr"); + auto index = arrayPtr->getNextNode(); + index->setName("index"); + + InsertPointGuard guard{m_builder}; + m_builder.SetInsertPoint(llvm::BasicBlock::Create(m_builder.getContext(), {}, func)); + auto dataPtr = m_builder.CreateStructGEP(arrayPtr, 0, "dataPtr"); + auto data = m_builder.CreateLoad(dataPtr, "data"); + auto valuePtr = m_builder.CreateGEP(data, index, "valuePtr"); + auto value = m_builder.CreateLoad(valuePtr, "value"); + m_builder.CreateRet(value); + return func; } -void Stack::push(llvm::Value* _value) +llvm::Function* Array::createFreeFunc() { - m_builder.CreateStore(_value, m_arg); - m_builder.CreateCall2(m_push, m_runtimeManager.getRuntimePtr(), m_arg); -} + auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, m_array->getType(), false), llvm::Function::PrivateLinkage, "array.free", getModule()); + func->setDoesNotThrow(); + func->setDoesNotCapture(1); + auto freeFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, Type::BytePtr, false), llvm::Function::ExternalLinkage, "ext_free", getModule()); + freeFunc->setDoesNotThrow(); + freeFunc->setDoesNotCapture(1); -size_t Stack::maxStackSize = 0; + auto arrayPtr = &func->getArgumentList().front(); + arrayPtr->setName("arrayPtr"); + InsertPointGuard guard{m_builder}; + m_builder.SetInsertPoint(llvm::BasicBlock::Create(m_builder.getContext(), {}, func)); + auto dataPtr = m_builder.CreateStructGEP(arrayPtr, 0, "dataPtr"); + auto data = m_builder.CreateLoad(dataPtr, "data"); + auto mem = m_builder.CreateBitCast(data, Type::BytePtr, "mem"); + m_builder.CreateCall(freeFunc, mem); + m_builder.CreateRetVoid(); + return func; } + +Array::Array(llvm::IRBuilder<>& _builder, char const* _name) : + CompilerHelper(_builder), + m_pushFunc([this](){ return createArrayPushFunc(); }), + m_setFunc([this](){ return createArraySetFunc(); }), + m_getFunc([this](){ return createArrayGetFunc(); }), + m_freeFunc([this](){ return createFreeFunc(); }) +{ + llvm::Type* elementTys[] = {Type::WordPtr, Type::Size, Type::Size}; + static auto arrayTy = llvm::StructType::create(elementTys, "Array"); + + m_array = m_builder.CreateAlloca(arrayTy, nullptr, _name); + m_builder.CreateStore(llvm::ConstantAggregateZero::get(arrayTy), m_array); } + +void Array::pop(llvm::Value* _count) +{ + auto sizePtr = m_builder.CreateStructGEP(m_array, 1, "sizePtr"); + auto size = m_builder.CreateLoad(sizePtr, "size"); + auto newSize = m_builder.CreateNUWSub(size, _count, "newSize"); + m_builder.CreateStore(newSize, sizePtr); } -extern "C" +llvm::Value* Array::size() { - using namespace dev::eth::jit; + auto sizePtr = m_builder.CreateStructGEP(m_array, 1, "sizePtr"); + return m_builder.CreateLoad(sizePtr, "array.size"); +} - EXPORT void stack_pop(Runtime* _rt, uint64_t _count) +Stack::Stack(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager): + CompilerHelper(_builder), + m_runtimeManager(_runtimeManager), + m_stack(_builder, "stack") +{} + +llvm::Function* Stack::getPushFunc() +{ + auto& func = m_push; + if (!func) { - auto& stack = _rt->getStack(); - if (stack.size() < _count) - longjmp(_rt->getJmpBuf(), static_cast(ReturnCode::StackTooSmall)); + llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Word}; + func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::ExternalLinkage, "stack.push", getModule()); + llvm::Type* extArgTypes[] = {Type::RuntimePtr, Type::WordPtr}; + auto extPushFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, extArgTypes, false), llvm::Function::ExternalLinkage, "stack_push", getModule()); + + auto rt = &func->getArgumentList().front(); + rt->setName("rt"); + auto value = rt->getNextNode(); + value->setName("value"); - stack.erase(stack.end() - _count, stack.end()); + InsertPointGuard guard{m_builder}; + auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), {}, func); + m_builder.SetInsertPoint(entryBB); + auto a = m_builder.CreateAlloca(Type::Word); + m_builder.CreateStore(value, a); + createCall(extPushFunc, {rt, a}); + m_builder.CreateRetVoid(); } + return func; +} - EXPORT void stack_push(Runtime* _rt, i256 const* _word) +llvm::Function* Stack::getSetFunc() +{ + auto& func = m_set; + if (!func) { - auto& stack = _rt->getStack(); - stack.push_back(*_word); + llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Size, Type::Word}; + func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::ExternalLinkage, "stack.set", getModule()); + llvm::Type* extArgTypes[] = {Type::RuntimePtr, Type::Size, Type::WordPtr}; + auto extSetFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, extArgTypes, false), llvm::Function::ExternalLinkage, "stack_set", getModule()); + + auto rt = &func->getArgumentList().front(); + rt->setName("rt"); + auto index = rt->getNextNode(); + index->setName("index"); + auto value = index->getNextNode(); + value->setName("value"); - if (stack.size() > Stack::maxStackSize) - Stack::maxStackSize = stack.size(); + InsertPointGuard guard{m_builder}; + auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), {}, func); + m_builder.SetInsertPoint(entryBB); + auto a = m_builder.CreateAlloca(Type::Word); + m_builder.CreateStore(value, a); + createCall(extSetFunc, {rt, index, a}); + m_builder.CreateRetVoid(); } + return func; +} - EXPORT void stack_get(Runtime* _rt, uint64_t _index, i256* o_ret) +llvm::Function* Stack::getPopFunc() +{ + auto& func = m_pop; + if (!func) { - auto& stack = _rt->getStack(); - // TODO: encode _index and stack size in the return code - if (stack.size() <= _index) - longjmp(_rt->getJmpBuf(), static_cast(ReturnCode::StackTooSmall)); + llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Size, Type::BytePtr}; + func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::ExternalLinkage, "stack.pop", getModule()); + llvm::Type* extArgTypes[] = {Type::RuntimePtr, Type::Size}; + auto extPopFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Bool, extArgTypes, false), llvm::Function::ExternalLinkage, "stack_pop", getModule()); + + auto rt = &func->getArgumentList().front(); + rt->setName("rt"); + auto index = rt->getNextNode(); + index->setName("index"); + auto jmpBuf = index->getNextNode(); + jmpBuf->setName("jmpBuf"); + + InsertPointGuard guard{m_builder}; + auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), {}, func); + auto underflowBB = llvm::BasicBlock::Create(m_builder.getContext(), "Underflow", func); + auto returnBB = llvm::BasicBlock::Create(m_builder.getContext(), "Return", func); - *o_ret = *(stack.rbegin() + _index); + m_builder.SetInsertPoint(entryBB); + auto ok = createCall(extPopFunc, {rt, index}); + m_builder.CreateCondBr(ok, returnBB, underflowBB); //TODO: Add branch weight + + m_builder.SetInsertPoint(underflowBB); + m_runtimeManager.abort(jmpBuf); + m_builder.CreateUnreachable(); + + m_builder.SetInsertPoint(returnBB); + m_builder.CreateRetVoid(); } + return func; +} - EXPORT void stack_set(Runtime* _rt, uint64_t _index, i256 const* _word) +llvm::Function* Stack::getGetFunc() +{ + auto& func = m_get; + if (!func) { - auto& stack = _rt->getStack(); - // TODO: encode _index and stack size in the return code - if (stack.size() <= _index) - longjmp(_rt->getJmpBuf(), static_cast(ReturnCode::StackTooSmall)); + llvm::Type* argTypes[] = {Type::Size, Type::Size, Type::BytePtr}; + func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::ExternalLinkage, "stack.require", getModule()); + + auto index = &func->getArgumentList().front(); + index->setName("index"); + auto size = index->getNextNode(); + size->setName("size"); + auto jmpBuf = size->getNextNode(); + jmpBuf->setName("jmpBuf"); - *(stack.rbegin() + _index) = *_word; + InsertPointGuard guard{m_builder}; + auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), {}, func); + auto underflowBB = llvm::BasicBlock::Create(m_builder.getContext(), "Underflow", func); + auto returnBB = llvm::BasicBlock::Create(m_builder.getContext(), "Return", func); + + m_builder.SetInsertPoint(entryBB); + auto underflow = m_builder.CreateICmpUGE(index, size, "underflow"); + m_builder.CreateCondBr(underflow, underflowBB, returnBB); + + m_builder.SetInsertPoint(underflowBB); + m_runtimeManager.abort(jmpBuf); + m_builder.CreateUnreachable(); + + m_builder.SetInsertPoint(returnBB); + m_builder.CreateRetVoid(); } + return func; +} + +llvm::Value* Stack::get(size_t _index) +{ + createCall(getGetFunc(), {m_builder.getInt64(_index), m_stack.size(), m_runtimeManager.getJmpBuf()}); + auto value = m_stack.get(m_builder.CreateSub(m_stack.size(), m_builder.getInt64(_index + 1))); + //return m_builder.CreateLoad(valuePtr); + return value; +} + +void Stack::set(size_t _index, llvm::Value* _value) +{ + m_stack.set(m_builder.CreateSub(m_stack.size(), m_builder.getInt64(_index + 1)), _value); + //createCall(getSetFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_index), _value}); +} + +void Stack::pop(size_t _count) +{ + // FIXME: Pop does not check for stack underflow but looks like not needed + // We should place stack.require() check and begining of every BB + m_stack.pop(m_builder.getInt64(_count)); + //createCall(getPopFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_count), m_runtimeManager.getJmpBuf()}); +} + +void Stack::push(llvm::Value* _value) +{ + m_stack.push(_value); + //createCall(getPushFunc(), {m_runtimeManager.getRuntimePtr(), _value}); +} + +} +} +} + +namespace +{ + struct AllocatedMemoryWatchdog + { + std::set allocatedMemory; + + ~AllocatedMemoryWatchdog() + { + if (!allocatedMemory.empty()) + DLOG(mem) << allocatedMemory.size() << " MEM LEAKS!\n"; + } + }; + + AllocatedMemoryWatchdog watchdog; +} + +extern "C" +{ + using namespace dev::eth::jit; EXPORT void ext_calldataload(RuntimeData* _rtData, i256* _index, byte* o_value) { @@ -129,5 +386,28 @@ extern "C" } } + EXPORT void* ext_realloc(void* _data, size_t _size) + { + //std::cerr << "REALLOC: " << _data << " [" << _size << "]" << std::endl; + auto newData = std::realloc(_data, _size); + if (_data != newData) + { + DLOG(mem) << "REALLOC: " << _data << " -> " << newData << " [" << _size << "]\n"; + watchdog.allocatedMemory.erase(_data); + watchdog.allocatedMemory.insert(newData); + } + return newData; + } + + EXPORT void ext_free(void* _data) + { + std::free(_data); + if (_data) + { + DLOG(mem) << "FREE : " << _data << "\n"; + watchdog.allocatedMemory.erase(_data); + } + } + } // extern "C" diff --git a/libevmjit/Stack.h b/libevmjit/Stack.h index 3e8881e4f..ac64d427e 100644 --- a/libevmjit/Stack.h +++ b/libevmjit/Stack.h @@ -1,8 +1,8 @@ #pragma once -#include "CompilerHelper.h" +#include -#include +#include "CompilerHelper.h" namespace dev { @@ -12,6 +12,50 @@ namespace jit { class RuntimeManager; +class LazyFunction +{ +public: + using Creator = std::function; + + LazyFunction(Creator _creator) : + m_creator(_creator) + {} + + llvm::Value* call(llvm::IRBuilder<>& _builder, std::initializer_list const& _args); + +private: + llvm::Function* m_func = nullptr; + Creator m_creator; +}; + +class Array : public CompilerHelper +{ +public: + Array(llvm::IRBuilder<>& _builder, char const* _name); + + void push(llvm::Value* _value) { m_pushFunc.call(m_builder, {m_array, _value}); } + void set(llvm::Value* _index, llvm::Value* _value) { m_setFunc.call(m_builder, {m_array, _index, _value}); } + llvm::Value* get(llvm::Value* _index) { return m_getFunc.call(m_builder, {m_array, _index}); } + void pop(llvm::Value* _count); + llvm::Value* size(); + void free() { m_freeFunc.call(m_builder, {m_array}); } + + llvm::Value* getPointerTo() const { return m_array; } + +private: + llvm::Value* m_array = nullptr; + + LazyFunction m_pushFunc; + LazyFunction m_setFunc; + LazyFunction m_getFunc; + LazyFunction m_freeFunc; + + llvm::Function* createArrayPushFunc(); + llvm::Function* createArraySetFunc(); + llvm::Function* createArrayGetFunc(); + llvm::Function* createFreeFunc(); +}; + class Stack : public CompilerHelper { public: @@ -21,18 +65,22 @@ public: void set(size_t _index, llvm::Value* _value); void pop(size_t _count); void push(llvm::Value* _value); - - static size_t maxStackSize; + void free() { m_stack.free(); } private: + llvm::Function* getPopFunc(); + llvm::Function* getPushFunc(); + llvm::Function* getGetFunc(); + llvm::Function* getSetFunc(); + RuntimeManager& m_runtimeManager; - llvm::Function* m_push; - llvm::Function* m_pop; - llvm::Function* m_get; - llvm::Function* m_set; + llvm::Function* m_pop = nullptr; + llvm::Function* m_push = nullptr; + llvm::Function* m_get = nullptr; + llvm::Function* m_set = nullptr; - llvm::Value* m_arg; + Array m_stack; }; diff --git a/libevmjit/Type.cpp b/libevmjit/Type.cpp index 22ccea12e..8e2bc13fc 100644 --- a/libevmjit/Type.cpp +++ b/libevmjit/Type.cpp @@ -1,8 +1,4 @@ - #include "Type.h" - -#include - #include "RuntimeManager.h" namespace dev @@ -17,6 +13,8 @@ llvm::PointerType* Type::WordPtr; llvm::IntegerType* Type::lowPrecision; llvm::IntegerType* Type::Bool; llvm::IntegerType* Type::Size; +llvm::IntegerType* Type::Gas; +llvm::PointerType* Type::GasPtr; llvm::IntegerType* Type::Byte; llvm::PointerType* Type::BytePtr; llvm::Type* Type::Void; @@ -24,6 +22,7 @@ llvm::IntegerType* Type::MainReturn; llvm::PointerType* Type::EnvPtr; llvm::PointerType* Type::RuntimeDataPtr; llvm::PointerType* Type::RuntimePtr; +llvm::ConstantInt* Constant::gasMax; void Type::init(llvm::LLVMContext& _context) { @@ -35,6 +34,8 @@ void Type::init(llvm::LLVMContext& _context) // TODO: Size should be architecture-dependent Bool = llvm::Type::getInt1Ty(_context); Size = llvm::Type::getInt64Ty(_context); + Gas = Size; + GasPtr = Gas->getPointerTo(); Byte = llvm::Type::getInt8Ty(_context); BytePtr = Byte->getPointerTo(); Void = llvm::Type::getVoidTy(_context); @@ -43,6 +44,8 @@ void Type::init(llvm::LLVMContext& _context) EnvPtr = llvm::StructType::create(_context, "Env")->getPointerTo(); RuntimeDataPtr = RuntimeManager::getRuntimeDataType()->getPointerTo(); RuntimePtr = RuntimeManager::getRuntimeType()->getPointerTo(); + + Constant::gasMax = llvm::ConstantInt::getSigned(Type::Gas, std::numeric_limits::max()); } } diff --git a/libevmjit/Type.h b/libevmjit/Type.h index d4804ee59..b8a4a09eb 100644 --- a/libevmjit/Type.h +++ b/libevmjit/Type.h @@ -1,8 +1,10 @@ - #pragma once +#include "preprocessor/llvm_includes_start.h" #include -#include +#include +#include "preprocessor/llvm_includes_end.h" + #include "Common.h" namespace dev @@ -23,6 +25,8 @@ struct Type static llvm::IntegerType* Bool; static llvm::IntegerType* Size; + static llvm::IntegerType* Gas; + static llvm::PointerType* GasPtr; static llvm::IntegerType* Byte; static llvm::PointerType* BytePtr; @@ -41,6 +45,8 @@ struct Type struct Constant { + static llvm::ConstantInt* gasMax; + /// Returns word-size constant static llvm::ConstantInt* get(int64_t _n); static llvm::ConstantInt* get(llvm::APInt const& _n); diff --git a/libevmjit/Utils.cpp b/libevmjit/Utils.cpp index 5f7f75bfd..3644def04 100644 --- a/libevmjit/Utils.cpp +++ b/libevmjit/Utils.cpp @@ -1,14 +1,21 @@ - #include "Utils.h" +#include + +#if !defined(NDEBUG) // Debug + namespace dev { -namespace eth -{ -namespace jit +namespace evmjit { - +std::ostream& getLogStream(char const* _channel) +{ + static std::ostream nullStream{nullptr}; + return (llvm::DebugFlag && llvm::isCurrentDebugType(_channel)) ? std::cerr : nullStream; } + } } + +#endif diff --git a/libevmjit/Utils.h b/libevmjit/Utils.h index 1e6705667..0caf5e1bd 100644 --- a/libevmjit/Utils.h +++ b/libevmjit/Utils.h @@ -1,19 +1,40 @@ #pragma once -#include "Common.h" +#include + +// The same as assert, but expression is always evaluated and result returned +#define CHECK(expr) (assert(expr), expr) + +#if !defined(NDEBUG) // Debug namespace dev { -namespace eth -{ -namespace jit +namespace evmjit { -struct JIT: public NoteChannel { static const char* name() { return "JIT"; } }; - -//#define clog(CHANNEL) std::cerr -#define clog(CHANNEL) std::ostream(nullptr) +std::ostream& getLogStream(char const* _channel); } } + +#define DLOG(CHANNEL) ::dev::evmjit::getLogStream(#CHANNEL) + +#else // Release + +namespace dev +{ +namespace evmjit +{ + +struct Voider +{ + void operator=(std::ostream const&) {} +}; + } +} + + +#define DLOG(CHANNEL) true ? (void)0 : ::dev::evmjit::Voider{} = std::cerr + +#endif diff --git a/libevmjit/interface.cpp b/libevmjit/interface.cpp index 6b0992dd4..645f3d150 100644 --- a/libevmjit/interface.cpp +++ b/libevmjit/interface.cpp @@ -12,6 +12,7 @@ using namespace dev::eth::jit; EXPORT void* evmjit_create() noexcept { + // TODO: Make sure ExecutionEngine constructor does not throw return new(std::nothrow) ExecutionEngine; } @@ -22,14 +23,12 @@ EXPORT void evmjit_destroy(ExecutionEngine* _engine) noexcept EXPORT int evmjit_run(ExecutionEngine* _engine, RuntimeData* _data, Env* _env) noexcept { + if (!_engine || !_data) + return static_cast(ReturnCode::UnexpectedException); + try { - auto codePtr = _data->code; - auto codeSize = _data->codeSize; - bytes bytecode; - bytecode.insert(bytecode.end(), codePtr, codePtr + codeSize); - - auto returnCode = _engine->run(bytecode, _data, _env); + auto returnCode = _engine->run(_data, _env); return static_cast(returnCode); } catch(...) diff --git a/libevmjit/preprocessor/llvm_includes_end.h b/libevmjit/preprocessor/llvm_includes_end.h new file mode 100644 index 000000000..2ead6dda3 --- /dev/null +++ b/libevmjit/preprocessor/llvm_includes_end.h @@ -0,0 +1,7 @@ +#if defined(_MSC_VER) + #pragma warning(pop) +#elif defined(__clang__) + #pragma clang diagnostic pop +#else + #pragma GCC diagnostic pop +#endif diff --git a/libevmjit/preprocessor/llvm_includes_start.h b/libevmjit/preprocessor/llvm_includes_start.h new file mode 100644 index 000000000..9077bf43f --- /dev/null +++ b/libevmjit/preprocessor/llvm_includes_start.h @@ -0,0 +1,12 @@ +#if defined(_MSC_VER) + #pragma warning(push) + #pragma warning(disable: 4267 4244 4800) +#elif defined(__clang__) + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wunused-parameter" + #pragma clang diagnostic ignored "-Wconversion" +#else + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wunused-parameter" + #pragma GCC diagnostic ignored "-Wconversion" +#endif