applies jamie's patch for eliminating recursion

original comment:
  This patch eliminates recursion entirely from the EVM when ENABLE_EVMC=0.
This commit is contained in:
Jordan Hrycaj 2021-04-21 08:18:59 +01:00 committed by zah
parent b2ce6d9e70
commit 01b96df99f
1 changed files with 17 additions and 25 deletions

View File

@ -185,36 +185,28 @@ template chainTo*(c, toChild: Computation, after: untyped) =
c.continuation = proc() = c.continuation = proc() =
after after
proc execCallOrCreateAux(c: var Computation) {.noinline.} =
# Perform recursion with minimum-size stack per level. The exception
# handling is very subtle. Each call to `snapshot` must have a corresponding
# `dispose` on exception. To minimise this proc's stackframe, `defer` is
# moved to the outermost proc only. `{.noinline.}` is also used to make
# extra sure they stay separate. `c` is a `var` parameter at every level of
# recursion, so the outermost proc sees every change to `c`, which is why `c`
# is updated instead of using `let`. On exception, the outermost `defer`
# walks the `c.parent` chain to call `dispose` on each `c`.
if c.beforeExec():
return
c.executeOpcodes()
while not c.continuation.isNil:
# Parent and child refs are updated and cleared so as to avoid circular
# refs (like a double-linked list) or dangling refs (to finished child).
(c.child, c, c.parent) = (nil.Computation, c.child, c)
execCallOrCreateAux(c)
c.dispose()
(c.parent, c) = (nil.Computation, c.parent)
(c.continuation)()
c.executeOpcodes()
c.afterExec()
proc execCallOrCreate*(cParam: Computation) = proc execCallOrCreate*(cParam: Computation) =
var c = cParam var (c, before) = (cParam, true)
defer: defer:
while not c.isNil: while not c.isNil:
c.dispose() c.dispose()
c = c.parent c = c.parent
execCallOrCreateAux(c)
# No actual recursion, but simulate recursion including before/after/dispose.
while true:
while true:
if before and c.beforeExec():
break
c.executeOpcodes()
if c.continuation.isNil:
c.afterExec()
break
(before, c.child, c, c.parent) = (true, nil.Computation, c.child, c)
if c.parent.isNil:
break
c.dispose()
(before, c.parent, c) = (false, nil.Computation, c.parent)
(c.continuation)()
proc merge*(c, child: Computation) = proc merge*(c, child: Computation) =
c.logEntries.add child.logEntries c.logEntries.add child.logEntries