WIP opcode dsl, code stream changes

This commit is contained in:
Alexander Ivanov 2018-01-23 20:36:23 +02:00
parent 72c8ad4877
commit 7b5f7e762b
4 changed files with 214 additions and 147 deletions

View File

@ -1,6 +1,6 @@
import import
../constants, ../utils_numeric, ../computation, ../constants, ../utils_numeric, ../computation,
.. / vm / [gas_meter, stack], .. / vm / [gas_meter, stack], ../opcode, ../opcode_values,
helpers, bigints helpers, bigints
proc add*(computation: var BaseComputation) = proc add*(computation: var BaseComputation) =
@ -101,3 +101,19 @@ proc signextend(computation: var BaseComputation) =
else: else:
res = value res = value
pushRes() 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)

50
src/opcode.nim Normal file
View File

@ -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

View File

@ -1,159 +1,160 @@
# TODO : hex # TODO : hex
const type
STOP* = 0.byte Op* {.pure.} = enum
ADD* = 1.byte STOP, # 0
MUL* = 2.byte ADD, # 1
SUB* = 3.byte MUL, # 2
DIV* = 4.byte SUB, # 3
SDIV* = 5.byte DIV, # 4
MOD* = 6.byte SDIV, # 5
SMOD* = 7.byte MOD, # 6
ADDMOD* = 8.byte SMOD, # 7
MULMOD* = 9.byte ADDMOD, # 8
EXP* = 10.byte MULMOD, # 9
SIGNEXTEND* = 11.byte EXP, # 10
SIGNEXTEND, # 11
LT* = 16.byte LT, # 16
GT* = 17.byte GT, # 17
SLT* = 18.byte SLT, # 18
SGT* = 19.byte SGT, # 19
EQ* = 20.byte EQ, # 20
ISZERO* = 21.byte ISZERO, # 21
AND* = 22.byte AND, # 22
OR* = 23.byte OR, # 23
XOR* = 24.byte XOR, # 24
NOT* = 25.byte NOT, # 25
BYTE* = 26.byte BYTE, # 26
SHA3* = 32.byte SHA3, # 32
ADDRESS* = 48.byte ADDRESS, # 48
BALANCE* = 49.byte BALANCE, # 49
ORIGIN* = 50.byte ORIGIN, # 50
CALLER* = 51.byte CALLER, # 51
CALLVALUE* = 52.byte CALLVALUE, # 52
CALLDATALOAD* = 53.byte CALLDATALOAD, # 53
CALLDATASIZE* = 54.byte CALLDATASIZE, # 54
CALLDATACOPY* = 55.byte CALLDATACOPY, # 55
CODESIZE* = 56.byte CODESIZE, # 56
CODECOPY* = 57.byte CODECOPY, # 57
GASPRICE* = 58.byte GASPRICE, # 58
EXTCODESIZE* = 59.byte EXTCODESIZE, # 59
EXTCODECOPY* = 60.byte EXTCODECOPY, # 60
RETURNDATASIZE* = 61.byte RETURNDATASIZE, # 61
RETURNDATACOPY* = 62.byte 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 GASLIMIT, # 69
POP* = 80.byte POP, # 80
MLOAD* = 81.byte MLOAD, # 81
MSTORE* = 82.byte MSTORE, # 82
MSTORE8 = 83.byte MSTORE8 # 83
SLOAD* = 84.byte SLOAD, # 84
SSTORE* = 85.byte SSTORE, # 85
JUMP* = 86.byte JUMP, # 86
JUMPI* = 87.byte JUMPI, # 87
PC* = 88.byte PC, # 88
MSIZE* = 89.byte MSIZE, # 89
GAS* = 90.byte GAS, # 90
JUMPDEST* = 91.byte JUMPDEST, # 91
PUSH1* = 96.byte PUSH1, # 96
PUSH2* = 97.byte PUSH2, # 97
PUSH3* = 98.byte PUSH3, # 98
PUSH4* = 99.byte PUSH4, # 99
PUSH5* = 100.byte PUSH5, # 100
PUSH6* = 101.byte PUSH6, # 101
PUSH7* = 102.byte PUSH7, # 102
PUSH8* = 103.byte PUSH8, # 103
PUSH9* = 104.byte PUSH9, # 104
PUSH10* = 105.byte PUSH10, # 105
PUSH11* = 106.byte PUSH11, # 106
PUSH12* = 107.byte PUSH12, # 107
PUSH13* = 108.byte PUSH13, # 108
PUSH14* = 109.byte PUSH14, # 109
PUSH15* = 110.byte PUSH15, # 110
PUSH16* = 111.byte PUSH16, # 111
PUSH17* = 112.byte PUSH17, # 112
PUSH18* = 113.byte PUSH18, # 113
PUSH19* = 114.byte PUSH19, # 114
PUSH20* = 115.byte PUSH20, # 115
PUSH21* = 116.byte PUSH21, # 116
PUSH22* = 117.byte PUSH22, # 117
PUSH23* = 118.byte PUSH23, # 118
PUSH24* = 119.byte PUSH24, # 119
PUSH25* = 120.byte PUSH25, # 120
PUSH26* = 121.byte PUSH26, # 121
PUSH27* = 122.byte PUSH27, # 122
PUSH28* = 123.byte PUSH28, # 123
PUSH29* = 124.byte PUSH29, # 124
PUSH30* = 125.byte PUSH30, # 125
PUSH31* = 126.byte PUSH31, # 126
PUSH32* = 127.byte PUSH32, # 127
DUP1* = 128.byte DUP1, # 128
DUP2* = 129.byte DUP2, # 129
DUP3* = 130.byte DUP3, # 130
DUP4* = 131.byte DUP4, # 131
DUP5* = 132.byte DUP5, # 132
DUP6* = 133.byte DUP6, # 133
DUP7* = 134.byte DUP7, # 134
DUP8* = 135.byte DUP8, # 135
DUP9* = 136.byte DUP9, # 136
DUP10* = 137.byte DUP10, # 137
DUP11* = 138.byte DUP11, # 138
DUP12* = 139.byte DUP12, # 139
DUP13* = 140.byte DUP13, # 140
DUP14* = 141.byte DUP14, # 141
DUP15* = 142.byte DUP15, # 142
DUP16* = 143.byte DUP16, # 143
SWAP1* = 144.byte SWAP1, # 144
SWAP2* = 145.byte SWAP2, # 145
SWAP3* = 146.byte SWAP3, # 146
SWAP4* = 147.byte SWAP4, # 147
SWAP5* = 148.byte SWAP5, # 148
SWAP6* = 149.byte SWAP6, # 149
SWAP7* = 150.byte SWAP7, # 150
SWAP8* = 151.byte SWAP8, # 151
SWAP9* = 152.byte SWAP9, # 152
SWAP10* = 153.byte SWAP10, # 153
SWAP11* = 154.byte SWAP11, # 154
SWAP12* = 155.byte SWAP12, # 155
SWAP13* = 156.byte SWAP13, # 156
SWAP14* = 157.byte SWAP14, # 157
SWAP15* = 158.byte SWAP15, # 158
SWAP16* = 159.byte SWAP16, # 159
LOG0* = 160.byte LOG0, # 160
LOG1* = 161.byte LOG1, # 161
LOG2* = 162.byte LOG2, # 162
LOG3* = 163.byte LOG3, # 163
LOG4* = 164.byte LOG4, # 164
CREATE* = 240.byte CREATE, # 240
CALL* = 241.byte CALL, # 241
CALLCODE* = 242.byte CALLCODE, # 242
RETURN* = 243.byte RETURN, # 243
DELEGATECALL* = 244.byte DELEGATECALL, # 244
STATICCALL* = 250.byte STATICCALL, # 250
REVERT* = 253.byte REVERT, # 253
SELFDESTRUCT* = 255.byte SELFDESTRUCT # 255

