some small performance improvement for the evaluator
This commit is contained in:
parent
976d5b18ed
commit
a8542fbe06
3 changed files with 69 additions and 50 deletions
|
|
@ -666,6 +666,7 @@ type
|
||||||
# (or not in symbol table)
|
# (or not in symbol table)
|
||||||
# for modules, an unique index corresponding
|
# for modules, an unique index corresponding
|
||||||
# to the module's fileIdx
|
# to the module's fileIdx
|
||||||
|
# for variables a slot index for the evaluator
|
||||||
|
|
||||||
offset*: int # offset of record field
|
offset*: int # offset of record field
|
||||||
loc*: TLoc
|
loc*: TLoc
|
||||||
|
|
|
||||||
|
|
@ -23,12 +23,12 @@ when hasFFI:
|
||||||
|
|
||||||
type
|
type
|
||||||
PStackFrame* = ref TStackFrame
|
PStackFrame* = ref TStackFrame
|
||||||
TStackFrame*{.final.} = object
|
TStackFrame* = object
|
||||||
mapping*: TIdNodeTable # mapping from symbols to nodes
|
prc: PSym # current prc; proc that is evaluated
|
||||||
prc*: PSym # current prc; proc that is evaluated
|
slots: TNodeSeq # parameters passed to the proc + locals;
|
||||||
call*: PNode
|
# parameters come first
|
||||||
next*: PStackFrame # for stacking
|
call: PNode
|
||||||
params*: TNodeSeq # parameters passed to the proc
|
next: PStackFrame # for stacking
|
||||||
|
|
||||||
TEvalMode* = enum ## reason for evaluation
|
TEvalMode* = enum ## reason for evaluation
|
||||||
emRepl, ## evaluate because in REPL mode
|
emRepl, ## evaluate because in REPL mode
|
||||||
|
|
@ -69,8 +69,7 @@ const
|
||||||
|
|
||||||
proc newStackFrame*(): PStackFrame =
|
proc newStackFrame*(): PStackFrame =
|
||||||
new(result)
|
new(result)
|
||||||
initIdNodeTable(result.mapping)
|
result.slots = @[]
|
||||||
result.params = @[]
|
|
||||||
|
|
||||||
proc newEvalContext*(module: PSym, mode: TEvalMode): PEvalContext =
|
proc newEvalContext*(module: PSym, mode: TEvalMode): PEvalContext =
|
||||||
new(result)
|
new(result)
|
||||||
|
|
@ -291,6 +290,20 @@ proc evalVarValue(c: PEvalContext, n: PNode): PNode =
|
||||||
result = evalAux(c, n, {})
|
result = evalAux(c, n, {})
|
||||||
if result.kind in {nkType..nkNilLit}: result = result.copyNode
|
if result.kind in {nkType..nkNilLit}: result = result.copyNode
|
||||||
|
|
||||||
|
proc setSlot(c: PStackFrame, sym: PSym, val: PNode) =
|
||||||
|
assert sym.owner == c.prc
|
||||||
|
var idx = sym.position
|
||||||
|
if idx == 0:
|
||||||
|
idx = c.slots.len
|
||||||
|
if idx == 0: idx = 1
|
||||||
|
sym.position = idx
|
||||||
|
setLen(c.slots, max(idx+1, c.slots.len))
|
||||||
|
c.slots[idx] = val
|
||||||
|
|
||||||
|
proc setVar(c: PEvalContext, v: PSym, n: PNode) =
|
||||||
|
if sfGlobal notin v.flags: setSlot(c.tos, v, n)
|
||||||
|
else: IdNodeTablePut(c.globals, v, n)
|
||||||
|
|
||||||
proc evalVar(c: PEvalContext, n: PNode): PNode =
|
proc evalVar(c: PEvalContext, n: PNode): PNode =
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
let a = n.sons[i]
|
let a = n.sons[i]
|
||||||
|
|
@ -305,7 +318,7 @@ proc evalVar(c: PEvalContext, n: PNode): PNode =
|
||||||
return raiseCannotEval(c, n.info)
|
return raiseCannotEval(c, n.info)
|
||||||
for i in 0 .. a.len-3:
|
for i in 0 .. a.len-3:
|
||||||
var v = a.sons[i].sym
|
var v = a.sons[i].sym
|
||||||
IdNodeTablePut(c.tos.mapping, v, result.sons[i])
|
setVar(c, v, result.sons[i])
|
||||||
else:
|
else:
|
||||||
if a.sons[2].kind != nkEmpty:
|
if a.sons[2].kind != nkEmpty:
|
||||||
result = evalVarValue(c, a.sons[2])
|
result = evalVarValue(c, a.sons[2])
|
||||||
|
|
@ -314,7 +327,7 @@ proc evalVar(c: PEvalContext, n: PNode): PNode =
|
||||||
result = getNullValue(a.sons[0].typ, a.sons[0].info)
|
result = getNullValue(a.sons[0].typ, a.sons[0].info)
|
||||||
if a.sons[0].kind == nkSym:
|
if a.sons[0].kind == nkSym:
|
||||||
var v = a.sons[0].sym
|
var v = a.sons[0].sym
|
||||||
IdNodeTablePut(c.tos.mapping, v, result)
|
setVar(c, v, result)
|
||||||
else:
|
else:
|
||||||
# assign to a.sons[0]:
|
# assign to a.sons[0]:
|
||||||
var x = result
|
var x = result
|
||||||
|
|
@ -342,18 +355,19 @@ proc aliasNeeded(n: PNode, flags: TEvalFlags): bool =
|
||||||
proc evalVariable(c: PStackFrame, sym: PSym, flags: TEvalFlags): PNode =
|
proc evalVariable(c: PStackFrame, sym: PSym, flags: TEvalFlags): PNode =
|
||||||
# We need to return a node to the actual value,
|
# We need to return a node to the actual value,
|
||||||
# which can be modified.
|
# which can be modified.
|
||||||
|
assert sym.position != 0 or skResult == sym.kind
|
||||||
var x = c
|
var x = c
|
||||||
while x != nil:
|
while x != nil:
|
||||||
if sym.kind == skResult and x.params.len > 0:
|
if sym.owner == c.prc:
|
||||||
result = x.params[0]
|
result = x.slots[sym.position]
|
||||||
if result == nil: result = emptyNode
|
assert result != nil
|
||||||
return
|
if not aliasNeeded(result, flags):
|
||||||
result = IdNodeTableGet(x.mapping, sym)
|
|
||||||
if result != nil and not aliasNeeded(result, flags):
|
|
||||||
result = copyTree(result)
|
result = copyTree(result)
|
||||||
if result != nil: return
|
return
|
||||||
x = x.next
|
x = x.next
|
||||||
#internalError(sym.info, "cannot eval " & sym.name.s)
|
debug sym.owner
|
||||||
|
debug c.prc
|
||||||
|
internalError(sym.info, "cannot eval " & sym.name.s & " " & $sym.position)
|
||||||
result = raiseCannotEval(nil, sym.info)
|
result = raiseCannotEval(nil, sym.info)
|
||||||
#result = emptyNode
|
#result = emptyNode
|
||||||
|
|
||||||
|
|
@ -385,12 +399,12 @@ proc evalCall(c: PEvalContext, n: PNode): PNode =
|
||||||
d.call = n
|
d.call = n
|
||||||
var prc = n.sons[0]
|
var prc = n.sons[0]
|
||||||
let isClosure = prc.kind == nkClosure
|
let isClosure = prc.kind == nkClosure
|
||||||
setlen(d.params, sonsLen(n) + ord(isClosure))
|
setlen(d.slots, sonsLen(n) + ord(isClosure))
|
||||||
if isClosure:
|
if isClosure:
|
||||||
#debug prc
|
#debug prc
|
||||||
result = evalAux(c, prc.sons[1], {efLValue})
|
result = evalAux(c, prc.sons[1], {efLValue})
|
||||||
if isSpecial(result): return
|
if isSpecial(result): return
|
||||||
d.params[sonsLen(n)] = result
|
d.slots[sonsLen(n)] = result
|
||||||
result = evalAux(c, prc.sons[0], {})
|
result = evalAux(c, prc.sons[0], {})
|
||||||
else:
|
else:
|
||||||
result = evalAux(c, prc, {})
|
result = evalAux(c, prc, {})
|
||||||
|
|
@ -408,21 +422,21 @@ proc evalCall(c: PEvalContext, n: PNode): PNode =
|
||||||
for i in countup(1, sonsLen(n) - 1):
|
for i in countup(1, sonsLen(n) - 1):
|
||||||
result = evalAux(c, n.sons[i], {})
|
result = evalAux(c, n.sons[i], {})
|
||||||
if isSpecial(result): return
|
if isSpecial(result): return
|
||||||
d.params[i] = result
|
d.slots[i] = result
|
||||||
if n.typ != nil: d.params[0] = getNullValue(n.typ, n.info)
|
if n.typ != nil: d.slots[0] = getNullValue(n.typ, n.info)
|
||||||
|
|
||||||
when hasFFI:
|
when hasFFI:
|
||||||
if sfImportc in prc.sym.flags and allowFFI in c.features:
|
if sfImportc in prc.sym.flags and allowFFI in c.features:
|
||||||
var newCall = newNodeI(nkCall, n.info, n.len)
|
var newCall = newNodeI(nkCall, n.info, n.len)
|
||||||
newCall.sons[0] = evalGlobalVar(c, prc.sym, {})
|
newCall.sons[0] = evalGlobalVar(c, prc.sym, {})
|
||||||
for i in 1 .. <n.len:
|
for i in 1 .. <n.len:
|
||||||
newCall.sons[i] = d.params[i]
|
newCall.sons[i] = d.slots[i]
|
||||||
return callForeignFunction(newCall)
|
return callForeignFunction(newCall)
|
||||||
|
|
||||||
pushStackFrame(c, d)
|
pushStackFrame(c, d)
|
||||||
result = evalAux(c, prc.sym.getBody, {})
|
result = evalAux(c, prc.sym.getBody, {})
|
||||||
if result.kind == nkExceptBranch: return
|
if result.kind == nkExceptBranch: return
|
||||||
if n.typ != nil: result = d.params[0]
|
if n.typ != nil: result = d.slots[0]
|
||||||
popStackFrame(c)
|
popStackFrame(c)
|
||||||
|
|
||||||
proc evalArrayAccess(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
|
proc evalArrayAccess(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
|
||||||
|
|
@ -564,8 +578,8 @@ proc evalSym(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
|
||||||
result = evalGlobalVar(c, s, flags)
|
result = evalGlobalVar(c, s, flags)
|
||||||
of skParam:
|
of skParam:
|
||||||
# XXX what about LValue?
|
# XXX what about LValue?
|
||||||
if s.position + 1 <% c.tos.params.len:
|
if s.position + 1 <% c.tos.slots.len:
|
||||||
result = c.tos.params[s.position + 1]
|
result = c.tos.slots[s.position + 1]
|
||||||
of skConst: result = s.ast
|
of skConst: result = s.ast
|
||||||
of skEnumField: result = newIntNodeT(s.position, n)
|
of skEnumField: result = newIntNodeT(s.position, n)
|
||||||
else: result = nil
|
else: result = nil
|
||||||
|
|
@ -750,10 +764,12 @@ proc evalProc(c: PEvalContext, n: PNode): PNode =
|
||||||
if (resultPos < sonsLen(n)) and (n.sons[resultPos].kind != nkEmpty):
|
if (resultPos < sonsLen(n)) and (n.sons[resultPos].kind != nkEmpty):
|
||||||
var v = n.sons[resultPos].sym
|
var v = n.sons[resultPos].sym
|
||||||
result = getNullValue(v.typ, n.info)
|
result = getNullValue(v.typ, n.info)
|
||||||
IdNodeTablePut(c.tos.mapping, v, result)
|
if c.tos.slots.len == 0: setLen(c.tos.slots, 1)
|
||||||
|
c.tos.slots[0] = result
|
||||||
|
#IdNodeTablePut(c.tos.mapping, v, result)
|
||||||
result = evalAux(c, s.getBody, {})
|
result = evalAux(c, s.getBody, {})
|
||||||
if result.kind == nkReturnToken:
|
if result.kind == nkReturnToken:
|
||||||
result = IdNodeTableGet(c.tos.mapping, v)
|
result = c.tos.slots[0]
|
||||||
else:
|
else:
|
||||||
result = evalAux(c, s.getBody, {})
|
result = evalAux(c, s.getBody, {})
|
||||||
if result.kind == nkReturnToken:
|
if result.kind == nkReturnToken:
|
||||||
|
|
@ -1507,16 +1523,17 @@ proc evalMacroCall(c: PEvalContext, n, nOrig: PNode, sym: PSym): PNode =
|
||||||
c.callsite = nOrig
|
c.callsite = nOrig
|
||||||
var s = newStackFrame()
|
var s = newStackFrame()
|
||||||
s.call = n
|
s.call = n
|
||||||
|
s.prc = sym
|
||||||
var L = n.safeLen
|
var L = n.safeLen
|
||||||
if L == 0: L = 1
|
if L == 0: L = 1
|
||||||
setlen(s.params, L)
|
setlen(s.slots, L)
|
||||||
# return value:
|
# return value:
|
||||||
s.params[0] = newNodeIT(nkNilLit, n.info, sym.typ.sons[0])
|
s.slots[0] = newNodeIT(nkNilLit, n.info, sym.typ.sons[0])
|
||||||
# setup parameters:
|
# setup parameters:
|
||||||
for i in 1 .. < L: s.params[i] = setupMacroParam(n.sons[i])
|
for i in 1 .. < L: s.slots[i] = setupMacroParam(n.sons[i])
|
||||||
pushStackFrame(c, s)
|
pushStackFrame(c, s)
|
||||||
discard eval(c, sym.getBody)
|
discard eval(c, sym.getBody)
|
||||||
result = s.params[0]
|
result = s.slots[0]
|
||||||
popStackFrame(c)
|
popStackFrame(c)
|
||||||
if cyclicTree(result): GlobalError(n.info, errCyclicTree)
|
if cyclicTree(result): GlobalError(n.info, errCyclicTree)
|
||||||
dec(evalTemplateCounter)
|
dec(evalTemplateCounter)
|
||||||
|
|
|
||||||
|
|
@ -417,6 +417,15 @@ proc putArgInto(arg: PNode, formal: PType): TPutArgInto =
|
||||||
if skipTypes(formal, abstractInst).kind == tyVar: result = paVarAsgn
|
if skipTypes(formal, abstractInst).kind == tyVar: result = paVarAsgn
|
||||||
else: result = paFastAsgn
|
else: result = paFastAsgn
|
||||||
|
|
||||||
|
proc findWrongOwners(c: PTransf, n: PNode) =
|
||||||
|
if n.kind == nkVarSection:
|
||||||
|
let x = n.sons[0].sons[0]
|
||||||
|
if x.kind == nkSym and x.sym.owner != getCurrOwner(c):
|
||||||
|
internalError(x.info, "bah " & x.sym.name.s & " " &
|
||||||
|
x.sym.owner.name.s & " " & getCurrOwner(c).name.s)
|
||||||
|
else:
|
||||||
|
for i in 0 .. <safeLen(n): findWrongOwners(c, n.sons[i])
|
||||||
|
|
||||||
proc transformFor(c: PTransf, n: PNode): PTransNode =
|
proc transformFor(c: PTransf, n: PNode): PTransNode =
|
||||||
# generate access statements for the parameters (unless they are constant)
|
# generate access statements for the parameters (unless they are constant)
|
||||||
# put mapping from formal parameters to actual parameters
|
# put mapping from formal parameters to actual parameters
|
||||||
|
|
@ -468,6 +477,7 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
|
||||||
pushInfoContext(n.info)
|
pushInfoContext(n.info)
|
||||||
inc(c.inlining)
|
inc(c.inlining)
|
||||||
add(result, transform(c, body))
|
add(result, transform(c, body))
|
||||||
|
#findWrongOwners(c, result.pnode)
|
||||||
dec(c.inlining)
|
dec(c.inlining)
|
||||||
popInfoContext()
|
popInfoContext()
|
||||||
popTransCon(c)
|
popTransCon(c)
|
||||||
|
|
@ -675,12 +685,12 @@ proc transform(c: PTransf, n: PNode): PTransNode =
|
||||||
if cnst != nil and not dontInlineConstant(n, cnst):
|
if cnst != nil and not dontInlineConstant(n, cnst):
|
||||||
result = PTransNode(cnst) # do not miss an optimization
|
result = PTransNode(cnst) # do not miss an optimization
|
||||||
|
|
||||||
proc processTransf(c: PTransf, n: PNode): PNode =
|
proc processTransf(c: PTransf, n: PNode, owner: PSym): PNode =
|
||||||
# Note: For interactive mode we cannot call 'passes.skipCodegen' and skip
|
# Note: For interactive mode we cannot call 'passes.skipCodegen' and skip
|
||||||
# this step! We have to rely that the semantic pass transforms too errornous
|
# this step! We have to rely that the semantic pass transforms too errornous
|
||||||
# nodes into an empty node.
|
# nodes into an empty node.
|
||||||
if passes.skipCodegen(n) or c.fromCache or nfTransf in n.flags: return n
|
if passes.skipCodegen(n) or c.fromCache or nfTransf in n.flags: return n
|
||||||
pushTransCon(c, newTransCon(getCurrOwner(c)))
|
pushTransCon(c, newTransCon(owner))
|
||||||
result = PNode(transform(c, n))
|
result = PNode(transform(c, n))
|
||||||
popTransCon(c)
|
popTransCon(c)
|
||||||
incl(result.flags, nfTransf)
|
incl(result.flags, nfTransf)
|
||||||
|
|
@ -691,22 +701,13 @@ proc openTransf(module: PSym, filename: string): PTransf =
|
||||||
result.breakSyms = @[]
|
result.breakSyms = @[]
|
||||||
result.module = module
|
result.module = module
|
||||||
|
|
||||||
when false:
|
|
||||||
proc openTransfCached(module: PSym, filename: string,
|
|
||||||
rd: PRodReader): PPassContext =
|
|
||||||
result = openTransf(module, filename)
|
|
||||||
for m in items(rd.methods): methodDef(m, true)
|
|
||||||
|
|
||||||
const transfPass* = makePass(openTransf, openTransfCached,
|
|
||||||
processTransf, processTransf) # we need to process generics too!
|
|
||||||
|
|
||||||
proc transformBody*(module: PSym, n: PNode, prc: PSym): PNode =
|
proc transformBody*(module: PSym, n: PNode, prc: PSym): PNode =
|
||||||
if nfTransf in n.flags or prc.kind in {skTemplate, skMacro}:
|
if nfTransf in n.flags or prc.kind in {skTemplate, skMacro}:
|
||||||
result = n
|
result = n
|
||||||
else:
|
else:
|
||||||
#when useEffectSystem: trackProc(prc, n)
|
#when useEffectSystem: trackProc(prc, n)
|
||||||
var c = openTransf(module, "")
|
var c = openTransf(module, "")
|
||||||
result = processTransf(c, n)
|
result = processTransf(c, n, prc)
|
||||||
if prc.kind != skMacro:
|
if prc.kind != skMacro:
|
||||||
# XXX no closures yet for macros:
|
# XXX no closures yet for macros:
|
||||||
result = liftLambdas(prc, result)
|
result = liftLambdas(prc, result)
|
||||||
|
|
@ -720,7 +721,7 @@ proc transformStmt*(module: PSym, n: PNode): PNode =
|
||||||
result = n
|
result = n
|
||||||
else:
|
else:
|
||||||
var c = openTransf(module, "")
|
var c = openTransf(module, "")
|
||||||
result = processTransf(c, n)
|
result = processTransf(c, n, module)
|
||||||
result = liftLambdasForTopLevel(module, result)
|
result = liftLambdasForTopLevel(module, result)
|
||||||
incl(result.flags, nfTransf)
|
incl(result.flags, nfTransf)
|
||||||
|
|
||||||
|
|
@ -729,5 +730,5 @@ proc transformExpr*(module: PSym, n: PNode): PNode =
|
||||||
result = n
|
result = n
|
||||||
else:
|
else:
|
||||||
var c = openTransf(module, "")
|
var c = openTransf(module, "")
|
||||||
result = processTransf(c, n)
|
result = processTransf(c, n, module)
|
||||||
incl(result.flags, nfTransf)
|
incl(result.flags, nfTransf)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue