diff --git a/nimbus/vm2/interpreter/op_codes.nim b/nimbus/vm2/interpreter/op_codes.nim new file mode 100644 index 000000000..eb3f4420f --- /dev/null +++ b/nimbus/vm2/interpreter/op_codes.nim @@ -0,0 +1,250 @@ +# Nimbus +# Copyright (c) 2018 Status Research & Development GmbH +# Licensed under either of +# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or +# http://www.apache.org/licenses/LICENSE-2.0) +# * MIT license ([LICENSE-MIT](LICENSE-MIT) or +# http://opensource.org/licenses/MIT) +# at your option. This file may not be copied, modified, or +# distributed except according to those terms. + +## Yellow Paper Appendix H - +## https://ethereum.github.io/yellowpaper/paper.pdf +## +## Special notes from Yellow Paper: +## - Signed values are treated as two’s complement signed 256-bit +## integers. +## - When −2^255 is negated, there is an overflow +## - For addmod and mulmod, intermediate computations are not subject to +## the 2^256 modulo. +## +## Nimbus authors note: +## - This means that we can't naively do (Uint256 + Uint256) mod uint256, +## because the intermediate sum (or multiplication) might roll over if +## intermediate result is greater or equal 2^256 + +type + Op* = enum + # 0s: Stop and Arithmetic Operations + Stop = 0x00, ## Halts execution. + Add = 0x01, ## Addition operation. + Mul = 0x02, ## Multiplication operation. + Sub = 0x03, ## Subtraction operation. + Div = 0x04, ## Integer division operation. + Sdiv = 0x05, ## Signed integer division operation (truncated). + Mod = 0x06, ## Modulo remainder operation. + Smod = 0x07, ## Signed modulo remainder operation. + Addmod = 0x08, ## Modulo addition operation. + Mulmod = 0x09, ## Modulo multiplication operation. + Exp = 0x0A, ## Exponentiation operation + SignExtend = 0x0B, ## Extend length of two’s complement signed + ## integer. + + Nop0x0C, Nop0x0D, Nop0x0E, Nop0x0F, ## .. + + # 10s: Comparison & Bitwise Logic Operations + Lt = 0x10, ## Less-than comparison. + Gt = 0x11, ## Greater-than comparison. + Slt = 0x12, ## Signed less-than comparison. + Sgt = 0x13, ## Signed greater-than comparison. + Eq = 0x14, ## Equality comparison. + IsZero = 0x15, ## Simple not operator. (Note: real Yellow Paper + ## description) + And = 0x16, ## Bitwise AND operation. + Or = 0x17, ## Bitwise OR operation. + Xor = 0x18, ## Bitwise XOR operation. + Not = 0x19, ## Bitwise NOT operation. + Byte = 0x1A, ## Retrieve single byte from word. + Shl = 0x1B, ## Shift left + Shr = 0x1C, ## Logical shift right + Sar = 0x1D, ## Arithmetic shift right + + Nop0x1E, Nop0x1F, ## .. + + # 20s: SHA3 + Sha3 = 0x20, ## Compute Keccak-256 hash. + + Nop0x21, Nop0x22, Nop0x23, Nop0x24, Nop0x25, Nop0x26, + Nop0x27, Nop0x28, Nop0x29, Nop0x2A, Nop0x2B, Nop0x2C, + Nop0x2D, Nop0x2E, Nop0x2F, ## .. + + # 30s: Environmental Information + Address = 0x30, ## Get address of currently executing account. + Balance = 0x31, ## Get balance of the given account. + Origin = 0x32, ## Get execution origination address. + Caller = 0x33, ## Get caller address. + CallValue = 0x34, ## Get deposited value by the + ## instruction/transaction responsible for this + ## execution. + CallDataLoad = 0x35, ## Get input data of current environment. + CallDataSize = 0x36, ## Get size of input data in current environment. + CallDataCopy = 0x37, ## Copy input data in current environment to + ## memory. + CodeSize = 0x38, ## Get size of code running in current environment. + CodeCopy = 0x39, ## Copy code running in current environment to + ## memory. + GasPrice = 0x3a, ## Get price of gas in current environment. + ExtCodeSize = 0x3b, ## Get size of an account's code + ExtCodeCopy = 0x3c, ## Copy an account's code to memory. + ReturnDataSize = 0x3d, ## Get size of output data from the previous call + ## from the current environment. + ReturnDataCopy = 0x3e, ## Copy output data from the previous call to + ## memory. + ExtCodeHash = 0x3f, ## Returns the keccak256 hash of a contract’s code + + # 40s: Block Information + Blockhash = 0x40, ## Get the hash of one of the 256 most recent + ## complete blocks. + Coinbase = 0x41, ## Get the block's beneficiary address. + Timestamp = 0x42, ## Get the block's timestamp. + Number = 0x43, ## Get the block's number. + Difficulty = 0x44, ## Get the block's difficulty. + GasLimit = 0x45, ## Get the block's gas limit. + + ChainId = 0x46, ## Get current chain’s EIP-155 unique identifier. + SelfBalance = 0x47, ## Get current contract's balance. + + Nop0x48, Nop0x49, Nop0x4A, Nop0x4B, Nop0x4C, Nop0x4D, + Nop0x4E, Nop0x4F, ## .. + + # 50s: Stack, Memory, Storage and Flow Operations + Pop = 0x50, ## Remove item from stack. + Mload = 0x51, ## Load word from memory. + Mstore = 0x52, ## Save word to memory. + Mstore8 = 0x53, ## Save byte to memory. + Sload = 0x54, ## Load word from storage. + Sstore = 0x55, ## Save word to storage. + Jump = 0x56, ## Alter the program counter. + JumpI = 0x57, ## Conditionally alter the program counter. + Pc = 0x58, ## Get the value of the program counter prior to + ## the increment corresponding to this instruction. + Msize = 0x59, ## Get the size of active memory in bytes. + Gas = 0x5a, ## Get the amount of available gas, including the + ## corresponding reduction for the cost of this + ## instruction. + JumpDest = 0x5b, ## Mark a valid destination for jumps. This + ## operation has no effect on machine state during + ## execution. + BeginSub = 0x5c, ## Marks the entry point to a subroutine + ReturnSub = 0x5d, ## Returns control to the caller of a subroutine. + JumpSub = 0x5e, ## Transfers control to a subroutine. + Nop0x5F = 0x5f, ## .. + + # 60s & 70s: Push Operations. + Push1 = 0x60, ## Place 1-byte item on stack. + Push2 = 0x61, ## Place 2-byte item on stack. + + Push3, Push4, Push5, Push6, Push7, Push8, + Push9, Push10, Push11, Push12, Push13, Push14, + Push15, Push16, Push17, Push18, Push19, Push20, + Push21, Push22, Push23, Push24, Push25, Push26, + Push27, Push28, Push29, Push30, Push31, ## .. + + Push32 = 0x7f, ## Place 32-byte (full word) item on stack. + + # 80s: Duplication Operations + Dup1 = 0x80, ## Duplicate 1st stack item. + Dup2 = 0x81, ## Duplicate 2nd stack item. + + Dup3, Dup4, Dup5, Dup6, Dup7, Dup8, + Dup9, Dup10, Dup11, Dup12, Dup13, Dup14, + Dup15, ## .. + + Dup16 = 0x8f, ## Duplicate 16th stack item. + + # 90s: Exchange Operations + Swap1 = 0x90, ## Exchange 1st and 2nd stack items. + Swap2 = 0x91, ## Exchange 1st and 3rd stack items. + + Swap3, Swap4, Swap5, Swap6, Swap7, Swap8, + Swap9, Swap10, Swap11, Swap12, Swap13, Swap14, + Swap15, ## .. + + Swap16 = 0x9f, ## Exchange 1st and 17th stack items. + + # a0s: Logging Operations + Log0 = 0xa0, ## Append log record with no topics. + Log1 = 0xa1, ## Append log record with one topics. + + Log2, Log3, ## .. + + Log4 = 0xa4, ## Append log record with four topics. + + Nop0xA5, Nop0xA6, Nop0xA7, Nop0xA8, Nop0xA9, Nop0xAA, + Nop0xAB, Nop0xAC, Nop0xAD, Nop0xAE, Nop0xAF, Nop0xB0, + Nop0xB1, Nop0xB2, Nop0xB3, Nop0xB4, Nop0xB5, Nop0xB6, + Nop0xB7, Nop0xB8, Nop0xB9, Nop0xBA, Nop0xBB, Nop0xBC, + Nop0xBD, Nop0xBE, Nop0xBF, Nop0xC0, Nop0xC1, Nop0xC2, + Nop0xC3, Nop0xC4, Nop0xC5, Nop0xC6, Nop0xC7, Nop0xC8, + Nop0xC9, Nop0xCA, Nop0xCB, Nop0xCC, Nop0xCD, Nop0xCE, + Nop0xCF, Nop0xD0, Nop0xD1, Nop0xD2, Nop0xD3, Nop0xD4, + Nop0xD5, Nop0xD6, Nop0xD7, Nop0xD8, Nop0xD9, Nop0xDA, + Nop0xDB, Nop0xDC, Nop0xDD, Nop0xDE, Nop0xDF, Nop0xE0, + Nop0xE1, Nop0xE2, Nop0xE3, Nop0xE4, Nop0xE5, Nop0xE6, + Nop0xE7, Nop0xE8, Nop0xE9, Nop0xEA, Nop0xEB, Nop0xEC, + Nop0xED, Nop0xEE, Nop0xEF, ## .. + + # f0s: System operations + Create = 0xf0, ## Create a new account with associated code. + Call = 0xf1, ## Message-call into an account. + CallCode = 0xf2, ## Message-call into this account with an + ## alternative account's code. + Return = 0xf3, ## Halt execution returning output data. + DelegateCall = 0xf4, ## Message-call into this account with an + ## alternative account's code, but persisting the + ## current values for sender and value. + Create2 = 0xf5, ## Behaves identically to CREATE, except using + ## keccak256( 0xff ++ address ++ salt ++ + ## keccak256(init_code))[12:] + + Nop0xF6, Nop0xF7, Nop0xF8, Nop0xF9, ## .. + + StaticCall = 0xfa, ## Static message-call into an account. + + Nop0xFB, Nop0xFC, ## .. + + Revert = 0xfd, ## Halt execution reverting state changes but + ## returning data and remaining gas. + Invalid = 0xfe, ## Designated invalid instruction. + SelfDestruct = 0xff ## Halt execution and register account for later + ## deletion. + +# ------------------------------------------------------------------------------ +# Verify that Op is contiguous and sym names follow some standards +# ------------------------------------------------------------------------------ + +import strutils, sequtils +static: + type Vfy = enum + VfyStop = 0x00, + VfySelfDestruct = 0xff + + const + allowedChars = {'A'..'Z', 'a'..'z', '0'..'9'} + + # Enum holes look like: "Op 123" (space triggers error) + proc badSymNames(a: openArray[string]): seq[string] = + toSeq(a).filterIt(it.len < 2 or + not it[0].isUpperAscii or + it.count(allowedChars) < it.len) + + const + vfySymNames = toSeq(0 .. 255).mapIt($it.Vfy).badSymNames + opSymNames = toSeq(0 .. 255).mapIt($it.Op).badSymNames + + # control test, values 1..254 must be rejected + when vfySymNames.len != 254: + static: + echo "*** Got only ", vfySymNames.len, + " rejected Vfy enum symbols (expected 254)" + {.fatal: "Compiler logic might have changed -- please fix"} + + # verify Op enum/table + when 0 < opSymNames.len: + static: + echo "*** Unexpected enum symbols: \"", opSymNames.join("\", "), '"' + {.fatal: "Probably holes in Op enum -- please fix"} + +# ------------------------------------------------------------------------------ +# End +# ------------------------------------------------------------------------------ diff --git a/nimbus/vm2/interpreter/utils/macros_gen_opcodes.nim b/nimbus/vm2/interpreter/utils/macros_gen_opcodes.nim index 1a48d2cd4..f1de368d9 100644 --- a/nimbus/vm2/interpreter/utils/macros_gen_opcodes.nim +++ b/nimbus/vm2/interpreter/utils/macros_gen_opcodes.nim @@ -8,79 +8,7 @@ # ################################################################## # Macros to facilitate opcode enum and table creation -import macros, strformat, strutils - -# Due to https://github.com/nim-lang/Nim/issues/8007, we can't -# use compile-time Tables of object variants, so instead, we use -# const arrays to map Op --> gas prices. -# Arrays require an enum without hole. This macro will fill the holes -# in the enum. - -# This has an added benefits that we can use computed gotos (direct threaded interpreter) -# instead of call or subroutine threading to dispatch opcode. -# see: https://github.com/nim-lang/Nim/issues/7699 (computed gotos, bad codegen with enum with holes) -# see: https://github.com/status-im/nimbus/wiki/Interpreter-optimization-resources -# for interpreter dispatch strategies - -macro fill_enum_holes*(body: untyped): untyped = - ## Fill the holes of an enum - ## For example - ## type Foo = enum - ## A = 0x00, - ## B = 0x10 - - # Sanity checks - # - # StmtList - # TypeSection - # TypeDef - # PragmaExpr - # Postfix - # Ident "*" - # Ident "Op" - # Pragma - # Ident "pure" - # Empty - # EnumTy - # Empty - # EnumFieldDef - # Ident "Stop" - # IntLit 0 - # EnumFieldDef - # Ident "Add" - # IntLit 1 - body[0].expectKind(nnkTypeSection) - body[0][0][2].expectKind(nnkEnumTy) - - let opcodes = body[0][0][2] - - # We will iterate over all the opcodes - # check if the i-th value is declared, if not add a no-op - # and accumulate that in a "dense opcodes" declaration - - var - opcode = 0 - holes_idx = 1 - dense_opcs = nnkEnumTy.newTree() - dense_opcs.add newEmptyNode() - - # Iterate on the enum with holes - while holes_idx < opcodes.len: - let curr_ident = opcodes[holes_idx] - - if curr_ident.kind in {nnkIdent, nnkEmpty} or - (curr_ident.kind == nnkEnumFieldDef and - curr_ident[1].intVal == opcode): - - dense_opcs.add curr_ident - inc holes_idx - else: - dense_opcs.add newIdentNode(&"Nop0x{opcode.toHex(2)}") - - inc opcode - - result = body - result[0][0][2] = dense_opcs +import macros macro fill_enum_table_holes*(enumTy: typedesc[enum], nop_filler, body: untyped): untyped = ## Fill the holes of table mapping for enum with a default value diff --git a/nimbus/vm2/interpreter/v2opcode_values.nim b/nimbus/vm2/interpreter/v2opcode_values.nim index 0c99356d6..aabc2a4a9 100644 --- a/nimbus/vm2/interpreter/v2opcode_values.nim +++ b/nimbus/vm2/interpreter/v2opcode_values.nim @@ -5,190 +5,8 @@ # * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) # at your option. This file may not be copied, modified, or distributed except according to those terms. -when not defined(vm2_enabled): - {.fatal: "Flags \"vm2_enabled\" must be defined"} when defined(evmc_enabled): {.fatal: "Flags \"evmc_enabled\" and \"vm2_enabled\" are mutually exclusive"} -import ./utils/macros_gen_opcodes - -fill_enum_holes: - type - # Yellow Paper Appendix H - https://ethereum.github.io/yellowpaper/paper.pdf - # Special notes from Yellow Paper: - # - Signed values are treated as two’s complement signed 256-bit integers. - # - When −2^255 is negated, there is an overflow - # - For addmod and mulmod, intermediate computations are not subject to the 2^256 modulo. - # Nimbus authors note: - # - This means that we can't naively do (Uint256 + Uint256) mod uint256, - # because the intermediate sum (or multiplication) might roll over if - # intermediate result is greater or equal 2^256 - - Op* = enum - # 0s: Stop and Arithmetic Operations - Stop = 0x00, # Halts execution. - Add = 0x01, # Addition operation. - Mul = 0x02, # Multiplication operation. - Sub = 0x03, # Subtraction operation. - Div = 0x04, # Integer division operation. - Sdiv = 0x05, # Signed integer division operation (truncated). - Mod = 0x06, # Modulo remainder operation. - Smod = 0x07, # Signed modulo remainder operation. - Addmod = 0x08, # Modulo addition operation. - Mulmod = 0x09, # Modulo multiplication operation. - Exp = 0x0A, # Exponentiation operation - SignExtend = 0x0B, # Extend length of two’s complement signed integer. - - # 10s: Comparison & Bitwise Logic Operations - Lt = 0x10, # Less-than comparison. - Gt = 0x11, # Greater-than comparison. - Slt = 0x12, # Signed less-than comparison. - Sgt = 0x13, # Signed greater-than comparison. - Eq = 0x14, # Equality comparison. - IsZero = 0x15, # Simple not operator. (Note: real Yellow Paper description) - And = 0x16, # Bitwise AND operation. - Or = 0x17, # Bitwise OR operation. - Xor = 0x18, # Bitwise XOR operation. - Not = 0x19, # Bitwise NOT operation. - Byte = 0x1A, # Retrieve single byte from word. - Shl = 0x1B, # Shift left - Shr = 0x1C, # Logical shift right - Sar = 0x1D, # Arithmetic shift right - - # 20s: SHA3 - Sha3 = 0x20, # Compute Keccak-256 hash. - - # 30s: Environmental Information - Address = 0x30, # Get address of currently executing account. - Balance = 0x31, # Get balance of the given account. - Origin = 0x32, # Get execution origination address. - Caller = 0x33, # Get caller address. - CallValue = 0x34, # Get deposited value by the instruction/transaction responsible for this execution. - CallDataLoad = 0x35, # Get input data of current environment. - CallDataSize = 0x36, # Get size of input data in current environment. - CallDataCopy = 0x37, # Copy input data in current environment to memory. - CodeSize = 0x38, # Get size of code running in current environment. - CodeCopy = 0x39, # Copy code running in current environment to memory. - GasPrice = 0x3a, # Get price of gas in current environment. - ExtCodeSize = 0x3b, # Get size of an account's code - ExtCodeCopy = 0x3c, # Copy an account's code to memory. - ReturnDataSize = 0x3d, # Get size of output data from the previous call from the current environment. - ReturnDataCopy = 0x3e, # Copy output data from the previous call to memory. - ExtCodeHash = 0x3f, # Returns the keccak256 hash of a contract’s code - - # 40s: Block Information - Blockhash = 0x40, # Get the hash of one of the 256 most recent complete blocks. - Coinbase = 0x41, # Get the block's beneficiary address. - Timestamp = 0x42, # Get the block's timestamp. - Number = 0x43, # Get the block's number. - Difficulty = 0x44, # Get the block's difficulty. - GasLimit = 0x45, # Get the block's gas limit. - - ChainId = 0x46, # Get current chain’s EIP-155 unique identifier. - SelfBalance = 0x47, # Get current contract's balance. - - # 50s: Stack, Memory, Storage and Flow Operations - Pop = 0x50, # Remove item from stack. - Mload = 0x51, # Load word from memory. - Mstore = 0x52, # Save word to memory. - Mstore8 = 0x53, # Save byte to memory. - Sload = 0x54, # Load word from storage. - Sstore = 0x55, # Save word to storage. - Jump = 0x56, # Alter the program counter. - JumpI = 0x57, # Conditionally alter the program counter. - Pc = 0x58, # Get the value of the program counter prior to the increment corresponding to this instruction. - Msize = 0x59, # Get the size of active memory in bytes. - Gas = 0x5a, # Get the amount of available gas, including the corresponding reduction for the cost of this instruction. - JumpDest = 0x5b, # Mark a valid destination for jumps. This operation has no effect on machine state during execution. - BeginSub = 0x5c, # Marks the entry point to a subroutine - ReturnSub = 0x5d, # Returns control to the caller of a subroutine. - JumpSub = 0x5e, # Transfers control to a subroutine. - - # 60s & 70s: Push Operations. - Push1 = 0x60, # Place 1-byte item on stack. - Push2 = 0x61, # Place 2-byte item on stack. - Push3, - Push4, - Push5, - Push6, - Push7, - Push8, - Push9, - Push10, - Push11, - Push12, - Push13, - Push14, - Push15, - Push16, - Push17, - Push18, - Push19, - Push20, - Push21, - Push22, - Push23, - Push24, - Push25, - Push26, - Push27, - Push28, - Push29, - Push30, - Push31, - Push32 = 0x7f, # Place 32-byte (full word) item on stack. - - # 80s: Duplication Operations - Dup1 = 0x80, # Duplicate 1st stack item. - Dup2 = 0x81, # Duplicate 2nd stack item. - Dup3, - Dup4, - Dup5, - Dup6, - Dup7, - Dup8, - Dup9, - Dup10, - Dup11, - Dup12, - Dup13, - Dup14, - Dup15, - Dup16 = 0x8f, # Duplicate 16th stack item. - - # 90s: Exchange Operations - Swap1 = 0x90, # Exchange 1st and 2nd stack items. - Swap2 = 0x91, # Exchange 1st and 3rd stack items. - Swap3, - Swap4, - Swap5, - Swap6, - Swap7, - Swap8, - Swap9, - Swap10, - Swap11, - Swap12, - Swap13, - Swap14, - Swap15, - Swap16 = 0x9f, # Exchange 1st and 17th stack items. - - # a0s: Logging Operations - Log0 = 0xa0, # Append log record with no topics. - Log1 = 0xa1, # Append log record with one topics. - Log2, - Log3, - Log4 = 0xa4, # Append log record with four topics. - - # f0s: System operations - Create = 0xf0, # Create a new account with associated code. - Call = 0xf1, # Message-call into an account. - CallCode = 0xf2, # Message-call into this account with an alternative account's code. - Return = 0xf3, # Halt execution returning output data. - DelegateCall = 0xf4, # Message-call into this account with an alternative account's code, but persisting the current values for sender and value. - Create2 = 0xf5, # Behaves identically to CREATE, except using keccak256( 0xff ++ address ++ salt ++ keccak256(init_code))[12:] - StaticCall = 0xfa, # Static message-call into an account. - Revert = 0xfd, # Halt execution reverting state changes but returning data and remaining gas. - Invalid = 0xfe, # Designated invalid instruction. - SelfDestruct = 0xff # Halt execution and register account for later deletion. +import ./op_codes +export Op