View File

@ -30,24 +30,24 @@ proc read*(c: var CodeStream, size: int): seq[byte] =
proc len*(c: CodeStream): int = proc len*(c: CodeStream): int =
len(c.bytes) len(c.bytes)
proc next*(c: var CodeStream): byte = proc next*(c: var CodeStream): Op =
var nextOpcode = c.read(1) var nextOpcode = c.read(1)
if nextOpcode[0] != 0x0.byte: if nextOpcode[0] != 0x0.byte:
return nextOpcode[0] return Op(nextOpcode[0])
else: else:
return opcode_values.STOP return Op.STOP
iterator items*(c: var CodeStream): byte = iterator items*(c: var CodeStream): Op =
var nextOpcode = c.next() var nextOpcode = c.next()
while nextOpcode != opcode_values.STOP: while nextOpcode != Op.STOP:
yield nextOpcode yield nextOpcode
nextOpcode = c.next() nextOpcode = c.next()
proc `[]`*(c: CodeStream, offset: int): byte = proc `[]`*(c: CodeStream, offset: int): byte =
c.bytes[offset] c.bytes[offset]
proc peek*(c: var CodeStream): byte = proc peek*(c: var CodeStream): Op =
var currentPc = c.pc var currentPc = c.pc
result = c.next() result = c.next()
c.pc = currentPc c.pc = currentPc
@ -74,8 +74,8 @@ proc isValidOpcode*(c: var CodeStream, position: int): bool =
else: else:
var i = c.depthProcessed var i = c.depthProcessed
while i <= position: while i <= position:
var opcode = c[i] var opcode = Op(c[i])
if opcode >= opcode_values.PUSH1 and opcode <= opcode_values.PUSH32: if opcode >= Op.PUSH1 and opcode <= Op.PUSH32:
var leftBound = (i + 1) var leftBound = (i + 1)
var rightBound = leftBound + (opcode.int - 95) var rightBound = leftBound + (opcode.int - 95)
for z in leftBound ..< rightBound: for z in leftBound ..< rightBound: