2021-04-08 14:52:10 +00:00
|
|
|
# Nimbus
|
|
|
|
# Copyright (c) 2018 Status Research & Development GmbH
|
|
|
|
# Licensed under either of
|
2021-04-20 15:39:32 +00:00
|
|
|
# * 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.
|
2021-04-08 14:52:10 +00:00
|
|
|
|
2021-04-22 11:02:13 +00:00
|
|
|
const
|
2021-04-23 07:50:48 +00:00
|
|
|
# help with low memory when compiling
|
|
|
|
lowmem {.intdefine.}: int = 0
|
|
|
|
lowMemoryCompileTime {.used.} = lowmem > 0
|
|
|
|
|
2021-04-23 17:43:44 +00:00
|
|
|
# debugging flag, dump macro info when asked for
|
2021-04-22 16:05:58 +00:00
|
|
|
noisy {.intdefine.}: int = 0
|
2021-04-23 17:43:44 +00:00
|
|
|
# isNoisy {.used.} = noisy > 0
|
|
|
|
isChatty {.used.} = noisy > 1
|
2021-04-22 11:02:13 +00:00
|
|
|
|
2021-04-08 14:52:10 +00:00
|
|
|
import
|
2021-04-20 15:39:32 +00:00
|
|
|
./compu_helper,
|
2021-04-21 17:04:54 +00:00
|
|
|
./interpreter/[forks_list, gas_costs, gas_meter,
|
|
|
|
op_codes, op_handlers, op_handlers/oph_defs],
|
2021-04-20 15:39:32 +00:00
|
|
|
./code_stream,
|
2021-04-22 16:05:58 +00:00
|
|
|
./types,
|
2021-04-22 11:02:13 +00:00
|
|
|
chronicles,
|
|
|
|
macros
|
2021-04-08 14:52:10 +00:00
|
|
|
|
|
|
|
logScope:
|
|
|
|
topics = "vm opcode"
|
|
|
|
|
2021-04-22 11:02:13 +00:00
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
# Helpers
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
template handleStopDirective(k: var Vm2Ctx) =
|
|
|
|
trace "op: Stop"
|
|
|
|
if not k.cpt.code.atEnd() and k.cpt.tracingEnabled:
|
|
|
|
# we only trace `REAL STOP` and ignore `FAKE STOP`
|
|
|
|
k.cpt.opIndex = k.cpt.traceOpCodeStarted(Stop)
|
|
|
|
k.cpt.traceOpCodeEnded(Stop, k.cpt.opIndex)
|
|
|
|
|
|
|
|
|
|
|
|
template handleFixedGasCostsDirective(fork: Fork; op: Op; k: var Vm2Ctx) =
|
|
|
|
if k.cpt.tracingEnabled:
|
|
|
|
k.cpt.opIndex = k.cpt.traceOpCodeStarted(op)
|
|
|
|
|
|
|
|
k.cpt.gasMeter.consumeGas(k.cpt.gasCosts[op].cost, reason = $op)
|
|
|
|
vmOpHandlers[fork][op].run(k)
|
|
|
|
|
|
|
|
if k.cpt.tracingEnabled:
|
|
|
|
k.cpt.traceOpCodeEnded(op, k.cpt.opIndex)
|
|
|
|
|
|
|
|
|
|
|
|
template handleOtherDirective(fork: Fork; op: Op; k: var Vm2Ctx) =
|
|
|
|
if k.cpt.tracingEnabled:
|
|
|
|
k.cpt.opIndex = k.cpt.traceOpCodeStarted(op)
|
|
|
|
|
|
|
|
vmOpHandlers[fork][op].run(k)
|
|
|
|
|
|
|
|
if k.cpt.tracingEnabled:
|
|
|
|
k.cpt.traceOpCodeEnded(op, k.cpt.opIndex)
|
|
|
|
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
# Private, big nasty doubly nested case matrix generator
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
# reminiscent of Mamy's opTableToCaseStmt() from original VM
|
|
|
|
proc toCaseStmt(forkArg, opArg, k: NimNode): NimNode =
|
|
|
|
|
|
|
|
# Outer case/switch => Op
|
|
|
|
let branchOnOp = quote do: `opArg`
|
|
|
|
result = nnkCaseStmt.newTree(branchOnOp)
|
|
|
|
for op in Op:
|
|
|
|
|
|
|
|
# Inner case/switch => Fork
|
|
|
|
let branchOnFork = quote do: `forkArg`
|
|
|
|
var forkCaseSubExpr = nnkCaseStmt.newTree(branchOnFork)
|
|
|
|
for fork in Fork:
|
|
|
|
|
|
|
|
let
|
|
|
|
asFork = quote do: Fork(`fork`)
|
|
|
|
asOp = quote do: Op(`op`)
|
|
|
|
|
|
|
|
let branchStmt = block:
|
|
|
|
if op == Stop:
|
|
|
|
quote do:
|
|
|
|
handleStopDirective(`k`)
|
|
|
|
elif BaseGasCosts[op].kind == GckFixed:
|
|
|
|
quote do:
|
|
|
|
handleFixedGasCostsDirective(`asFork`,`asOp`,`k`)
|
|
|
|
else:
|
|
|
|
quote do:
|
|
|
|
handleOtherDirective(`asFork`,`asOp`,`k`)
|
|
|
|
|
|
|
|
forkCaseSubExpr.add nnkOfBranch.newTree(
|
|
|
|
newIdentNode(fork.toSymbolName),
|
|
|
|
branchStmt)
|
|
|
|
|
|
|
|
# Wrap innner case/switch into outer case/switch
|
|
|
|
let branchStmt = block:
|
|
|
|
case op
|
|
|
|
of Create, Create2, Call, CallCode, DelegateCall, StaticCall:
|
|
|
|
quote do:
|
|
|
|
`forkCaseSubExpr`
|
2021-04-23 07:50:48 +00:00
|
|
|
if not `k`.cpt.continuation.isNil:
|
2021-04-22 11:02:13 +00:00
|
|
|
break
|
|
|
|
of Stop, Return, Revert, SelfDestruct:
|
|
|
|
quote do:
|
|
|
|
`forkCaseSubExpr`
|
|
|
|
break
|
|
|
|
else:
|
|
|
|
quote do:
|
|
|
|
`forkCaseSubExpr`
|
|
|
|
|
|
|
|
result.add nnkOfBranch.newTree(
|
|
|
|
newIdentNode(op.toSymbolName),
|
|
|
|
branchStmt)
|
|
|
|
|
2021-04-23 17:43:44 +00:00
|
|
|
when isChatty:
|
2021-04-22 11:02:13 +00:00
|
|
|
echo ">>> ", result.repr
|
|
|
|
|
|
|
|
|
2021-04-23 07:50:48 +00:00
|
|
|
macro genDispatchMatrix(fork: Fork; op: Op; k: Vm2Ctx): untyped {.used.} =
|
2021-04-22 11:02:13 +00:00
|
|
|
result = fork.toCaseStmt(op, k)
|
|
|
|
|
2021-04-23 07:50:48 +00:00
|
|
|
|
|
|
|
template genLowMemDispatcher(fork: Fork; op: Op; k: Vm2Ctx) {.used.} =
|
|
|
|
if op == Stop:
|
|
|
|
handleStopDirective(k)
|
|
|
|
break
|
|
|
|
|
|
|
|
if BaseGasCosts[op].kind == GckFixed:
|
|
|
|
handleFixedGasCostsDirective(fork, op, k)
|
|
|
|
else:
|
|
|
|
handleOtherDirective(fork, op, k)
|
|
|
|
|
|
|
|
case c.instr
|
|
|
|
of Create, Create2, Call, CallCode, DelegateCall, StaticCall:
|
|
|
|
if not k.cpt.continuation.isNil:
|
|
|
|
break
|
|
|
|
of Return, Revert, SelfDestruct:
|
|
|
|
break
|
|
|
|
else:
|
|
|
|
discard
|
|
|
|
|
2021-04-22 11:02:13 +00:00
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
# Public functions
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
|
2021-04-20 15:39:32 +00:00
|
|
|
proc selectVM*(c: Computation, fork: Fork) {.gcsafe.} =
|
2021-04-22 11:02:13 +00:00
|
|
|
## Op code execution handler main loop.
|
2021-04-20 12:07:01 +00:00
|
|
|
var desc: Vm2Ctx
|
2021-04-22 11:02:13 +00:00
|
|
|
desc.cpt = c
|
2021-04-20 12:07:01 +00:00
|
|
|
|
2021-04-20 11:14:43 +00:00
|
|
|
if c.tracingEnabled:
|
|
|
|
c.prepareTracer()
|
|
|
|
|
|
|
|
while true:
|
|
|
|
c.instr = c.code.next()
|
|
|
|
|
2021-04-22 11:02:13 +00:00
|
|
|
# Note Mamy's observation in opTableToCaseStmt() from original VM
|
|
|
|
# regarding computed goto
|
|
|
|
#
|
|
|
|
# ackn:
|
|
|
|
# #{.computedGoto.}
|
|
|
|
# # computed goto causing stack overflow, it consumes a lot of space
|
|
|
|
# # we could use manual jump table instead
|
|
|
|
# # TODO lots of macro magic here to unravel, with chronicles...
|
|
|
|
# # `c`.logger.log($`c`.stack & "\n\n", fgGreen)
|
2021-04-23 07:50:48 +00:00
|
|
|
when not lowMemoryCompileTime:
|
|
|
|
when defined(release):
|
|
|
|
#
|
|
|
|
# FIXME: OS case list below needs to be adjusted
|
|
|
|
#
|
|
|
|
when defined(windows):
|
|
|
|
when defined(cpu64):
|
|
|
|
{.warning: "*** Win64/VM2 handler switch => computedGoto".}
|
|
|
|
{.computedGoto, optimization: speed.}
|
|
|
|
else:
|
|
|
|
# computedGoto not compiling on github/ci (out of memory) -- jordan
|
|
|
|
{.warning: "*** Win32/VM2 handler switch => optimisation disabled".}
|
|
|
|
# {.computedGoto, optimization: speed.}
|
|
|
|
|
|
|
|
elif defined(linux):
|
|
|
|
when defined(cpu64):
|
|
|
|
{.warning: "*** Linux64/VM2 handler switch => computedGoto".}
|
|
|
|
{.computedGoto, optimization: speed.}
|
|
|
|
else:
|
|
|
|
{.warning: "*** Linux32/VM2 handler switch => computedGoto".}
|
|
|
|
{.computedGoto, optimization: speed.}
|
|
|
|
|
|
|
|
elif defined(macosx):
|
|
|
|
when defined(cpu64):
|
|
|
|
{.warning: "*** MacOs64/VM2 handler switch => computedGoto".}
|
|
|
|
{.computedGoto, optimization: speed.}
|
|
|
|
else:
|
|
|
|
{.warning: "*** MacOs32/VM2 handler switch => computedGoto".}
|
|
|
|
{.computedGoto, optimization: speed.}
|
2021-04-22 11:02:13 +00:00
|
|
|
|
|
|
|
else:
|
2021-04-23 07:50:48 +00:00
|
|
|
{.warning: "*** Unsupported OS => no handler switch optimisation".}
|
2021-04-22 11:02:13 +00:00
|
|
|
|
2021-04-23 07:50:48 +00:00
|
|
|
genDispatchMatrix(fork, c.instr, desc)
|
2021-04-22 11:02:13 +00:00
|
|
|
|
2021-04-23 07:50:48 +00:00
|
|
|
else:
|
|
|
|
{.warning: "*** low memory compiler mode => program will be slow".}
|
2021-04-22 11:02:13 +00:00
|
|
|
|
2021-04-23 07:50:48 +00:00
|
|
|
genLowMemDispatcher(fork, c.instr, desc)
|
2021-04-22 11:02:13 +00:00
|
|
|
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
# End
|
|
|
|
# ------------------------------------------------------------------------------
|