summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2013-12-12 01:34:01 +0100
committerAraq <rumpf_a@web.de>2013-12-12 01:34:01 +0100
commit6db20a4be8556621b3a33f87854b4b857c4dcf9e (patch)
treeb160173ad85e9c75f2a11d4746b971cac5c9e8ac
parent29357ab556a25ea75d0cf837eace079b46d51fc8 (diff)
downloadNim-6db20a4be8556621b3a33f87854b4b857c4dcf9e.tar.gz
new VM: improvements
-rw-r--r--compiler/semexprs.nim6
-rw-r--r--compiler/semmagic.nim17
-rw-r--r--compiler/vm.nim78
-rw-r--r--compiler/vmdef.nim3
-rw-r--r--compiler/vmgen.nim60
-rw-r--r--tests/compile/tircbot.nim6
-rw-r--r--todo.txt1
7 files changed, 114 insertions, 57 deletions
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 13bfddab7..4b263b3a3 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -300,11 +300,11 @@ proc semOf(c: PContext, n: PNode): PNode =
   result = n
 
 proc isOpImpl(c: PContext, n: PNode): PNode =
-  InternalAssert n.sonsLen == 3 and
-    n[1].kind == nkSym and n[1].sym.kind == skType and
+  internalAssert n.sonsLen == 3 and
+    n[1].typ != nil and
     n[2].kind in {nkStrLit..nkTripleStrLit, nkType}
   
-  let t1 = n[1].sym.typ.skipTypes({tyTypeDesc})
+  let t1 = n[1].typ.skipTypes({tyTypeDesc})
 
   if n[2].kind in {nkStrLit..nkTripleStrLit}:
     case n[2].strVal.normalize
diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim
index 44e106678..a5f763519 100644
--- a/compiler/semmagic.nim
+++ b/compiler/semmagic.nim
@@ -33,10 +33,8 @@ proc semInstantiationInfo(c: PContext, n: PNode): PNode =
   result.add(line)
 
  
-proc evalTypeTrait(trait, operand: PNode, context: PSym): PNode =
-  InternalAssert operand.kind == nkSym
-
-  let typ = operand.sym.typ.skipTypes({tyTypeDesc})
+proc evalTypeTrait(trait: PNode, operand: PType, context: PSym): PNode =
+  let typ = operand.skipTypes({tyTypeDesc})
   case trait.sym.name.s.normalize
   of "name":
     result = newStrNode(nkStrLit, typ.typeToString(preferName))
@@ -51,13 +49,10 @@ proc evalTypeTrait(trait, operand: PNode, context: PSym): PNode =
 
 proc semTypeTraits(c: PContext, n: PNode): PNode =
   checkMinSonsLen(n, 2)
-  internalAssert n.sons[1].kind == nkSym
-  let typArg = n.sons[1].sym
-  if typArg.kind == skType or
-    (typArg.kind == skParam and typArg.typ.sonsLen > 0):
-    # This is either a type known to sem or a typedesc
-    # param to a regular proc (again, known at instantiation)
-    result = evalTypeTrait(n[0], n[1], GetCurrOwner())
+  let t = n.sons[1].typ
+  internalAssert t != nil
+  if not containsGenericType(t):
+    result = evalTypeTrait(n[0], t, GetCurrOwner())
   else:
     # a typedesc variable, pass unmodified to evals
     result = n
diff --git a/compiler/vm.nim b/compiler/vm.nim
index 94ff8a4c7..984cc4bb8 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -52,9 +52,9 @@ proc stackTraceAux(c: PCtx; x: PStackFrame; pc: int) =
 
 proc stackTrace(c: PCtx, tos: PStackFrame, pc: int,
                 msg: TMsgKind, arg = "") =
-  MsgWriteln("stack trace: (most recent call last)")
+  msgWriteln("stack trace: (most recent call last)")
   stackTraceAux(c, tos, pc)
