nimbus-eth1/nimbus/opcode.nim

77 lines
2.9 KiB
Nim

# 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.
import
strformat, strutils, sequtils, macros,
constants, logging, errors, opcode_values, computation, vm/stack, stint,
./vm_types
template run*(opcode: Opcode, computation: var BaseComputation) =
# Hook for performing the actual VM execution
# opcode.consumeGas(computation)
computation.gasMeter.consumeGas(computation.gasCosts[opcode.gasCost(computation)], reason = $opcode.kind) # TODO: further refactoring of gas costs
opcode.runLogic(computation)
method logger*(opcode: Opcode): Logger =
logging.getLogger(&"vm.opcode.{opcode.kind}")
method gasCost*(opcode: Opcode, computation: var BaseComputation): GasCostKind =
#if opcode.kind in VARIABLE_GAS_COST_OPS:
# opcode.gasCostHandler(computation)
#else:
opcode.gasCostKind
template newOpcode*(kind: Op, gasCost: UInt256, logic: proc(computation: var BaseComputation)): Opcode =
Opcode(kind: kind, gasCostKind: 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)
method `$`*(opcode: Opcode): string =
let gasCost = $opcode.gasCostKind
# if opcode.kind in VARIABLE_GAS_COST_OPS:
# "variable"
# else:
# $opcode.gasCostKind
&"{opcode.kind}(0x{opcode.kind.int.toHex(2)}: {gasCost})"
macro initOpcodes*(spec: untyped): untyped =
var value = ident("value")
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`, gasCostKind: `gasCost`, runLogic: `handler`)
result[1].add(opcode)
result[1].add(value)