summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2013-06-28 23:36:43 +0200
committerAraq <rumpf_a@web.de>2013-06-28 23:36:43 +0200
commita8542fbe0654d2236dc25eb42c111b470416b82e (patch)
tree257db5584d1388d538c1056e65699795578282b7
parent976d5b18edf1e650db21c4f5e6990c037ed305a7 (diff)
downloadNim-a8542fbe0654d2236dc25eb42c111b470416b82e.tar.gz
some small performance improvement for the evaluator
-rw-r--r--compiler/ast.nim1
-rw-r--r--compiler/evals.nim89
-rw-r--r--compiler/transf.nim29
3 files changed, 69 insertions, 50 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index eee1e1ad2..3456177d3 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -666,6 +666,7 @@ type
                               # (or not in symbol table)
                               # for modules, an unique index corresponding
                               # to the module's fileIdx
+                              # for variables a slot index for the evaluator
 
     offset*: int              # offset of record field
     loc*: TLoc
diff --git a/compiler/evals.nim b/compiler/evals.nim
index 8c05d57fc..1689a37d8 100644
--- a/compiler/evals.nim
+++ b/compiler/evals.nim
@@ -23,12 +23,12 @@ when hasFFI:
 
 type 
   PStackFrame* = ref TStackFrame
-  TStackFrame*{.final.} = object 
-    mapping*: TIdNodeTable    # mapping from symbols to nodes
-    prc*: PSym                # current prc; proc that is evaluated
-    call*: PNode
-    next*: PStackFrame        # for stacking
-    params*: TNodeSeq         # parameters passed to the proc
+  TStackFrame* = object
+    prc: PSym                 # current prc; proc that is evaluated
+    slots: TNodeSeq           # parameters passed to the proc + locals;
+                              # parameters come first
+    call: PNode
+    next: PStackFrame         # for stacking
   
   TEvalMode* = enum           ## reason for evaluation
     emRepl,                   ## evaluate because in REPL mode
@@ -67,10 +67,9 @@ const
 # other idea: use a timeout! -> Wether code compiles depends on the machine
 # the compiler runs on then! Bad idea!
 
-proc newStackFrame*(): PStackFrame = 
+proc newStackFrame*(): PStackFrame =
   new(result)
-  initIdNodeTable(result.mapping)
-  result.params = @[]
+  result.slots = @[]
 
 proc newEvalContext*(module: PSym, mode: TEvalMode): PEvalContext =
   new(result)
@@ -291,6 +290,20 @@ proc evalVarValue(c: PEvalContext, n: PNode): PNode =
   result = evalAux(c, n, {})
   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 =
   for i in countup(0, sonsLen(n) - 1):
     let a = n.sons[i]
@@ -305,7 +318,7 @@ proc evalVar(c: PEvalContext, n: PNode): PNode =
         return raiseCannotEval(c, n.info)
       for i in 0 .. a.len-3:
         var v = a.sons[i].sym
-        IdNodeTablePut(c.tos.mapping, v, result.sons[i])
+        setVar(c, v, result.sons[i])
     else:
       if a.sons[2].kind != nkEmpty:
         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)
       if a.sons[0].kind == nkSym:
         var v = a.sons[0].sym
-        IdNodeTablePut(c.tos.mapping, v, result)
+        setVar(c, v, result)
       else:
         # assign to a.sons[0]:
         var x = result
@@ -339,21 +352,22 @@ proc aliasNeeded(n: PNode, flags: TEvalFlags): bool =
   result = efLValue in flags or n.typ == nil or 
     n.typ.kind in {tyExpr, tyStmt, tyTypeDesc}
 
-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,
   # which can be modified.
+  assert sym.position != 0 or skResult == sym.kind
   var x = c
-  while x != nil: 
-    if sym.kind == skResult and x.params.len > 0:
-      result = x.params[0]
-      if result == nil: result = emptyNode
+  while x != nil:
+    if sym.owner == c.prc:
+      result = x.slots[sym.position]
+      assert result != nil
+      if not aliasNeeded(result, flags):
+        result = copyTree(result)
       return
-    result = IdNodeTableGet(x.mapping, sym)
-    if result != nil and not aliasNeeded(result, flags): 
-      result = copyTree(result)
-    if result != nil: return 
     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 = emptyNode
 
@@ -385,12 +399,12 @@ proc evalCall(c: PEvalContext, n: PNode): PNode =
   d.call = n
   var prc = n.sons[0]
   let isClosure = prc.kind == nkClosure
-  setlen(d.params, sonsLen(n) + ord(isClosure))
+  setlen(d.slots, sonsLen(n) + ord(isClosure))
   if isClosure:
     #debug prc
     result = evalAux(c, prc.sons[1], {efLValue})
     if isSpecial(result): return
-    d.params[sonsLen(n)] = result
+    d.slots[sonsLen(n)] = result
     result = evalAux(c, prc.sons[0], {})
   else:
     result = evalAux(c, prc, {})