-  LocalError(c.debug[pc], msg, arg)
+  localError(c.debug[pc], msg, arg)
 
 proc bailOut(c: PCtx; tos: PStackFrame) =
   stackTrace(c, tos, c.exceptionInstr, errUnhandledExceptionX,
@@ -63,9 +63,6 @@ proc bailOut(c: PCtx; tos: PStackFrame) =
 when not defined(nimComputedGoto):
   {.pragma: computedGoto.}
 
-template inc(pc: ptr TInstr, diff = 1) =
-  inc cast[TAddress](pc), TInstr.sizeof * diff
-
 proc myreset(n: PNode) =
   when defined(system.reset): 
     var oldInfo = n.info
@@ -299,6 +296,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
     let instr = c.code[pc]
     let ra = instr.regA
     #echo "PC ", pc, " ", c.code[pc].opcode, " ra ", ra
+    #message(c.debug[pc], warnUser, "gah")
     case instr.opcode
     of opcEof: return regs[ra]
     of opcRet:
@@ -338,25 +336,38 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
       # a = b[c]
       let rb = instr.regB
       let rc = instr.regC
-      let idx = regs[rc].intVal
+      let idx = regs[rc].intVal.int
       # XXX what if the array is not 0-based? -> codegen should insert a sub
       assert regs[rb].kind != nkMetaNode
-      asgnComplex(regs[ra], regs[rb].sons[idx.int])
+      let src = regs[rb]
+      if src.kind notin {nkEmpty..nkNilLit} and idx <% src.len:
+        asgnComplex(regs[ra], src.sons[idx])
+      else:
+        stackTrace(c, tos, pc, errIndexOutOfBounds)
     of opcLdStrIdx:
       decodeBC(nkIntLit)
-      let idx = regs[rc].intVal
-      regs[ra].intVal = regs[rb].strVal[idx.int].ord
+      let idx = regs[rc].intVal.int
+      if idx <=% regs[rb].strVal.len:
+        regs[ra].intVal = regs[rb].strVal[idx].ord
+      else:
+        stackTrace(c, tos, pc, errIndexOutOfBounds)
     of opcWrArr:
       # a[b] = c
       let rb = instr.regB
       let rc = instr.regC
-      let idx = regs[rb].intVal
-      asgnComplex(regs[ra].sons[idx.int], regs[rc])
+      let idx = regs[rb].intVal.int
+      if idx <% regs[ra].len:
+        asgnComplex(regs[ra].sons[idx], regs[rc])
+      else:
+        stackTrace(c, tos, pc, errIndexOutOfBounds)
     of opcWrArrRef:
       let rb = instr.regB
       let rc = instr.regC
-      let idx = regs[rb].intVal
-      asgnRef(regs[ra].sons[idx.int], regs[rc])
+      let idx = regs[rb].intVal.int
+      if idx <% regs[ra].len:
+        asgnRef(regs[ra].sons[idx], regs[rc])
+      else:
+        stackTrace(c, tos, pc, errIndexOutOfBounds)
     of opcLdObj:
       # a = b.c
       let rb = instr.regB
@@ -381,7 +392,10 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
     of opcWrStrIdx:
       decodeBC(nkStrLit)
       let idx = regs[rb].intVal.int
-      regs[ra].strVal[idx] = chr(regs[rc].intVal)
+      if idx <% regs[ra].strVal.len:
+        regs[ra].strVal[idx] = chr(regs[rc].intVal)
+      else:
+        stackTrace(c, tos, pc, errIndexOutOfBounds)
     of opcAddr:
       decodeB(nkRefTy)
       if regs[ra].len == 0: regs[ra].add regs[rb]
@@ -631,7 +645,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
         #echo "new pc ", newPc, " calling: ", prc.name.s
         var newFrame = PStackFrame(prc: prc, comesFrom: pc, next: tos)
         newSeq(newFrame.slots, prc.offset)
-        if not isEmptyType(prc.typ.sons[0]):
+        if not isEmptyType(prc.typ.sons[0]) or prc.kind == skMacro:
           newFrame.slots[0] = getNullValue(prc.typ.sons[0], prc.info)
         # pass every parameter by var (the language definition allows this):
         for i in 1 .. rc-1:
@@ -769,7 +783,15 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
       regs[ra].strVal.setLen(regs[rb].getOrdValue.int)
     of opcOf:
       decodeBC(nkIntLit)
-      regs[ra].intVal = ord(inheritanceDiff(regs[rb].typ, regs[rc].typ) >= 0)
+      let typ = c.types[regs[rc].intVal.int]
+      regs[ra].intVal = ord(inheritanceDiff(regs[rb].typ, typ) >= 0)
+    of opcIs:
+      decodeBC(nkIntLit)
+      let t1 = regs[rb].typ.skipTypes({tyTypeDesc})
+      let t2 = c.types[regs[rc].intVal.int]
+      let match = if t2.kind == tyTypeClass: matchTypeClass(t2, t1)
+                  else: sameType(t1, t2)
+      regs[ra].intVal = ord(match)
     of opcSetLenSeq:
       decodeB(nkBracket)
       let newLen = regs[rb].getOrdValue.int
@@ -787,10 +809,20 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
       decodeBC(nkMetaNode)
       if regs[rb].kind != nkMetaNode:
         internalError(c.debug[pc], "no MetaNode")
-      setMeta(regs[ra], regs[rb].uast.sons[regs[rc].intVal.int])
+      let idx = regs[rc].intVal.int
+      let src = regs[rb].uast
+      if src.kind notin {nkEmpty..nkNilLit} and idx <% src.len:
+        setMeta(regs[ra], src.sons[idx])
+      else:
+        stackTrace(c, tos, pc, errIndexOutOfBounds)
     of opcNSetChild:
       decodeBC(nkMetaNode)
-      regs[ra].uast.sons[regs[rb].intVal.int] = regs[rc].uast
+      let idx = regs[rb].intVal.int
+      var dest = regs[ra].uast
+      if dest.kind notin {nkEmpty..nkNilLit} and idx <% dest.len:
+        dest.sons[idx] = regs[rc].uast
+      else:
+        stackTrace(c, tos, pc, errIndexOutOfBounds)
     of opcNAdd:
       decodeBC(nkMetaNode)
       var u = regs[rb].uast
@@ -986,6 +1018,15 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
       decodeB(nkStrLit)
       let typ = regs[rb].sym.typ.skipTypes({tyTypeDesc})
       regs[ra].strVal = typ.typeToString(preferExported)
+    of opcGlobalOnce:
+      let rb = instr.regBx
+      if c.globals.sons[rb - wordExcess - 1].kind != nkEmpty:
+        # skip initialization instructions:
+        while true:
+          inc pc
+          if c.code[pc].opcode in {opcWrGlobal, opcWrGlobalRef} and
+             c.code[pc].regBx == rb:
+            break
     inc pc
 
 proc fixType(result, n: PNode) {.inline.} =
@@ -1073,6 +1114,7 @@ proc setupMacroParam(x: PNode): PNode =
   y.flags.incl nfIsRef
   result = newNode(nkMetaNode)
   result.add y
+  result.typ = x.typ
 
 var evalMacroCounter: int
 
diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim
index 290dfd38c..e31dc9de6 100644
--- a/compiler/vmdef.nim
+++ b/compiler/vmdef.nim
@@ -60,7 +60,7 @@ type
     opcEqStr, opcLeStr, opcLtStr, opcEqSet, opcLeSet, opcLtSet,
     opcMulSet, opcPlusSet, opcMinusSet, opcSymdiffSet, opcConcatStr,
     opcContainsSet, opcRepr, opcSetLenStr, opcSetLenSeq,
-    opcSwap, opcIsNil, opcOf, 
+    opcSwap, opcIsNil, opcOf, opcIs,
     opcSubStr, opcConv, opcCast, opcQuit, opcReset,
     
     opcAddStrCh,
@@ -122,6 +122,7 @@ type
     opcLdImmInt,  # dest = immediate value
     opcWrGlobal,
     opcWrGlobalRef,
+    opcGlobalOnce,  # used to introduce an assignment to a global once
     opcSetType,   # dest.typ = types[Bx]
     opcTypeTrait
 
diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim
index 62b9e7d1e..6f07a2dfe 100644
--- a/compiler/vmgen.nim
+++ b/compiler/vmgen.nim
@@ -301,7 +301,8 @@ proc sameConstant*(a, b: PNode): bool =
     of nkCharLit..nkInt64Lit: result = a.intVal == b.intVal
     of nkFloatLit..nkFloat64Lit: result = a.floatVal == b.floatVal
     of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal
-    of nkEmpty, nkNilLit, nkType: result = true
+    of nkType: result = a.typ == b.typ
+    of nkEmpty, nkNilLit: result = true
     else: 
       if sonsLen(a) == sonsLen(b): 
         for i in countup(0, sonsLen(a) - 1): 
@@ -674,12 +675,16 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
     unused(n, dest)
     var d = c.genx(n.sons[1])
     c.gABC(n, opcReset, d)
-  of mOf: 
+  of mOf, mIs:
     if dest < 0: dest = c.getTemp(n.typ)
     var tmp = c.genx(n.sons[1])
-    c.gABC(n, opcOf, dest, tmp)
-    c.gABx(n, opcOf, 0, c.genType(n.sons[2].typ.skipTypes(abstractPtrs)))
+    var idx = c.getTemp(getSysType(tyInt))
+    var typ = n.sons[2].typ
+    if m == mOf: typ = typ.skipTypes(abstractPtrs)
+    c.gABx(n, opcLdImmInt, idx, c.genType(typ))
+    c.gABC(n, if m == mOf: opcOf else: opcIs, dest, tmp, idx)
     c.freeTemp(tmp)
+    c.freeTemp(idx)
   of mSizeOf:
     GlobalError(n.info, errCannotInterpretNodeX, renderTree(n))
   of mHigh:
@@ -717,8 +722,6 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
     c.gABx(n, opcSetType, tmp, c.genType(n.sons[1].typ))
     c.gABC(n, opcTypeTrait, dest, tmp)
     c.freeTemp(tmp)
-  of mIs:
-    InternalError(n.info, "cannot generate code for: " & $m)
   of mSlurp: genUnaryABC(c, n, dest, opcSlurp)
   of mStaticExec: genBinaryABC(c, n, dest, opcGorge)
   of mNLen: genUnaryABI(c, n, dest, opcLenSeq)
@@ -905,6 +908,11 @@ proc genLit(c: PCtx; n: PNode; dest: var TDest) =
   let lit = genLiteral(c, n)
   c.gABx(n, opc, dest, lit)
 
+proc genTypeLit(c: PCtx; t: PType; dest: var TDest) =
+  var n = newNode(nkType)
+  n.typ = t
+  genLit(c, n, dest)
+
 proc importcSym(c: PCtx; info: TLineInfo; s: PSym) =
   when hasFFI:
     if allowFFI in c.features:
@@ -920,6 +928,17 @@ proc cannotEval(n: PNode) {.noinline.} =
   globalError(n.info, errGenerated, "cannot evaluate at compile time: " &
     n.renderTree)
 
+proc genGlobalInit(c: PCtx; n: PNode; s: PSym) =
+  c.globals.add(emptyNode)
+  s.position = c.globals.len
+  # This is rather hard to support, due to the laziness of the VM code
+  # generator. See tests/compile/tmacro2 for why this is necesary:
+  #   var decls{.compileTime.}: seq[PNimrodNode] = @[]
+  c.gABx(n, opcGlobalOnce, 0, s.position)
+  let tmp = c.genx(s.ast)
+  c.gABx(n, whichAsgnOpc(n, opcWrGlobal), tmp, s.position)
+  c.freeTemp(tmp)
+
 proc genRdVar(c: PCtx; n: PNode; dest: var TDest) =
   let s = n.sym
   if s.isGlobal:
@@ -930,10 +949,7 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest) =
     if dest < 0: dest = c.getTemp(s.typ)
     if s.position == 0:
       if sfImportc in s.flags: c.importcSym(n.info, s)
