From 7b5f7e762b8c6d3b3c68dcf39ff4fdfe530dd8d5 Mon Sep 17 00:00:00 2001 From: Alexander Ivanov Date: Tue, 23 Jan 2018 20:36:23 +0200 Subject: [PATCH] WIP opcode dsl, code stream changes --- src/logic/arithmetic.nim | 18 ++- src/opcode.nim | 50 +++++++ src/opcode_values.nim | 277 ++++++++++++++++++++------------------- src/vm/code_stream.nim | 16 +-- 4 files changed, 214 insertions(+), 147 deletions(-) create mode 100644 src/opcode.nim diff --git a/src/logic/arithmetic.nim b/src/logic/arithmetic.nim index 11a105993..e9d5e3dc8 100644 --- a/src/logic/arithmetic.nim +++ b/src/logic/arithmetic.nim @@ -1,6 +1,6 @@ import ../constants, ../utils_numeric, ../computation, - .. / vm / [gas_meter, stack], + .. / vm / [gas_meter, stack], ../opcode, ../opcode_values, helpers, bigints proc add*(computation: var BaseComputation) = @@ -101,3 +101,19 @@ proc signextend(computation: var BaseComputation) = else: res = value pushRes() + +# TODO: why fail +# newOpcode(Op.Mul, GAS_VERY_LOW, mul) + +# type +# OpcodeMul* = ref object of Opcode +# method kind*(opcode247321: OpcodeMul): Op = +# Op.Mul + +# method gasCost*(opcode247323: OpcodeMul): Int256 = +# GAS_VERY_LOW + +# method run*(opcode247325: OpcodeMul; computation: var BaseComputation) = +# computation.gasMeter.consumeGas(GAS_VERY_LOW, reason = $Op.Mul) +# mul(computation) + diff --git a/src/opcode.nim b/src/opcode.nim new file mode 100644 index 000000000..5f4ed1114 --- /dev/null +++ b/src/opcode.nim @@ -0,0 +1,50 @@ +import + strformat, strutils, sequtils, macros, + constants, logging, errors, opcode_values, computation, vm/stack, bigints + +type + Opcode* = ref object of RootObj + +method run*(opcode: var Opcode, computation: var BaseComputation) {.base.} = + # Hook for performing the actual VM execution. + raise newException(ValueError, "Must be implemented by subclasses") + +method kind*(opcode: Opcode): Op {.base.} = + raise newException(ValueError, "Must be implemented by subclasses") + +method gasCost*(opcode: Opcode): Op {.base.} = + raise newException(ValueError, "Must be implemented by subclasses") + +method logger*(opcode: Opcode): Logger = + logging.getLogger(&"vm.logic.call.{$opcode.kind}") + +# TODO: not extremely happy with the method approach, maybe optimize +# a bit the run, so we directly replace it with handler's body +macro newOpcode*(kind: untyped, gasCost: untyped, handler: untyped): untyped = + # newOpcode(Op.Mul, GAS_LOW, mul) + let name = ident(&"Opcode{kind[1].repr}") + let computation = ident("computation") + result = quote: + type + `name`* = ref object of Opcode + + method kind*(opcode: `name`): Op = + `kind` + + method gasCost*(opcode: `name`): Int256 = + `gasCost` + + var code: NimNode + if handler.kind != nnkStmtList: + code = quote: + method `run`*(opcode: `name`, `computation`: var BaseComputation) = + `computation`.gasMeter.consumeGas(`gasCost`, reason = $`kind`) + `handler`(`computation`) + else: + code = quote: + method `run*`(opcode: `name`, `computation`: var BaseComputation) = + `computation`.gasMeter.consumeGas(`gasCost`, reason = $`kind`) + `handler` + + result.add(code) + echo result.repr diff --git a/src/opcode_values.nim b/src/opcode_values.nim index 719f93eb9..c8b5ecb27 100644 --- a/src/opcode_values.nim +++ b/src/opcode_values.nim @@ -1,159 +1,160 @@ # TODO : hex -const - STOP* = 0.byte - ADD* = 1.byte - MUL* = 2.byte - SUB* = 3.byte - DIV* = 4.byte - SDIV* = 5.byte - MOD* = 6.byte - SMOD* = 7.byte - ADDMOD* = 8.byte - MULMOD* = 9.byte - EXP* = 10.byte - SIGNEXTEND* = 11.byte +type + Op* {.pure.} = enum + STOP, # 0 + ADD, # 1 + MUL, # 2 + SUB, # 3 + DIV, # 4 + SDIV, # 5 + MOD, # 6 + SMOD, # 7 + ADDMOD, # 8 + MULMOD, # 9 + EXP, # 10 + SIGNEXTEND, # 11 - LT* = 16.byte - GT* = 17.byte - SLT* = 18.byte - SGT* = 19.byte - EQ* = 20.byte - ISZERO* = 21.byte - AND* = 22.byte - OR* = 23.byte - XOR* = 24.byte - NOT* = 25.byte - BYTE* = 26.byte + LT, # 16 + GT, # 17 + SLT, # 18 + SGT, # 19 + EQ, # 20 + ISZERO, # 21 + AND, # 22 + OR, # 23 + XOR, # 24 + NOT, # 25 + BYTE, # 26 - SHA3* = 32.byte - - ADDRESS* = 48.byte - BALANCE* = 49.byte - ORIGIN* = 50.byte + SHA3, # 32 + + ADDRESS, # 48 + BALANCE, # 49 + ORIGIN, # 50 - CALLER* = 51.byte - CALLVALUE* = 52.byte - CALLDATALOAD* = 53.byte - CALLDATASIZE* = 54.byte - CALLDATACOPY* = 55.byte + CALLER, # 51 + CALLVALUE, # 52 + CALLDATALOAD, # 53 + CALLDATASIZE, # 54 + CALLDATACOPY, # 55 - CODESIZE* = 56.byte - CODECOPY* = 57.byte + CODESIZE, # 56 + CODECOPY, # 57 - GASPRICE* = 58.byte + GASPRICE, # 58 - EXTCODESIZE* = 59.byte - EXTCODECOPY* = 60.byte + EXTCODESIZE, # 59 + EXTCODECOPY, # 60 - RETURNDATASIZE* = 61.byte - RETURNDATACOPY* = 62.byte + RETURNDATASIZE, # 61 + RETURNDATACOPY, # 62 - BLOCKHASH* = 64.byte + BLOCKHASH, # 64 - COINBASE* = 65.byte + COINBASE, # 65 - TIMESTAMP* = 66.byte + TIMESTAMP, # 66 - NUMBER* = 67.byte + NUMBER, # 67 - DIFFICULTY* = 68.byte + DIFFICULTY, # 68 - GASLIMIT* = 69.byte - - POP* = 80.byte + GASLIMIT, # 69 + + POP, # 80 - MLOAD* = 81.byte - MSTORE* = 82.byte - MSTORE8 = 83.byte + MLOAD, # 81 + MSTORE, # 82 + MSTORE8 # 83 - SLOAD* = 84.byte - SSTORE* = 85.byte + SLOAD, # 84 + SSTORE, # 85 - JUMP* = 86.byte - JUMPI* = 87.byte + JUMP, # 86 + JUMPI, # 87 - PC* = 88.byte + PC, # 88 - MSIZE* = 89.byte + MSIZE, # 89 - GAS* = 90.byte + GAS, # 90 - JUMPDEST* = 91.byte - - PUSH1* = 96.byte - PUSH2* = 97.byte - PUSH3* = 98.byte - PUSH4* = 99.byte - PUSH5* = 100.byte - PUSH6* = 101.byte - PUSH7* = 102.byte - PUSH8* = 103.byte - PUSH9* = 104.byte - PUSH10* = 105.byte - PUSH11* = 106.byte - PUSH12* = 107.byte - PUSH13* = 108.byte - PUSH14* = 109.byte - PUSH15* = 110.byte - PUSH16* = 111.byte - PUSH17* = 112.byte - PUSH18* = 113.byte - PUSH19* = 114.byte - PUSH20* = 115.byte - PUSH21* = 116.byte - PUSH22* = 117.byte - PUSH23* = 118.byte - PUSH24* = 119.byte - PUSH25* = 120.byte - PUSH26* = 121.byte - PUSH27* = 122.byte - PUSH28* = 123.byte - PUSH29* = 124.byte - PUSH30* = 125.byte - PUSH31* = 126.byte - PUSH32* = 127.byte - DUP1* = 128.byte - DUP2* = 129.byte - DUP3* = 130.byte - DUP4* = 131.byte - DUP5* = 132.byte - DUP6* = 133.byte - DUP7* = 134.byte - DUP8* = 135.byte - DUP9* = 136.byte - DUP10* = 137.byte - DUP11* = 138.byte - DUP12* = 139.byte - DUP13* = 140.byte - DUP14* = 141.byte - DUP15* = 142.byte - DUP16* = 143.byte - SWAP1* = 144.byte - SWAP2* = 145.byte - SWAP3* = 146.byte - SWAP4* = 147.byte - SWAP5* = 148.byte - SWAP6* = 149.byte - SWAP7* = 150.byte - SWAP8* = 151.byte - SWAP9* = 152.byte - SWAP10* = 153.byte - SWAP11* = 154.byte - SWAP12* = 155.byte - SWAP13* = 156.byte - SWAP14* = 157.byte - SWAP15* = 158.byte - SWAP16* = 159.byte - LOG0* = 160.byte - LOG1* = 161.byte - LOG2* = 162.byte - LOG3* = 163.byte - LOG4* = 164.byte - CREATE* = 240.byte - CALL* = 241.byte - CALLCODE* = 242.byte - RETURN* = 243.byte - DELEGATECALL* = 244.byte - STATICCALL* = 250.byte - REVERT* = 253.byte - SELFDESTRUCT* = 255.byte + JUMPDEST, # 91 + + PUSH1, # 96 + PUSH2, # 97 + PUSH3, # 98 + PUSH4, # 99 + PUSH5, # 100 + PUSH6, # 101 + PUSH7, # 102 + PUSH8, # 103 + PUSH9, # 104 + PUSH10, # 105 + PUSH11, # 106 + PUSH12, # 107 + PUSH13, # 108 + PUSH14, # 109 + PUSH15, # 110 + PUSH16, # 111 + PUSH17, # 112 + PUSH18, # 113 + PUSH19, # 114 + PUSH20, # 115 + PUSH21, # 116 + PUSH22, # 117 + PUSH23, # 118 + PUSH24, # 119 + PUSH25, # 120 + PUSH26, # 121 + PUSH27, # 122 + PUSH28, # 123 + PUSH29, # 124 + PUSH30, # 125 + PUSH31, # 126 + PUSH32, # 127 + DUP1, # 128 + DUP2, # 129 + DUP3, # 130 + DUP4, # 131 + DUP5, # 132 + DUP6, # 133 + DUP7, # 134 + DUP8, # 135 + DUP9, # 136 + DUP10, # 137 + DUP11, # 138 + DUP12, # 139 + DUP13, # 140 + DUP14, # 141 + DUP15, # 142 + DUP16, # 143 + SWAP1, # 144 + SWAP2, # 145 + SWAP3, # 146 + SWAP4, # 147 + SWAP5, # 148 + SWAP6, # 149 + SWAP7, # 150 + SWAP8, # 151 + SWAP9, # 152 + SWAP10, # 153 + SWAP11, # 154 + SWAP12, # 155 + SWAP13, # 156 + SWAP14, # 157 + SWAP15, # 158 + SWAP16, # 159 + LOG0, # 160 + LOG1, # 161 + LOG2, # 162 + LOG3, # 163 + LOG4, # 164 + CREATE, # 240 + CALL, # 241 + CALLCODE, # 242 + RETURN, # 243 + DELEGATECALL, # 244 + STATICCALL, # 250 + REVERT, # 253 + SELFDESTRUCT # 255 diff --git a/src/vm/code_stream.nim b/src/vm/code_stream.nim index bf2c34698..c6b194aee 100644 --- a/src/vm/code_stream.nim +++ b/src/vm/code_stream.nim @@ -30,24 +30,24 @@ proc read*(c: var CodeStream, size: int): seq[byte] = proc len*(c: CodeStream): int = len(c.bytes) -proc next*(c: var CodeStream): byte = +proc next*(c: var CodeStream): Op = var nextOpcode = c.read(1) if nextOpcode[0] != 0x0.byte: - return nextOpcode[0] + return Op(nextOpcode[0]) else: - return opcode_values.STOP + return Op.STOP -iterator items*(c: var CodeStream): byte = +iterator items*(c: var CodeStream): Op = var nextOpcode = c.next() - while nextOpcode != opcode_values.STOP: + while nextOpcode != Op.STOP: yield nextOpcode nextOpcode = c.next() proc `[]`*(c: CodeStream, offset: int): byte = c.bytes[offset] -proc peek*(c: var CodeStream): byte = +proc peek*(c: var CodeStream): Op = var currentPc = c.pc result = c.next() c.pc = currentPc @@ -74,8 +74,8 @@ proc isValidOpcode*(c: var CodeStream, position: int): bool = else: var i = c.depthProcessed while i <= position: - var opcode = c[i] - if opcode >= opcode_values.PUSH1 and opcode <= opcode_values.PUSH32: + var opcode = Op(c[i]) + if opcode >= Op.PUSH1 and opcode <= Op.PUSH32: var leftBound = (i + 1) var rightBound = leftBound + (opcode.int - 95) for z in leftBound ..< rightBound: