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
../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)

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

View File

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