-      else:
-        c.globals.add(s.ast)
-        s.position = c.globals.len
-      # XXX var g = codeHere() ?
+      else: genGlobalInit(c, n, s)
     c.gABx(n, opcLdGlobal, dest, s.position)
   else:
     if s.position > 0 or (s.position == 0 and s.kind in {skParam, skResult}):
@@ -1052,6 +1068,7 @@ proc genVarSection(c: PCtx; n: PNode) =
             let sa = if s.ast.isNil: getNullValue(s.typ, a.info) else: s.ast
             c.globals.add(sa)
             s.position = c.globals.len
+            # "Once support" is unnecessary here
         if a.sons[2].kind == nkEmpty:
           when false:
             withTemp(tmp, s.typ):
@@ -1079,15 +1096,16 @@ proc genVarSection(c: PCtx; n: PNode) =
 proc genArrayConstr(c: PCtx, n: PNode, dest: var TDest) =
   if dest < 0: dest = c.getTemp(n.typ)
   c.gABx(n, opcLdNull, dest, c.genType(n.typ))
-  let intType = getSysType(tyInt)
-  var tmp = getTemp(c, intType)
-  c.gABx(n, opcLdNull, tmp, c.genType(intType))
-  for x in n:
-    let a = c.genx(x)
-    c.gABC(n, whichAsgnOpc(x, opcWrArr), dest, tmp, a)
-    c.gABI(n, opcAddImmInt, tmp, tmp, 1)
-    c.freeTemp(a)
-  c.freeTemp(tmp)
+  if n.len > 0:
+    let intType = getSysType(tyInt)
+    var tmp = getTemp(c, intType)
+    c.gABx(n, opcLdNull, tmp, c.genType(intType))
+    for x in n:
+      let a = c.genx(x)
+      c.gABC(n, whichAsgnOpc(x, opcWrArr), dest, tmp, a)
+      c.gABI(n, opcAddImmInt, tmp, tmp, 1)
+      c.freeTemp(a)
+    c.freeTemp(tmp)
 
 proc genSetConstr(c: PCtx, n: PNode, dest: var TDest) =
   if dest < 0: dest = c.getTemp(n.typ)
