nimbus-eth1/src/opcode.nim

67 lines
2.4 KiB
Nim
Raw Normal View History

2018-01-23 18:36:23 +00:00
import
strformat, strutils, sequtils, macros,
2018-02-07 16:16:04 +00:00
constants, logging, errors, opcode_values, computation, vm/stack, ttmath
2018-01-23 18:36:23 +00:00
template run*(opcode: Opcode, computation: var BaseComputation) =
# Hook for performing the actual VM execution
computation.gasMeter.consumeGas(opcode.gasCost(computation), reason = $opcode.kind)
opcode.runLogic(computation)
2018-01-23 18:36:23 +00:00
method logger*(opcode: Opcode): Logger =
logging.getLogger(&"vm.opcode.{opcode.kind}")
2018-01-23 18:36:23 +00:00
method gasCost*(opcode: Opcode, computation: var BaseComputation): UInt256 =
if opcode.kind in VARIABLE_GAS_COST_OPS:
opcode.gasCostHandler(computation)
else:
opcode.gasCostConstant
2018-01-23 18:36:23 +00:00
template newOpcode*(kind: Op, gasCost: UInt256, logic: proc(computation: var BaseComputation)): Opcode =
Opcode(kind: kind, gasCostConstant: gasCost, runLogic: logic)
template newOpcode*(kind: Op, gasHandler: proc(computation: var BaseComputation): UInt256, logic: proc(computation: var BaseComputation)): Opcode =
Opcode(kind: kind, gasCostHandler: gasHandler, runLogic: logic)
2018-01-23 18:36:23 +00:00
method `$`*(opcode: Opcode): string =
let gasCost = if opcode.kind in VARIABLE_GAS_COST_OPS:
"variable"
else:
$opcode.gasCostConstant
&"{opcode.kind}(0x{opcode.kind.int.toHex(2)}: {gasCost})"
macro initOpcodes*(spec: untyped): untyped =
var value = ident("value")
2018-01-23 18:36:23 +00:00
result = quote:
block:
var `value` = initTable[Op, Opcode]()
for child in spec:
var ops, gasCosts, handlers: seq[NimNode]
if child.kind == nnkInfix and child[0].repr == "..":
ops = @[]
gasCosts = @[]
handlers = @[]
let first = child[1].repr.parseInt
let last = child[2][0].repr.parseInt
let op = child[2][1][1].repr
for z in first .. last:
ops.add(nnkDotExpr.newTree(ident("Op"), ident(op.replace("XX", $z))))
gasCosts.add(child[3][0][0])
handlers.add(ident(child[3][0][1].repr.replace("XX", $z)))
else:
ops = @[child[0]]
gasCosts = @[child[1][0][0]]
handlers = @[child[1][0][1]]
for z in 0 ..< ops.len:
let (op, gasCost, handler) = (ops[z], gasCosts[z], handlers[z])
let opcode = if gasCost.repr[0].isLowerAscii():
quote:
`value`[`op`] = Opcode(kind: `op`, gasCostHandler: `gasCost`, runLogic: `handler`)
else:
quote:
`value`[`op`] = Opcode(kind: `op`, gasCostConstant: `gasCost`, runLogic: `handler`)
result[1].add(opcode)
2018-01-23 18:36:23 +00:00
result[1].add(value)