some small performance improvement for the evaluator

This commit is contained in:
Araq 2013-06-28 23:36:43 +02:00
commit a8542fbe06
3 changed files with 69 additions and 50 deletions

View file

@ -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

View file

@ -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)

View file

@ -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)