@@ -1167,6 +1185,8 @@ proc gen(c: PCtx; n: PNode; dest: var TDest) =
         InternalError(n.info, 
           "too large offset! cannot generate code for: " & s.name.s)
       dest = s.position
+    of skType:
+      genTypeLit(c, s.typ, dest)
     else:
       InternalError(n.info, "cannot generate code for: " & s.name.s)
   of nkCallKinds:
@@ -1371,7 +1391,7 @@ proc genProc(c: PCtx; s: PSym): int =
     c.gABC(body, opcEof, eofInstr.regA)
     c.optimizeJumps(result)
     s.offset = c.prc.maxSlots
-    #if s.name.s == "treeRepr" or s.name.s == "traverse":
+    #if s.name.s == "importImpl_forward" or s.name.s == "importImpl":
     #  c.echoCode(result)
     #  echo renderTree(body)
     c.prc = oldPrc
diff --git a/tests/compile/tircbot.nim b/tests/compile/tircbot.nim
index d16c99b69..6008838ff 100644
--- a/tests/compile/tircbot.nim
+++ b/tests/compile/tircbot.nim
@@ -257,7 +257,7 @@ proc limitCommitMsg(m: string): string =
 proc handleWebMessage(state: PState, line: string) =
   echo("Got message from hub: " & line)
   var json = parseJson(line)
-  if json.existsKey("payload"):
+  if json.hasKey("payload"):
     for i in 0..min(4, json["payload"]["commits"].len-1):
       var commit = json["payload"]["commits"][i]
       # Create the message
@@ -273,8 +273,8 @@ proc handleWebMessage(state: PState, line: string) =
 
       # Send message to #nimrod.
       state.ircClient.privmsg(joinChans[0], message)
-  elif json.existsKey("redisinfo"):
-    assert json["redisinfo"].existsKey("port")
+  elif json.hasKey("redisinfo"):
+    assert json["redisinfo"].hasKey("port")
     #let redisPort = json["redisinfo"]["port"].num
     state.dbConnected = true
 
diff --git a/todo.txt b/todo.txt
index 91df38a14..4c999226f 100644
--- a/todo.txt
+++ b/todo.txt
@@ -20,7 +20,6 @@ Bugs
 - bug: 'type T = ref T' not recognized as illegal recursion
 - bug: type conversions concerning proc types are weird
 - compilation of niminst takes way too long. looks like a regression
-- simple closure iterator doesn't work
 - docgen: sometimes effects are listed twice
 - 'result' is not properly cleaned for NRVO --> use uninit checking instead
 - sneaking with qualifiedLookup() is really broken!