@@ -408,21 +422,21 @@ proc evalCall(c: PEvalContext, n: PNode): PNode =
   for i in countup(1, sonsLen(n) - 1): 
     result = evalAux(c, n.sons[i], {})
     if isSpecial(result): return 
-    d.params[i] = result
-  if n.typ != nil: d.params[0] = getNullValue(n.typ, n.info)
+    d.slots[i] = result
+  if n.typ != nil: d.slots[0] = getNullValue(n.typ, n.info)
   
   when hasFFI:
     if sfImportc in prc.sym.flags and allowFFI in c.features:
       var newCall = newNodeI(nkCall, n.info, n.len)
       newCall.sons[0] = evalGlobalVar(c, prc.sym, {})
       for i in 1 .. <n.len:
-        newCall.sons[i] = d.params[i]
+        newCall.sons[i] = d.slots[i]
       return callForeignFunction(newCall)
   
   pushStackFrame(c, d)
   result = evalAux(c, prc.sym.getBody, {})
   if result.kind == nkExceptBranch: return 
-  if n.typ != nil: result = d.params[0]
+  if n.typ != nil: result = d.slots[0]
   popStackFrame(c)
 
 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)
   of skParam:
     # XXX what about LValue?
-    if s.position + 1 <% c.tos.params.len:
-      result = c.tos.params[s.position + 1]
+    if s.position + 1 <% c.tos.slots.len:
+      result = c.tos.slots[s.position + 1]
   of skConst: result = s.ast
   of skEnumField: result = newIntNodeT(s.position, n)
   else: result = nil
@@ -750,10 +764,12 @@ proc evalProc(c: PEvalContext, n: PNode): PNode =
     if (resultPos < sonsLen(n)) and (n.sons[resultPos].kind != nkEmpty): 
       var v = n.sons[resultPos].sym
       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, {})
-      if result.kind == nkReturnToken: 
-        result = IdNodeTableGet(c.tos.mapping, v)
+      if result.kind == nkReturnToken:
+        result = c.tos.slots[0]
     else:
       result = evalAux(c, s.getBody, {})
       if result.kind == nkReturnToken: 
@@ -1507,16 +1523,17 @@ proc evalMacroCall(c: PEvalContext, n, nOrig: PNode, sym: PSym): PNode =
   c.callsite = nOrig
   var s = newStackFrame()
   s.call = n
+  s.prc = sym
   var L = n.safeLen
   if L == 0: L = 1
-  setlen(s.params, L)
+  setlen(s.slots, L)
   # 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:
-  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)
   discard eval(c, sym.getBody)
-  result = s.params[0]
+  result = s.slots[0]
   popStackFrame(c)
   if cyclicTree(result): GlobalError(n.info, errCyclicTree)
   dec(evalTemplateCounter)
diff --git a/compiler/transf.nim b/compiler/transf.nim
index a35669e1d..82122d776 100644
--- a/compiler/transf.nim
+++ b/compiler/transf.nim
@@ -417,6 +417,15 @@ proc putArgInto(arg: PNode, formal: PType): TPutArgInto =
     if skipTypes(formal, abstractInst).kind == tyVar: result = paVarAsgn
     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 = 
   # generate access statements for the parameters (unless they are constant)
   # put mapping from formal parameters to actual parameters
@@ -468,6 +477,7 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
   pushInfoContext(n.info)
   inc(c.inlining)
   add(result, transform(c, body))
+  #findWrongOwners(c, result.pnode)
   dec(c.inlining)
   popInfoContext()
   popTransCon(c)
@@ -675,12 +685,12 @@ proc transform(c: PTransf, n: PNode): PTransNode =
   if cnst != nil and not dontInlineConstant(n, cnst):
     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
   # this step! We have to rely that the semantic pass transforms too errornous
   # nodes into an empty node.
   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))
   popTransCon(c)
   incl(result.flags, nfTransf)
@@ -691,22 +701,13 @@ proc openTransf(module: PSym, filename: string): PTransf =
   result.breakSyms = @[]
   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 =
   if nfTransf in n.flags or prc.kind in {skTemplate, skMacro}:
     result = n
   else:
     #when useEffectSystem: trackProc(prc, n)
     var c = openTransf(module, "")
-    result = processTransf(c, n)
+    result = processTransf(c, n, prc)
     if prc.kind != skMacro:
       # XXX no closures yet for macros:
       result = liftLambdas(prc, result)
@@ -720,7 +721,7 @@ proc transformStmt*(module: PSym, n: PNode): PNode =
     result = n
   else:
     var c = openTransf(module, "")
-    result = processTransf(c, n)
+    result = processTransf(c, n, module)
     result = liftLambdasForTopLevel(module, result)
     incl(result.flags, nfTransf)
 
@@ -729,5 +730,5 @@ proc transformExpr*(module: PSym, n: PNode): PNode =
     result = n
   else:
     var c = openTransf(module, "")
-    result = processTransf(c, n)
+    result = processTransf(c, n, module)
     incl(result.flags, nfTransf)