summary refs log tree commit diff stats
path: root/compiler/vm.nim
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/vm.nim')
-rw-r--r--compiler/vm.nim1052
1 files changed, 593 insertions, 459 deletions
diff --git a/compiler/vm.nim b/compiler/vm.nim
index 10ac7aaaf..0d5386502 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -1,14 +1,16 @@
 #
 #
 #           The Nimrod Compiler
-#        (c) Copyright 2013 Andreas Rumpf
+#        (c) Copyright 2014 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
 #
 
 ## This file implements the new evaluation engine for Nimrod code.
-## An instruction is 1-2 int32s in memory, it is a register based VM.
+## An instruction is 1-3 int32s in memory, it is a register based VM.
+
+const debugEchoCode = false
 
 import ast except getstr
 
@@ -23,10 +25,22 @@ when hasFFI:
   import evalffi
 
 type
+  TRegisterKind = enum
+    rkNone, rkNode, rkInt, rkFloat, rkRegisterAddr, rkNodeAddr
+  TFullReg = object   # with a custom mark proc, we could use the same
+                      # data representation as LuaJit (tagged NaNs).
+    case kind: TRegisterKind
+    of rkNone: nil
+    of rkInt: intVal: BiggestInt
+    of rkFloat: floatVal: BiggestFloat
+    of rkNode: node: PNode
+    of rkRegisterAddr: regAddr: ptr TFullReg
+    of rkNodeAddr: nodeAddr: ptr PNode
+
   PStackFrame* = ref TStackFrame
   TStackFrame* = object
     prc: PSym                 # current prc; proc that is evaluated
-    slots: TNodeSeq           # parameters passed to the proc + locals;
+    slots: seq[TFullReg]      # parameters passed to the proc + locals;
                               # parameters come first
     next: PStackFrame         # for stacking
     comesFrom: int
@@ -54,7 +68,9 @@ proc stackTrace(c: PCtx, tos: PStackFrame, pc: int,
                 msg: TMsgKind, arg = "") =
   msgWriteln("stack trace: (most recent call last)")
   stackTraceAux(c, tos, pc)
-  localError(c.debug[pc], msg, arg)
+  # XXX test if we want 'globalError' for every mode
+  if c.mode == emRepl: globalError(c.debug[pc], msg, arg)
+  else: localError(c.debug[pc], msg, arg)
 
 proc bailOut(c: PCtx; tos: PStackFrame) =
   stackTrace(c, tos, c.exceptionInstr, errUnhandledExceptionX,
@@ -63,24 +79,9 @@ proc bailOut(c: PCtx; tos: PStackFrame) =
 when not defined(nimComputedGoto):
   {.pragma: computedGoto.}
 
-proc myreset(n: PNode) =
+proc myreset(n: var TFullReg) =
   when defined(system.reset): 
-    var oldInfo = n.info
-    reset(n[])
-    n.info = oldInfo
-
-proc skipMeta(n: PNode): PNode = (if n.kind != nkMetaNode: n else: n.sons[0])
-
-proc setMeta(n, child: PNode) =
-  assert n.kind == nkMetaNode
-  let child = child.skipMeta
-  if n.sons.isNil: n.sons = @[child]
-  else: n.sons[0] = child
-
-proc uast(n: PNode): PNode {.inline.} =
-  # "underlying ast"
-  assert n.kind == nkMetaNode
-  n.sons[0]
+    reset(n)
 
 template ensureKind(k: expr) {.immediate, dirty.} =
   if regs[ra].kind != k:
@@ -112,23 +113,32 @@ template decodeBx(k: expr) {.immediate, dirty.} =
 template move(a, b: expr) {.immediate, dirty.} = system.shallowCopy(a, b)
 # XXX fix minor 'shallowCopy' overloading bug in compiler
 
-proc moveConst(x, y: PNode) =
+proc createStrKeepNode(x: var TFullReg) =
+  if x.node.isNil:
+    x.node = newNode(nkStrLit)
+  elif x.node.kind == nkNilLit:
+    system.reset(x.node[])
+    x.node.kind = nkStrLit
+  elif x.node.kind notin {nkStrLit..nkTripleStrLit}:
+    # XXX this is hacky; tests/txmlgen triggers it:
+    x.node = newNode(nkStrLit)
+    #  debug x.node
+    #assert x.node.kind in {nkStrLit..nkTripleStrLit}
+
+template createStr(x) =
+  x.node = newNode(nkStrLit)
+
+proc moveConst(x: var TFullReg, y: TFullReg) =
   if x.kind != y.kind:
     myreset(x)
     x.kind = y.kind
-  x.typ = y.typ
   case x.kind
-  of nkCharLit..nkInt64Lit: x.intVal = y.intVal
-  of nkFloatLit..nkFloat64Lit: x.floatVal = y.floatVal
-  of nkStrLit..nkTripleStrLit: move(x.strVal, y.strVal)
-  of nkIdent: x.ident = y.ident
-  of nkSym: x.sym = y.sym
-  of nkMetaNode:
-    if x.sons.isNil: x.sons = @[y.sons[0]]
-    else: x.sons[0] = y.sons[0]
-  else:
-    if x.kind notin {nkEmpty..nkNilLit}:
-      move(x.sons, y.sons)
+  of rkNone: discard
+  of rkInt: x.intVal = y.intVal
+  of rkFloat: x.floatVal = y.floatVal
+  of rkNode: x.node = y.node
+  of rkRegisterAddr: x.regAddr = y.regAddr
+  of rkNodeAddr: x.nodeAddr = y.nodeAddr
 
 # this seems to be the best way to model the reference semantics
 # of PNimrodNode:
@@ -155,29 +165,56 @@ proc copyValue(src: PNode): PNode =
     for i in countup(0, sonsLen(src) - 1):
       result.sons[i] = copyValue(src.sons[i])
 
-proc asgnComplex(x, y: PNode) =
+proc asgnComplex(x: var TFullReg, y: TFullReg) =
   if x.kind != y.kind:
     myreset(x)
     x.kind = y.kind
-  x.typ = y.typ
   case x.kind
-  of nkCharLit..nkInt64Lit: x.intVal = y.intVal
-  of nkFloatLit..nkFloat64Lit: x.floatVal = y.floatVal
-  of nkStrLit..nkTripleStrLit: x.strVal = y.strVal
-  of nkIdent: x.ident = y.ident
-  of nkSym: x.sym = y.sym
-  of nkMetaNode:
-    if x.sons.isNil: x.sons = @[y.sons[0]]
-    else: x.sons[0] = y.sons[0]
+  of rkNone: discard
+  of rkInt: x.intVal = y.intVal
+  of rkFloat: x.floatVal = y.floatVal
+  of rkNode: x.node = copyValue(y.node)
+  of rkRegisterAddr: x.regAddr = y.regAddr
+  of rkNodeAddr: x.nodeAddr = y.nodeAddr
+
+proc putIntoNode(n: var PNode; x: TFullReg) =
+  case x.kind
+  of rkNone: discard
+  of rkInt: n.intVal = x.intVal
+  of rkFloat: n.floatVal = x.floatVal
+  of rkNode:
+    if nfIsRef in x.node.flags: n = x.node
+    else: n[] = x.node[]
+  of rkRegisterAddr: putIntoNode(n, x.regAddr[])
+  of rkNodeAddr: n[] = x.nodeAddr[][]
+
+proc putIntoReg(dest: var TFullReg; n: PNode) =
+  case n.kind
+  of nkStrLit..nkTripleStrLit:
+    dest.kind = rkNode
+    createStr(dest)
+    dest.node.strVal = n.strVal
+  of nkCharLit..nkUInt64Lit:
+    dest.kind = rkInt
+    dest.intVal = n.intVal
+  of nkFloatLit..nkFloat128Lit:
+    dest.kind = rkFloat
+    dest.floatVal = n.floatVal
   else:
-    if x.kind notin {nkEmpty..nkNilLit}:
-      let y = y.copyValue
-      for i in countup(0, sonsLen(y) - 1): 
-        if i < x.len: x.sons[i] = y.sons[i]
-        else: addSon(x, y.sons[i])
+    dest.kind = rkNode
+    dest.node = n
+
+proc regToNode(x: TFullReg): PNode =
+  case x.kind
+  of rkNone: result = newNode(nkEmpty)
+  of rkInt: result = newNode(nkIntLit); result.intVal = x.intVal
+  of rkFloat: result = newNode(nkFloatLit); result.floatVal = x.floatVal
+  of rkNode: result = x.node
+  of rkRegisterAddr: result = regToNode(x.regAddr[])
+  of rkNodeAddr: result = x.nodeAddr[]
 
 template getstr(a: expr): expr =
-  (if a.kind in {nkStrLit..nkTripleStrLit}: a.strVal else: $chr(int(a.intVal)))
+  (if a.kind == rkNode: a.node.strVal else: $chr(int(a.intVal)))
 
 proc pushSafePoint(f: PStackFrame; pc: int) =
   if f.safePoints.isNil: f.safePoints = @[]
@@ -185,7 +222,7 @@ proc pushSafePoint(f: PStackFrame; pc: int) =
 
 proc popSafePoint(f: PStackFrame) = discard f.safePoints.pop()
 
-proc cleanUpOnException(c: PCtx; tos: PStackFrame; regs: TNodeSeq): int =
+proc cleanUpOnException(c: PCtx; tos: PStackFrame; regs: seq[TFullReg]): int =
   let raisedType = c.currentExceptionA.typ.skipTypes(abstractPtrs)
   var f = tos
   while true:
@@ -227,50 +264,65 @@ proc cleanUpOnReturn(c: PCtx; f: PStackFrame): int =
       return pc
   return -1
 
-proc opConv*(dest, src: PNode, typ: PType): bool =
-  if typ.kind == tyString:
-    if dest.kind != nkStrLit:
+proc opConv*(dest: var TFullReg, src: TFullReg, desttyp, srctyp: PType): bool =
+  if desttyp.kind == tyString:
+    if dest.kind != rkNode:
       myreset(dest)
-      dest.kind = nkStrLit
-    case src.typ.skipTypes(abstractRange).kind
-    of tyEnum: 
-      dest.strVal = ordinalValToString(src)
-    of tyInt..tyInt64, tyUInt..tyUInt64:
-      dest.strVal = $src.intVal
+      dest.kind = rkNode
+    dest.node = newNode(nkStrLit)
+    let styp = srctyp.skipTypes(abstractRange)
+    case styp.kind
+    of tyEnum:
+      let n = styp.n
+      let x = src.intVal.int
+      if x <% n.len and (let f = n.sons[x].sym; f.position == x):
+        dest.node.strVal = if f.ast.isNil: f.name.s else: f.ast.strVal
+      else:
+        for i in 0.. <n.len:
+          if n.sons[i].kind != nkSym: internalError("opConv for enum")
+          let f = n.sons[i].sym
+          if f.position == x:
+            dest.node.strVal = if f.ast.isNil: f.name.s else: f.ast.strVal
+            return
+        internalError("opConv for enum")
+    of tyInt..tyInt64:
+      dest.node.strVal = $src.intVal
+    of tyUInt..tyUInt64:
+      dest.node.strVal = $uint64(src.intVal)
     of tyBool:
-      dest.strVal = if src.intVal == 0: "false" else: "true"
+      dest.node.strVal = if src.intVal == 0: "false" else: "true"
     of tyFloat..tyFloat128:
-      dest.strVal = $src.floatVal
+      dest.node.strVal = $src.floatVal
     of tyString, tyCString:
-      dest.strVal = src.strVal
+      dest.node.strVal = src.node.strVal
     of tyChar:
-      dest.strVal = $chr(src.intVal)
+      dest.node.strVal = $chr(src.intVal)
     else:
-      internalError("cannot convert to string " & typ.typeToString)
+      internalError("cannot convert to string " & desttyp.typeToString)
   else:
-    case skipTypes(typ, abstractRange).kind
+    case skipTypes(desttyp, abstractRange).kind
     of tyInt..tyInt64:
-      if dest.kind != nkIntLit:
-        myreset(dest); dest.kind = nkIntLit
-      case skipTypes(src.typ, abstractRange).kind
+      if dest.kind != rkInt:
+        myreset(dest); dest.kind = rkInt
+      case skipTypes(srctyp, abstractRange).kind
       of tyFloat..tyFloat64:
         dest.intVal = system.toInt(src.floatVal)
       else:
         dest.intVal = src.intVal
-      if dest.intVal < firstOrd(typ) or dest.intVal > lastOrd(typ):
+      if dest.intVal < firstOrd(desttyp) or dest.intVal > lastOrd(desttyp):
         return true
     of tyUInt..tyUInt64:
-      if dest.kind != nkIntLit:
-        myreset(dest); dest.kind = nkIntLit
-      case skipTypes(src.typ, abstractRange).kind
+      if dest.kind != rkInt:
+        myreset(dest); dest.kind = rkInt
+      case skipTypes(srctyp, abstractRange).kind
       of tyFloat..tyFloat64:
         dest.intVal = system.toInt(src.floatVal)
       else:
-        dest.intVal = src.intVal and ((1 shl typ.size)-1)
+        dest.intVal = src.intVal and ((1 shl (desttyp.size*8))-1)
     of tyFloat..tyFloat64:
-      if dest.kind != nkFloatLit:
-        myreset(dest); dest.kind = nkFloatLit
-      case skipTypes(src.typ, abstractRange).kind
+      if dest.kind != rkFloat:
+        myreset(dest); dest.kind = rkFloat
+      case skipTypes(srctyp, abstractRange).kind
       of tyInt..tyInt64, tyUInt..tyUInt64, tyEnum, tyBool, tyChar: 
         dest.floatVal = toFloat(src.intVal.int)
       else:
@@ -280,25 +332,32 @@ proc opConv*(dest, src: PNode, typ: PType): bool =
 
 proc compile(c: PCtx, s: PSym): int = 
   result = vmgen.genProc(c, s)
+  when debugEchoCode: c.echoCode result
   #c.echoCode
 
-proc regsContents(regs: TNodeSeq) =
-  for i in 0.. <regs.len:
-    echo "Register ", i
-    #debug regs[i]
+template handleJmpBack() {.dirty.} =
+  if c.loopIterations <= 0:
+    if allowInfiniteLoops in c.features:
+      c.loopIterations = MaxLoopIterations
+    else:
+      msgWriteln("stack trace: (most recent call last)")
+      stackTraceAux(c, tos, pc)
+      globalError(c.debug[pc], errTooManyIterations)
+  dec(c.loopIterations)
 
-proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
+proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
   var pc = start
   var tos = tos
-  var regs: TNodeSeq # alias to tos.slots for performance
+  var regs: seq[TFullReg] # alias to tos.slots for performance
   move(regs, tos.slots)
   #echo "NEW RUN ------------------------"
   while true:
     #{.computedGoto.}
     let instr = c.code[pc]
     let ra = instr.regA
-    #echo "PC ", pc, " ", c.code[pc].opcode, " ra ", ra
-    #message(c.debug[pc], warnUser, "gah")
+    #if c.traceActive:
+    #  echo "PC ", pc, " ", c.code[pc].opcode, " ra ", ra
+    #  message(c.debug[pc], warnUser, "Trace")
     case instr.opcode
     of opcEof: return regs[ra]
     of opcRet:
@@ -318,325 +377,348 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
     of opcYldYoid: assert false
     of opcYldVal: assert false
     of opcAsgnInt:
-      decodeB(nkIntLit)
+      decodeB(rkInt)
       regs[ra].intVal = regs[rb].intVal
     of opcAsgnStr:
-      if regs[instr.regB].kind == nkNilLit:
-        decodeB(nkNilLit)
-      else:
-        decodeB(nkStrLit)
-        regs[ra].strVal = regs[rb].strVal
+      decodeB(rkNode)
+      createStrKeepNode regs[ra]
+      regs[ra].node.strVal = regs[rb].node.strVal
     of opcAsgnFloat:
-      decodeB(nkFloatLit)
+      decodeB(rkFloat)
       regs[ra].floatVal = regs[rb].floatVal
     of opcAsgnComplex:
       asgnComplex(regs[ra], regs[instr.regB])
     of opcAsgnRef:
       asgnRef(regs[ra], regs[instr.regB])
-    of opcWrGlobalRef:
-      asgnRef(c.globals.sons[instr.regBx-wordExcess-1], regs[ra])
-    of opcWrGlobal:
-      asgnComplex(c.globals.sons[instr.regBx-wordExcess-1], regs[ra])
-    of opcLdArr, opcLdArrRef:
-      # a = b[c]
+    of opcRegToNode:
+      decodeB(rkNode)
+      putIntoNode(regs[ra].node, regs[rb])
+    of opcNodeToReg:
+      let ra = instr.regA
       let rb = instr.regB
-      let rc = instr.regC
+      # opcDeref might already have loaded it into a register. XXX Let's hope
+      # this is still correct this way:
+      if regs[rb].kind != rkNode:
+        regs[ra] = regs[rb]
+      else:
+        assert regs[rb].kind == rkNode
+        let nb = regs[rb].node
+        case nb.kind
+        of nkCharLit..nkInt64Lit:
+          ensureKind(rkInt)
+          regs[ra].intVal = nb.intVal
+        of nkFloatLit..nkFloat64Lit:
+          ensureKind(rkFloat)
+          regs[ra].floatVal = nb.floatVal
+        else:
+          ensureKind(rkNode)
+          regs[ra].node = nb
+    of opcLdArr:
+      # a = b[c]
+      decodeBC(rkNode)
       if regs[rc].intVal > high(int):
         stackTrace(c, tos, pc, errIndexOutOfBounds)
       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
-      let src = regs[rb]
+      let src = regs[rb].node
       if src.kind notin {nkEmpty..nkNilLit} and idx <% src.len:
-        if instr.opcode == opcLdArrRef and false:
-          # XXX activate when seqs are fixed
-          asgnRef(regs[ra], src.sons[idx])
-        else:
-          asgnComplex(regs[ra], src.sons[idx])
+        regs[ra].node = src.sons[idx]
       else:
         stackTrace(c, tos, pc, errIndexOutOfBounds)
     of opcLdStrIdx:
-      decodeBC(nkIntLit)
+      decodeBC(rkInt)
       let idx = regs[rc].intVal.int
-      if idx <=% regs[rb].strVal.len:
-        regs[ra].intVal = regs[rb].strVal[idx].ord
+      if idx <=% regs[rb].node.strVal.len:
+        regs[ra].intVal = regs[rb].node.strVal[idx].ord
       else:
         stackTrace(c, tos, pc, errIndexOutOfBounds)
     of opcWrArr:
       # a[b] = c
-      let rb = instr.regB
-      let rc = instr.regC
+      decodeBC(rkNode)
       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.int
-      if idx <% regs[ra].len:
-        asgnRef(regs[ra].sons[idx], regs[rc])
+      if idx <% regs[ra].node.len:
+        putIntoNode(regs[ra].node.sons[idx], regs[rc])
       else:
         stackTrace(c, tos, pc, errIndexOutOfBounds)
     of opcLdObj:
       # a = b.c
-      let rb = instr.regB
-      let rc = instr.regC
-      #Message(c.debug[pc], warnUser, $regs[rb].safeLen & " " & $rc)
-      asgnComplex(regs[ra], regs[rb].sons[rc])
-    of opcLdObjRef:
-      # a = b.c
-      let rb = instr.regB
-      let rc = instr.regC
-      # XXX activate when seqs are fixed
-      asgnComplex(regs[ra], regs[rb].sons[rc])
-      #asgnRef(regs[ra], regs[rb].sons[rc])
+      decodeBC(rkNode)
+      let src = regs[rb].node
+      if src.kind notin {nkEmpty..nkNilLit}:
+        let n = src.sons[rc]
+        regs[ra].node = n
+      else:
+        stackTrace(c, tos, pc, errNilAccess)
     of opcWrObj:
       # a.b = c
-      let rb = instr.regB
-      let rc = instr.regC
-      #if regs[ra].isNil or regs[ra].sons.isNil or rb >= len(regs[ra]):
-      #  debug regs[ra]
-      #  debug regs[rc]
-      #  echo "RB ", rb
-      #  internalError(c.debug[pc], "argl")
-      asgnComplex(regs[ra].sons[rb], regs[rc])
-    of opcWrObjRef:
-      let rb = instr.regB
-      let rc = instr.regC
-      asgnRef(regs[ra].sons[rb], regs[rc])
+      decodeBC(rkNode)
+      putIntoNode(regs[ra].node.sons[rb], regs[rc])
     of opcWrStrIdx:
-      decodeBC(nkStrLit)
+      decodeBC(rkNode)
       let idx = regs[rb].intVal.int
-      if idx <% regs[ra].strVal.len:
-        regs[ra].strVal[idx] = chr(regs[rc].intVal)
+      if idx <% regs[ra].node.strVal.len:
+        regs[ra].node.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]
-      else: regs[ra].sons[0] = regs[rb]
-    of opcDeref:
+    of opcAddrReg:
+      decodeB(rkRegisterAddr)
+      regs[ra].regAddr = addr(regs[rb])
+    of opcAddrNode:
+      decodeB(rkNodeAddr)
+      regs[ra].nodeAddr = addr(regs[rb].node)
+    of opcLdDeref:
       # a = b[]
+      let ra = instr.regA
       let rb = instr.regB
-      if regs[rb].kind == nkNilLit:
+      case regs[rb].kind
+      of rkNodeAddr:
+        ensureKind(rkNode)
+        regs[ra].node = regs[rb].nodeAddr[]
+      of rkRegisterAddr:
+        ensureKind(regs[rb].regAddr.kind)
+        regs[ra] = regs[rb].regAddr[]
+      of rkNode:
+        if regs[rb].node.kind == nkNilLit:
+          stackTrace(c, tos, pc, errNilAccess)
+        assert regs[rb].node.kind == nkRefTy
+        regs[ra].node = regs[rb].node.sons[0]
+      else:
         stackTrace(c, tos, pc, errNilAccess)
-      assert regs[rb].kind == nkRefTy
-      # XXX this is not correct
-      regs[ra] = regs[rb].sons[0]
+    of opcWrDeref:
+      # a[] = b
+      let ra = instr.regA
+      let rb = instr.regB
+      case regs[ra].kind
+      of rkNodeAddr: putIntoNode(regs[ra].nodeAddr[], regs[rb])
+      of rkRegisterAddr: regs[ra].regAddr[] = regs[rb]
+      of rkNode: putIntoNode(regs[ra].node, regs[rb])
+      else: stackTrace(c, tos, pc, errNilAccess)
     of opcAddInt:
-      decodeBC(nkIntLit)
+      decodeBC(rkInt)
       regs[ra].intVal = regs[rb].intVal + regs[rc].intVal
     of opcAddImmInt:
-      decodeBImm(nkIntLit)
+      decodeBImm(rkInt)
+      #message(c.debug[pc], warnUser, "came here")
+      #debug regs[rb].node
       regs[ra].intVal = regs[rb].intVal + imm
     of opcSubInt:
-      decodeBC(nkIntLit)
+      decodeBC(rkInt)
       regs[ra].intVal = regs[rb].intVal - regs[rc].intVal
     of opcSubImmInt:
-      decodeBImm(nkIntLit)
+      decodeBImm(rkInt)
       regs[ra].intVal = regs[rb].intVal - imm
     of opcLenSeq:
-      decodeBImm(nkIntLit)
+      decodeBImm(rkInt)
       #assert regs[rb].kind == nkBracket
       # also used by mNLen:
-      regs[ra].intVal = regs[rb].skipMeta.len - imm
+      regs[ra].intVal = regs[rb].node.safeLen - imm
     of opcLenStr:
-      decodeBImm(nkIntLit)
-      if regs[rb].kind == nkNilLit:
-        stackTrace(c, tos, pc, errNilAccess)
-      else:
-        assert regs[rb].kind in {nkStrLit..nkTripleStrLit}
-        regs[ra].intVal = regs[rb].strVal.len - imm
+      decodeBImm(rkInt)
+      assert regs[rb].kind == rkNode
+      regs[ra].intVal = regs[rb].node.strVal.len - imm
     of opcIncl:
-      decodeB(nkCurly)
-      if not inSet(regs[ra], regs[rb]): addSon(regs[ra], copyTree(regs[rb]))
+      decodeB(rkNode)
+      let b = regs[rb].regToNode
+      if not inSet(regs[ra].node, b):
+        addSon(regs[ra].node, copyTree(b))
     of opcInclRange:
-      decodeBC(nkCurly)
+      decodeBC(rkNode)
       var r = newNode(nkRange)
-      r.add regs[rb]
-      r.add regs[rc]
-      addSon(regs[ra], r.copyTree)
+      r.add regs[rb].regToNode
+      r.add regs[rc].regToNode
+      addSon(regs[ra].node, r.copyTree)
     of opcExcl:
-      decodeB(nkCurly)
-      var b = newNodeIT(nkCurly, regs[rb].info, regs[rb].typ)
-      addSon(b, regs[rb])
-      var r = diffSets(regs[ra], b)
-      discardSons(regs[ra])
-      for i in countup(0, sonsLen(r) - 1): addSon(regs[ra], r.sons[i])
+      decodeB(rkNode)
+      var b = newNodeIT(nkCurly, regs[rb].node.info, regs[rb].node.typ)
+      addSon(b, regs[rb].regToNode)
+      var r = diffSets(regs[ra].node, b)
+      discardSons(regs[ra].node)
+      for i in countup(0, sonsLen(r) - 1): addSon(regs[ra].node, r.sons[i])
     of opcCard:
-      decodeB(nkIntLit)
-      regs[ra].intVal = nimsets.cardSet(regs[rb])
+      decodeB(rkInt)
+      regs[ra].intVal = nimsets.cardSet(regs[rb].node)
     of opcMulInt:
-      decodeBC(nkIntLit)
+      decodeBC(rkInt)
       regs[ra].intVal = regs[rb].intVal * regs[rc].intVal
     of opcDivInt:
-      decodeBC(nkIntLit)
-      regs[ra].intVal = regs[rb].intVal div regs[rc].intVal
+      decodeBC(rkInt)
+      if regs[rc].intVal == 0: stackTrace(c, tos, pc, errConstantDivisionByZero)
+      else: regs[ra].intVal = regs[rb].intVal div regs[rc].intVal
     of opcModInt:
-      decodeBC(nkIntLit)
-      regs[ra].intVal = regs[rb].intVal mod regs[rc].intVal
+      decodeBC(rkInt)
+      if regs[rc].intVal == 0: stackTrace(c, tos, pc, errConstantDivisionByZero)
+      else: regs[ra].intVal = regs[rb].intVal mod regs[rc].intVal
     of opcAddFloat:
-      decodeBC(nkFloatLit)
+      decodeBC(rkFloat)
       regs[ra].floatVal = regs[rb].floatVal + regs[rc].floatVal
     of opcSubFloat:
-      decodeBC(nkFloatLit)
+      decodeBC(rkFloat)
       regs[ra].floatVal = regs[rb].floatVal - regs[rc].floatVal
     of opcMulFloat:
-      decodeBC(nkFloatLit)
+      decodeBC(rkFloat)
       regs[ra].floatVal = regs[rb].floatVal * regs[rc].floatVal
     of opcDivFloat:
-      decodeBC(nkFloatLit)
+      decodeBC(rkFloat)
       regs[ra].floatVal = regs[rb].floatVal / regs[rc].floatVal
     of opcShrInt:
-      decodeBC(nkIntLit)
+      decodeBC(rkInt)
       regs[ra].intVal = regs[rb].intVal shr regs[rc].intVal
     of opcShlInt:
-      decodeBC(nkIntLit)
+      decodeBC(rkInt)
       regs[ra].intVal = regs[rb].intVal shl regs[rc].intVal
     of opcBitandInt:
-      decodeBC(nkIntLit)
+      decodeBC(rkInt)
       regs[ra].intVal = regs[rb].intVal and regs[rc].intVal
     of opcBitorInt:
-      decodeBC(nkIntLit)
+      decodeBC(rkInt)
       regs[ra].intVal = regs[rb].intVal or regs[rc].intVal
     of opcBitxorInt:
-      decodeBC(nkIntLit)
+      decodeBC(rkInt)
       regs[ra].intVal = regs[rb].intVal xor regs[rc].intVal
     of opcAddu:
-      decodeBC(nkIntLit)
+      decodeBC(rkInt)
       regs[ra].intVal = regs[rb].intVal +% regs[rc].intVal
     of opcSubu:
-      decodeBC(nkIntLit)
+      decodeBC(rkInt)
       regs[ra].intVal = regs[rb].intVal -% regs[rc].intVal
     of opcMulu: 
-      decodeBC(nkIntLit)
+      decodeBC(rkInt)
       regs[ra].intVal = regs[rb].intVal *% regs[rc].intVal
     of opcDivu:
-      decodeBC(nkIntLit)
+      decodeBC(rkInt)
       regs[ra].intVal = regs[rb].intVal /% regs[rc].intVal
     of opcModu:
-      decodeBC(nkIntLit)
+      decodeBC(rkInt)
       regs[ra].intVal = regs[rb].intVal %% regs[rc].intVal
     of opcEqInt:
-      decodeBC(nkIntLit)
+      decodeBC(rkInt)
       regs[ra].intVal = ord(regs[rb].intVal == regs[rc].intVal)
     of opcLeInt:
-      decodeBC(nkIntLit)
+      decodeBC(rkInt)
       regs[ra].intVal = ord(regs[rb].intVal <= regs[rc].intVal)
     of opcLtInt:
-      decodeBC(nkIntLit)
+      decodeBC(rkInt)
       regs[ra].intVal = ord(regs[rb].intVal < regs[rc].intVal)
     of opcEqFloat:
-      decodeBC(nkIntLit)
+      decodeBC(rkInt)
       regs[ra].intVal = ord(regs[rb].floatVal == regs[rc].floatVal)
     of opcLeFloat:
-      decodeBC(nkIntLit)
+      decodeBC(rkInt)
       regs[ra].intVal = ord(regs[rb].floatVal <= regs[rc].floatVal)
     of opcLtFloat:
-      decodeBC(nkIntLit)
+      decodeBC(rkInt)
       regs[ra].intVal = ord(regs[rb].floatVal < regs[rc].floatVal)
     of opcLeu:
-      decodeBC(nkIntLit)
+      decodeBC(rkInt)
       regs[ra].intVal = ord(regs[rb].intVal <=% regs[rc].intVal)
     of opcLtu:
-      decodeBC(nkIntLit)
+      decodeBC(rkInt)
       regs[ra].intVal = ord(regs[rb].intVal <% regs[rc].intVal)
     of opcEqRef:
-      decodeBC(nkIntLit)
-      regs[ra].intVal = ord((regs[rb].kind == nkNilLit and
-                             regs[rc].kind == nkNilLit) or
-                             regs[rb].sons == regs[rc].sons)
+      decodeBC(rkInt)
+      regs[ra].intVal = ord((regs[rb].node.kind == nkNilLit and
+                             regs[rc].node.kind == nkNilLit) or
+                             regs[rb].node == regs[rc].node)
     of opcEqNimrodNode:
-      decodeBC(nkIntLit)
-      regs[ra].intVal = ord(regs[rb].skipMeta == regs[rc].skipMeta)
+      decodeBC(rkInt)
+      regs[ra].intVal = ord(regs[rb].node == regs[rc].node)
     of opcXor:
-      decodeBC(nkIntLit)
+      decodeBC(rkInt)
       regs[ra].intVal = ord(regs[rb].intVal != regs[rc].intVal)
     of opcNot:
-      decodeB(nkIntLit)
-      assert regs[rb].kind == nkIntLit
+      decodeB(rkInt)
+      assert regs[rb].kind == rkInt
       regs[ra].intVal = 1 - regs[rb].intVal
     of opcUnaryMinusInt:
-      decodeB(nkIntLit)
-      assert regs[rb].kind == nkIntLit
+      decodeB(rkInt)
+      assert regs[rb].kind == rkInt
       regs[ra].intVal = -regs[rb].intVal
     of opcUnaryMinusFloat:
-      decodeB(nkFloatLit)
-      assert regs[rb].kind == nkFloatLit
+      decodeB(rkFloat)
+      assert regs[rb].kind == rkFloat
       regs[ra].floatVal = -regs[rb].floatVal
     of opcBitnotInt:
-      decodeB(nkIntLit)
-      assert regs[rb].kind == nkIntLit
+      decodeB(rkInt)
+      assert regs[rb].kind == rkInt
       regs[ra].intVal = not regs[rb].intVal
     of opcEqStr:
-      decodeBC(nkIntLit)
-      regs[ra].intVal = ord(regs[rb].strVal == regs[rc].strVal)
+      decodeBC(rkInt)
+      regs[ra].intVal = ord(regs[rb].node.strVal == regs[rc].node.strVal)
     of opcLeStr:
-      decodeBC(nkIntLit)
-      regs[ra].intVal = ord(regs[rb].strVal <= regs[rc].strVal)
+      decodeBC(rkInt)
+      regs[ra].intVal = ord(regs[rb].node.strVal <= regs[rc].node.strVal)
     of opcLtStr:
-      decodeBC(nkIntLit)
-      regs[ra].intVal = ord(regs[rb].strVal < regs[rc].strVal)
+      decodeBC(rkInt)
+      regs[ra].intVal = ord(regs[rb].node.strVal < regs[rc].node.strVal)
     of opcLeSet:
-      decodeBC(nkIntLit)
-      regs[ra].intVal = ord(containsSets(regs[rb], regs[rc]))
+      decodeBC(rkInt)
+      regs[ra].intVal = ord(containsSets(regs[rb].node, regs[rc].node))
     of opcEqSet: 
-      decodeBC(nkIntLit)
-      regs[ra].intVal = ord(equalSets(regs[rb], regs[rc]))
+      decodeBC(rkInt)
+      regs[ra].intVal = ord(equalSets(regs[rb].node, regs[rc].node))
     of opcLtSet:
-      decodeBC(nkIntLit)
-      let a = regs[rb]
-      let b = regs[rc]
+      decodeBC(rkInt)
+      let a = regs[rb].node
+      let b = regs[rc].node
       regs[ra].intVal = ord(containsSets(a, b) and not equalSets(a, b))
     of opcMulSet:
-      decodeBC(nkCurly)
-      move(regs[ra].sons, nimsets.intersectSets(regs[rb], regs[rc]).sons)
+      decodeBC(rkNode)
+      move(regs[ra].node.sons, 
+            nimsets.intersectSets(regs[rb].node, regs[rc].node).sons)
     of opcPlusSet: 
-      decodeBC(nkCurly)
-      move(regs[ra].sons, nimsets.unionSets(regs[rb], regs[rc]).sons)
+      decodeBC(rkNode)
+      move(regs[ra].node.sons,
+           nimsets.unionSets(regs[rb].node, regs[rc].node).sons)
     of opcMinusSet:
-      decodeBC(nkCurly)
-      move(regs[ra].sons, nimsets.diffSets(regs[rb], regs[rc]).sons)
+      decodeBC(rkNode)
+      move(regs[ra].node.sons,
+           nimsets.diffSets(regs[rb].node, regs[rc].node).sons)
     of opcSymdiffSet:
-      decodeBC(nkCurly)
-      move(regs[ra].sons, nimsets.symdiffSets(regs[rb], regs[rc]).sons)    
+      decodeBC(rkNode)
+      move(regs[ra].node.sons,
+           nimsets.symdiffSets(regs[rb].node, regs[rc].node).sons)    
     of opcConcatStr:
-      decodeBC(nkStrLit)
-      regs[ra].strVal = getstr(regs[rb])
+      decodeBC(rkNode)
+      createStr regs[ra]
+      regs[ra].node.strVal = getstr(regs[rb])
       for i in rb+1..rb+rc-1:
-        regs[ra].strVal.add getstr(regs[i])
+        regs[ra].node.strVal.add getstr(regs[i])
     of opcAddStrCh:
-      decodeB(nkStrLit)
-      regs[ra].strVal.add(regs[rb].intVal.chr)
+      decodeB(rkNode)
+      createStrKeepNode regs[ra]
+      regs[ra].node.strVal.add(regs[rb].intVal.chr)
     of opcAddStrStr:
-      decodeB(nkStrLit)
-      regs[ra].strVal.add(regs[rb].strVal)
+      decodeB(rkNode)
+      createStrKeepNode regs[ra]
+      regs[ra].node.strVal.add(regs[rb].node.strVal)
     of opcAddSeqElem:
-      decodeB(nkBracket)
-      regs[ra].add(copyTree(regs[rb]))
+      decodeB(rkNode)
+      if regs[ra].node.kind == nkBracket:
+        regs[ra].node.add(copyTree(regs[rb].regToNode))
+      else:
+        stackTrace(c, tos, pc, errNilAccess)
     of opcEcho:
       let rb = instr.regB
       for i in ra..ra+rb-1:
-        #if regs[i].kind != nkStrLit: debug regs[i]
-        write(stdout, regs[i].strVal)
+        #if regs[i].kind != rkNode: debug regs[i]
+        write(stdout, regs[i].node.strVal)
       writeln(stdout, "")
     of opcContainsSet:
-      decodeBC(nkIntLit)
-      regs[ra].intVal = ord(inSet(regs[rb], regs[rc]))
+      decodeBC(rkInt)
+      regs[ra].intVal = ord(inSet(regs[rb].node, regs[rc].regToNode))
     of opcSubStr:
-      decodeBC(nkStrLit)
+      decodeBC(rkNode)
       inc pc
       assert c.code[pc].opcode == opcSubStr
       let rd = c.code[pc].regA
-      regs[ra].strVal = substr(regs[rb].strVal, regs[rc].intVal.int, 
-                               regs[rd].intVal.int)
+      createStr regs[ra]
+      regs[ra].node.strVal = substr(regs[rb].node.strVal, 
+                                    regs[rc].intVal.int, regs[rd].intVal.int)
     of opcRangeChck:
       let rb = instr.regB
       let rc = instr.regC
-      if not (leValueConv(regs[rb], regs[ra]) and
-              leValueConv(regs[ra], regs[rc])):
+      if not (leValueConv(regs[rb].regToNode, regs[ra].regToNode) and
+              leValueConv(regs[ra].regToNode, regs[rc].regToNode)):
         stackTrace(c, tos, pc, errGenerated,
           msgKindToString(errIllegalConvFromXtoY) % [
           "unknown type" , "unknown type"])
@@ -644,8 +726,9 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
       # dest = call regStart, n; where regStart = fn, arg1, ...
       let rb = instr.regB
       let rc = instr.regC
-      let isClosure = regs[rb].kind == nkPar
-      let prc = if not isClosure: regs[rb].sym else: regs[rb].sons[0].sym
+      let bb = regs[rb].node
+      let isClosure = bb.kind == nkPar
+      let prc = if not isClosure: bb.sym else: bb.sons[0].sym
       if sfImportc in prc.flags:
         if allowFFI notin c.features:
           globalError(c.debug[pc], errGenerated, "VM not allowed to do FFI")
@@ -659,24 +742,27 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
                                              rb+1, rc-1, c.debug[pc])
           if newValue.kind != nkEmpty:
             assert instr.opcode == opcIndCallAsgn
-            asgnRef(regs[ra], newValue)
+            putIntoReg(regs[ra], newValue)
         else:
           globalError(c.debug[pc], errGenerated, "VM not built with FFI support")
       elif prc.kind != skTemplate:
         let newPc = compile(c, prc)
+        # tricky: a recursion is also a jump back, so we use the same
+        # logic as for loops:
+        if newPc < pc: handleJmpBack()
         #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]) or prc.kind == skMacro:
-          newFrame.slots[0] = getNullValue(prc.typ.sons[0], prc.info)
-        # pass every parameter by var (the language definition allows this):
+          putIntoReg(newFrame.slots[0], getNullValue(prc.typ.sons[0], prc.info))
         for i in 1 .. rc-1:
           newFrame.slots[i] = regs[rb+i]
         if isClosure:
-          newFrame.slots[rc] = regs[rb].sons[1]
+          newFrame.slots[rc].kind = rkNode
+          newFrame.slots[rc].node = regs[rb].node.sons[1]
         # allocate the temporaries:
-        for i in rc+ord(isClosure) .. <prc.offset:
-          newFrame.slots[i] = newNode(nkEmpty)
+        #for i in rc+ord(isClosure) .. <prc.offset:
+        #  newFrame.slots[i] = newNode(nkEmpty)
         tos = newFrame
         move(regs, newFrame.slots)
         # -1 for the following 'inc pc'
@@ -689,10 +775,10 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
                             c.module
         var macroCall = newNodeI(nkCall, c.debug[pc])
         macroCall.add(newSymNode(prc))
-        for i in 1 .. rc-1: macroCall.add(regs[rb+i].skipMeta)
+        for i in 1 .. rc-1: macroCall.add(regs[rb+i].regToNode)
         let a = evalTemplate(macroCall, prc, genSymOwner)
-        ensureKind(nkMetaNode)
-        setMeta(regs[ra], a)
+        ensureKind(rkNode)
+        regs[ra].node = a
     of opcTJmp:
       # jump Bx if A != 0
       let rbx = instr.regBx - wordExcess - 1 # -1 for the following 'inc pc'
@@ -707,12 +793,16 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
       # jump Bx
       let rbx = instr.regBx - wordExcess - 1 # -1 for the following 'inc pc'
       inc pc, rbx
+    of opcJmpBack:
+      let rbx = instr.regBx - wordExcess - 1 # -1 for the following 'inc pc'
+      inc pc, rbx
+      handleJmpBack()
     of opcBranch:
       # we know the next instruction is a 'fjmp':
       let branch = c.constants[instr.regBx-wordExcess]
       var cond = false
       for j in countup(0, sonsLen(branch) - 2): 
-        if overlap(regs[ra], branch.sons[j]): 
+        if overlap(regs[ra].regToNode, branch.sons[j]): 
           cond = true
           break
       assert c.code[pc+1].opcode == opcFJmp
@@ -741,7 +831,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
           bailOut(c, tos)
           return
     of opcRaise:
-      let raised = regs[ra]
+      let raised = regs[ra].node
       c.currentExceptionA = raised
       c.exceptionInstr = pc
       # -1 because of the following 'inc'
@@ -750,332 +840,377 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
         bailOut(c, tos)
         return
     of opcNew:
+      ensureKind(rkNode)
       let typ = c.types[instr.regBx - wordExcess]
-      regs[ra] = getNullValue(typ, regs[ra].info)
-      regs[ra].flags.incl nfIsRef
+      regs[ra].node = getNullValue(typ, c.debug[pc])
+      regs[ra].node.flags.incl nfIsRef
     of opcNewSeq:
       let typ = c.types[instr.regBx - wordExcess]
       inc pc
-      ensureKind(nkBracket)
+      ensureKind(rkNode)
       let instr2 = c.code[pc]
       let count = regs[instr2.regA].intVal.int
-      regs[ra].typ = typ
-      newSeq(regs[ra].sons, count)
+      regs[ra].node = newNodeI(nkBracket, c.debug[pc])
+      regs[ra].node.typ = typ
+      newSeq(regs[ra].node.sons, count)
       for i in 0 .. <count:
-        regs[ra].sons[i] = getNullValue(typ.sons[0], regs[ra].info)
+        regs[ra].node.sons[i] = getNullValue(typ.sons[0], c.debug[pc])
     of opcNewStr:
-      decodeB(nkStrLit)
-      regs[ra].strVal = newString(regs[rb].intVal.int)
+      decodeB(rkNode)
+      regs[ra].node = newNodeI(nkStrLit, c.debug[pc])
+      regs[ra].node.strVal = newString(regs[rb].intVal.int)
     of opcLdImmInt:
       # dest = immediate value
-      decodeBx(nkIntLit)
+      decodeBx(rkInt)
       regs[ra].intVal = rbx
     of opcLdNull:
+      ensureKind(rkNode)
+      let typ = c.types[instr.regBx - wordExcess]
+      regs[ra].node = getNullValue(typ, c.debug[pc])
+      # opcLdNull really is the gist of the VM's problems: should it load
+      # a fresh null to  regs[ra].node  or to regs[ra].node[]? This really
+      # depends on whether regs[ra] represents the variable itself or wether
+      # it holds the indirection! Due to the way registers are re-used we cannot
+      # say for sure here! --> The codegen has to deal with it
+      # via 'genAsgnPatch'.
+    of opcLdNullReg:
       let typ = c.types[instr.regBx - wordExcess]
-      regs[ra] = getNullValue(typ, c.debug[pc])
+      if typ.skipTypes(abstractInst+{tyRange}-{tyTypeDesc}).kind in {
+          tyFloat..tyFloat128}:
+        ensureKind(rkFloat)
+        regs[ra].floatVal = 0.0
+      else:
+        ensureKind(rkInt)
+        regs[ra].intVal = 0
     of opcLdConst:
       let rb = instr.regBx - wordExcess
-      if regs[ra].isNil:
-        regs[ra] = copyTree(c.constants.sons[rb])
+      let cnst = c.constants.sons[rb]
+      if fitsRegister(cnst.typ):
+        putIntoReg(regs[ra], cnst)
       else:
-        moveConst(regs[ra], c.constants.sons[rb])
+        ensureKind(rkNode)
+        regs[ra].node = cnst
     of opcAsgnConst:
       let rb = instr.regBx - wordExcess
-      if regs[ra].isNil:
-        regs[ra] = copyTree(c.constants.sons[rb])
+      let cnst = c.constants.sons[rb]
+      if fitsRegister(cnst.typ):
+        putIntoReg(regs[ra], cnst)
       else:
-        asgnComplex(regs[ra], c.constants.sons[rb])
+        ensureKind(rkNode)
+        regs[ra].node = cnst.copyTree
     of opcLdGlobal:
       let rb = instr.regBx - wordExcess - 1
-      if regs[ra].isNil:
-        regs[ra] = copyTree(c.globals.sons[rb])
-      else:
-        asgnComplex(regs[ra], c.globals.sons[rb])
+      ensureKind(rkNode)
+      regs[ra].node = c.globals.sons[rb]
+    of opcLdGlobalAddr:
+      let rb = instr.regBx - wordExcess - 1
+      ensureKind(rkNodeAddr)
+      regs[ra].nodeAddr = addr(c.globals.sons[rb])
     of opcRepr:
-      decodeB(nkStrLit)
-      regs[ra].strVal = renderTree(regs[rb].skipMeta, {renderNoComments})
+      decodeB(rkNode)
+      createStr regs[ra]
+      regs[ra].node.strVal = renderTree(regs[rb].node, {renderNoComments})
     of opcQuit:
       if c.mode in {emRepl, emStaticExpr, emStaticStmt}:
         message(c.debug[pc], hintQuitCalled)
-        quit(int(getOrdValue(regs[ra])))
+        quit(int(getOrdValue(regs[ra].regToNode)))
       else:
-        return nil
+        return TFullReg(kind: rkNone)
     of opcSetLenStr:
-      decodeB(nkStrLit)
-      regs[ra].strVal.setLen(regs[rb].getOrdValue.int)
+      decodeB(rkNode)
+      createStrKeepNode regs[ra]
+      regs[ra].node.strVal.setLen(regs[rb].intVal.int)
     of opcOf:
-      decodeBC(nkIntLit)
+      decodeBC(rkInt)
       let typ = c.types[regs[rc].intVal.int]
-      regs[ra].intVal = ord(inheritanceDiff(regs[rb].typ, typ) >= 0)
+      regs[ra].intVal = ord(inheritanceDiff(regs[rb].node.typ, typ) >= 0)
     of opcIs:
-      decodeBC(nkIntLit)
-      let t1 = regs[rb].typ.skipTypes({tyTypeDesc})
+      decodeBC(rkInt)
+      let t1 = regs[rb].node.typ.skipTypes({tyTypeDesc})
       let t2 = c.types[regs[rc].intVal.int]
       # XXX: This should use the standard isOpImpl
       let match = if t2.kind == tyUserTypeClass: true
                   else: sameType(t1, t2)
       regs[ra].intVal = ord(match)
     of opcSetLenSeq:
-      decodeB(nkBracket)
-      let newLen = regs[rb].getOrdValue.int
-      setLen(regs[ra].sons, newLen)
-    of opcSwap, opcReset:
+      decodeB(rkNode)
+      let newLen = regs[rb].intVal.int
+      if regs[ra].node.isNil: stackTrace(c, tos, pc, errNilAccess)
+      else: setLen(regs[ra].node.sons, newLen)
+    of opcSwap:
+      let rb = instr.regB
+      if regs[ra].kind == regs[rb].kind:
+        case regs[ra].kind
+        of rkNone: discard
+        of rkInt: swap regs[ra].intVal, regs[rb].intVal
+        of rkFloat: swap regs[ra].floatVal, regs[rb].floatVal
+        of rkNode: swap regs[ra].node, regs[rb].node
+        of rkRegisterAddr: swap regs[ra].regAddr, regs[rb].regAddr
+        of rkNodeAddr: swap regs[ra].nodeAddr, regs[rb].nodeAddr
+      else:
+        internalError(c.debug[pc], "cannot swap operands")
+    of opcReset:
       internalError(c.debug[pc], "too implement")
+    of opcNarrowS:
+      decodeB(rkInt)
+      let min = -(1 shl (rb-1))
+      let max = (1 shl (rb-1))-1
+      if regs[ra].intVal < min or regs[ra].intVal > max:
+        stackTrace(c, tos, pc, errGenerated,
+          msgKindToString(errUnhandledExceptionX) % "value out of range")
+    of opcNarrowU:
+      decodeB(rkInt)
+      regs[ra].intVal = regs[ra].intVal and ((1'i64 shl rb)-1)
     of opcIsNil:
-      decodeB(nkIntLit)
-      regs[ra].intVal = ord(regs[rb].skipMeta.kind == nkNilLit)
+      decodeB(rkInt)
+      regs[ra].intVal = ord(regs[rb].node.kind == nkNilLit)
     of opcNBindSym:
-      decodeBx(nkMetaNode)
-      setMeta(regs[ra], copyTree(c.constants.sons[rbx]))
+      decodeBx(rkNode)
+      regs[ra].node = copyTree(c.constants.sons[rbx])
     of opcNChild:
-      decodeBC(nkMetaNode)
-      if regs[rb].kind != nkMetaNode:
-        internalError(c.debug[pc], "no MetaNode")
+      decodeBC(rkNode)
       let idx = regs[rc].intVal.int
-      let src = regs[rb].uast
+      let src = regs[rb].node
       if src.kind notin {nkEmpty..nkNilLit} and idx <% src.len:
-        setMeta(regs[ra], src.sons[idx])
+        regs[ra].node = src.sons[idx]
       else:
         stackTrace(c, tos, pc, errIndexOutOfBounds)
     of opcNSetChild:
-      decodeBC(nkMetaNode)
+      decodeBC(rkNode)
       let idx = regs[rb].intVal.int
-      var dest = regs[ra].uast
+      var dest = regs[ra].node
       if dest.kind notin {nkEmpty..nkNilLit} and idx <% dest.len:
-        dest.sons[idx] = regs[rc].uast
+        dest.sons[idx] = regs[rc].node
       else:
         stackTrace(c, tos, pc, errIndexOutOfBounds)
     of opcNAdd:
-      decodeBC(nkMetaNode)
-      var u = regs[rb].uast
-      u.add(regs[rc].uast)
-      setMeta(regs[ra], u)
+      decodeBC(rkNode)
+      var u = regs[rb].node
+      u.add(regs[rc].node)
+      regs[ra].node = u
     of opcNAddMultiple:
-      decodeBC(nkMetaNode)
-      let x = regs[rc]
-      var u = regs[rb].uast
+      decodeBC(rkNode)
+      let x = regs[rc].node
+      var u = regs[rb].node
       # XXX can be optimized:
-      for i in 0.. <x.len: u.add(x.sons[i].skipMeta)
-      setMeta(regs[ra], u)
+      for i in 0.. <x.len: u.add(x.sons[i])
+      regs[ra].node = u
     of opcNKind:
-      decodeB(nkIntLit)
-      regs[ra].intVal = ord(regs[rb].uast.kind)
+      decodeB(rkInt)
+      regs[ra].intVal = ord(regs[rb].node.kind)
     of opcNIntVal:
-      decodeB(nkIntLit)
-      let a = regs[rb].uast
+      decodeB(rkInt)
+      let a = regs[rb].node
       case a.kind
       of nkCharLit..nkInt64Lit: regs[ra].intVal = a.intVal
       else: stackTrace(c, tos, pc, errFieldXNotFound, "intVal")
     of opcNFloatVal:
-      decodeB(nkFloatLit)
-      let a = regs[rb].uast
+      decodeB(rkFloat)
+      let a = regs[rb].node
       case a.kind
       of nkFloatLit..nkFloat64Lit: regs[ra].floatVal = a.floatVal
       else: stackTrace(c, tos, pc, errFieldXNotFound, "floatVal")
     of opcNSymbol:
-      decodeB(nkSym)
-      let a = regs[rb].uast
+      decodeB(rkNode)
+      let a = regs[rb].node
       if a.kind == nkSym:
-        regs[ra].sym = a.sym
+        regs[ra].node = copyNode(a)
       else:
         stackTrace(c, tos, pc, errFieldXNotFound, "symbol")
     of opcNIdent:
-      decodeB(nkIdent)
-      let a = regs[rb].uast
+      decodeB(rkNode)
+      let a = regs[rb].node
       if a.kind == nkIdent:
-        regs[ra].ident = a.ident
+        regs[ra].node = copyNode(a)
       else:
         stackTrace(c, tos, pc, errFieldXNotFound, "ident")
     of opcNGetType:
       internalError(c.debug[pc], "unknown opcode " & $instr.opcode)
     of opcNStrVal:
-      decodeB(nkStrLit)
-      let a = regs[rb].uast
-      case a.kind
-      of nkStrLit..nkTripleStrLit: regs[ra].strVal = a.strVal
+      decodeB(rkNode)
+      createStr regs[ra]
+      let a = regs[rb].node
+      if a.kind in {nkStrLit..nkTripleStrLit}: regs[ra].node.strVal = a.strVal
       else: stackTrace(c, tos, pc, errFieldXNotFound, "strVal")
     of opcSlurp:
-      decodeB(nkStrLit)
-      regs[ra].strVal = opSlurp(regs[rb].strVal, c.debug[pc], c.module)
+      decodeB(rkNode)
+      createStr regs[ra]
+      regs[ra].node.strVal = opSlurp(regs[rb].node.strVal, c.debug[pc],
+                                     c.module)
     of opcGorge:
-      decodeBC(nkStrLit)
-      regs[ra].strVal = opGorge(regs[rb].strVal, regs[rc].strVal)
+      decodeBC(rkNode)
+      regs[ra].node.strVal = opGorge(regs[rb].node.strVal,
+                                     regs[rc].node.strVal)
     of opcNError:
-      stackTrace(c, tos, pc, errUser, regs[ra].strVal)
+      stackTrace(c, tos, pc, errUser, regs[ra].node.strVal)
     of opcNWarning:
-      message(c.debug[pc], warnUser, regs[ra].strVal)
+      message(c.debug[pc], warnUser, regs[ra].node.strVal)
     of opcNHint:
-      message(c.debug[pc], hintUser, regs[ra].strVal)
+      message(c.debug[pc], hintUser, regs[ra].node.strVal)
     of opcParseExprToAst:
-      decodeB(nkMetaNode)
+      decodeB(rkNode)
       # c.debug[pc].line.int - countLines(regs[rb].strVal) ?
-      let ast = parseString(regs[rb].strVal, c.debug[pc].toFilename,
+      let ast = parseString(regs[rb].node.strVal, c.debug[pc].toFilename,
                             c.debug[pc].line.int)
       if sonsLen(ast) != 1:
         globalError(c.debug[pc], errExprExpected, "multiple statements")
-      setMeta(regs[ra], ast.sons[0])
+      regs[ra].node = ast.sons[0]
     of opcParseStmtToAst:
-      decodeB(nkMetaNode)
-      let ast = parseString(regs[rb].strVal, c.debug[pc].toFilename,
+      decodeB(rkNode)
+      let ast = parseString(regs[rb].node.strVal, c.debug[pc].toFilename,
                             c.debug[pc].line.int)
-      setMeta(regs[ra], ast)
+      regs[ra].node = ast
     of opcCallSite:
-      ensureKind(nkMetaNode)
-      if c.callsite != nil: setMeta(regs[ra], c.callsite)
+      ensureKind(rkNode)
+      if c.callsite != nil: regs[ra].node = c.callsite
       else: stackTrace(c, tos, pc, errFieldXNotFound, "callsite")
     of opcNLineInfo:
-      decodeB(nkStrLit)
-      let n = regs[rb]
-      regs[ra].strVal = n.info.toFileLineCol
-      regs[ra].info = c.debug[pc]
+      decodeB(rkNode)
+      let n = regs[rb].node
+      createStr regs[ra]
+      regs[ra].node.strVal = n.info.toFileLineCol
+      regs[ra].node.info = c.debug[pc]
     of opcEqIdent:
-      decodeBC(nkIntLit)
-      if regs[rb].kind == nkIdent and regs[rc].kind == nkIdent:
-        regs[ra].intVal = ord(regs[rb].ident.id == regs[rc].ident.id)
+      decodeBC(rkInt)
+      if regs[rb].node.kind == nkIdent and regs[rc].node.kind == nkIdent:
+        regs[ra].intVal = ord(regs[rb].node.ident.id == regs[rc].node.ident.id)
       else:
         regs[ra].intVal = 0
     of opcStrToIdent:
-      decodeB(nkIdent)
-      if regs[rb].kind notin {nkStrLit..nkTripleStrLit}:
+      decodeB(rkNode)
+      if regs[rb].node.kind notin {nkStrLit..nkTripleStrLit}:
         stackTrace(c, tos, pc, errFieldXNotFound, "strVal")
       else:
-        regs[ra].info = c.debug[pc]
-        regs[ra].ident = getIdent(regs[rb].strVal)
+        regs[ra].node = newNodeI(nkIdent, c.debug[pc])
+        regs[ra].node.ident = getIdent(regs[rb].node.strVal)
     of opcIdentToStr:
-      decodeB(nkStrLit)
-      let a = regs[rb]
-      regs[ra].info = c.debug[pc]
+      decodeB(rkNode)
+      let a = regs[rb].node
+      createStr regs[ra]
+      regs[ra].node.info = c.debug[pc]
       if a.kind == nkSym:
-        regs[ra].strVal = a.sym.name.s
+        regs[ra].node.strVal = a.sym.name.s
       elif a.kind == nkIdent:
-        regs[ra].strVal = a.ident.s
+        regs[ra].node.strVal = a.ident.s
       else:
         stackTrace(c, tos, pc, errFieldXNotFound, "ident")
     of opcSetType:
-      regs[ra].typ = c.types[instr.regBx - wordExcess]
+      if regs[ra].kind != rkNode:
+        internalError(c.debug[pc], "cannot set type")
+      regs[ra].node.typ = c.types[instr.regBx - wordExcess]
     of opcConv:
       let rb = instr.regB
       inc pc
-      let typ = c.types[c.code[pc].regBx - wordExcess]
-      if opConv(regs[ra], regs[rb], typ):
+      let desttyp = c.types[c.code[pc].regBx - wordExcess]
+      inc pc
+      let srctyp = c.types[c.code[pc].regBx - wordExcess]
+
+      if opConv(regs[ra], regs[rb], desttyp, srctyp):
         stackTrace(c, tos, pc, errGenerated,
           msgKindToString(errIllegalConvFromXtoY) % [
-          "unknown type" , "unknown type"])
+          typeToString(srctyp), typeToString(desttyp)])
     of opcCast:
       let rb = instr.regB
       inc pc
-      let typ = c.types[c.code[pc].regBx - wordExcess]
+      let desttyp = c.types[c.code[pc].regBx - wordExcess]
+      inc pc
+      let srctyp = c.types[c.code[pc].regBx - wordExcess]
+
       when hasFFI:
-        let dest = fficast(regs[rb], typ)
+        let dest = fficast(regs[rb], desttyp)
         asgnRef(regs[ra], dest)
       else:
         globalError(c.debug[pc], "cannot evaluate cast")
     of opcNSetIntVal:
-      decodeB(nkMetaNode)
-      var dest = regs[ra].uast
+      decodeB(rkNode)
+      var dest = regs[ra].node
       if dest.kind in {nkCharLit..nkInt64Lit} and 
-         regs[rb].kind in {nkCharLit..nkInt64Lit}:
+         regs[rb].kind in {rkInt}:
         dest.intVal = regs[rb].intVal
       else:
         stackTrace(c, tos, pc, errFieldXNotFound, "intVal")
     of opcNSetFloatVal:
-      decodeB(nkMetaNode)
-      var dest = regs[ra].uast
+      decodeB(rkNode)
+      var dest = regs[ra].node
       if dest.kind in {nkFloatLit..nkFloat64Lit} and 
-         regs[rb].kind in {nkFloatLit..nkFloat64Lit}:
+         regs[rb].kind in {rkFloat}:
         dest.floatVal = regs[rb].floatVal
       else: 
         stackTrace(c, tos, pc, errFieldXNotFound, "floatVal")
     of opcNSetSymbol:
-      decodeB(nkMetaNode)
-      var dest = regs[ra].uast
-      if dest.kind == nkSym and regs[rb].kind == nkSym:
-        dest.sym = regs[rb].sym
+      decodeB(rkNode)
+      var dest = regs[ra].node
+      if dest.kind == nkSym and regs[rb].node.kind == nkSym:
+        dest.sym = regs[rb].node.sym
       else: 
         stackTrace(c, tos, pc, errFieldXNotFound, "symbol")
     of opcNSetIdent:
-      decodeB(nkMetaNode)
-      var dest = regs[ra].uast
-      if dest.kind == nkIdent and regs[rb].kind == nkIdent:
-        dest.ident = regs[rb].ident
+      decodeB(rkNode)
+      var dest = regs[ra].node
+      if dest.kind == nkIdent and regs[rb].node.kind == nkIdent:
+        dest.ident = regs[rb].node.ident
       else: 
         stackTrace(c, tos, pc, errFieldXNotFound, "ident")
     of opcNSetType:
-      decodeB(nkMetaNode)
-      let b = regs[rb].skipMeta
+      decodeB(rkNode)
+      let b = regs[rb].node
       internalAssert b.kind == nkSym and b.sym.kind == skType
-      regs[ra].uast.typ = b.sym.typ
+      internalAssert regs[ra].node != nil
+      regs[ra].node.typ = b.sym.typ
     of opcNSetStrVal:
-      decodeB(nkMetaNode)
-      var dest = regs[ra].uast
+      decodeB(rkNode)
+      var dest = regs[ra].node
       if dest.kind in {nkStrLit..nkTripleStrLit} and 
-         regs[rb].kind in {nkStrLit..nkTripleStrLit}:
-        dest.strVal = regs[rb].strVal
+         regs[rb].kind in {rkNode}:
+        dest.strVal = regs[rb].node.strVal
       else:
         stackTrace(c, tos, pc, errFieldXNotFound, "strVal")
     of opcNNewNimNode:
-      decodeBC(nkMetaNode)
+      decodeBC(rkNode)
       var k = regs[rb].intVal
-      if k < 0 or k > ord(high(TNodeKind)) or k == ord(nkMetaNode):
+      if k < 0 or k > ord(high(TNodeKind)):
         internalError(c.debug[pc],
           "request to create a NimNode of invalid kind")
-      let cc = regs[rc].skipMeta
-      setMeta(regs[ra], newNodeI(TNodeKind(int(k)), 
-        if cc.kind == nkNilLit: c.debug[pc] else: cc.info))
-      regs[ra].sons[0].flags.incl nfIsRef
+      let cc = regs[rc].node
+      regs[ra].node = newNodeI(TNodeKind(int(k)),
+        if cc.kind == nkNilLit: c.debug[pc] else: cc.info)
+      regs[ra].node.flags.incl nfIsRef
     of opcNCopyNimNode:
-      decodeB(nkMetaNode)
-      setMeta(regs[ra], copyNode(regs[rb]))
+      decodeB(rkNode)
+      regs[ra].node = copyNode(regs[rb].node)
     of opcNCopyNimTree:
-      decodeB(nkMetaNode)
-      setMeta(regs[ra], copyTree(regs[rb]))
+      decodeB(rkNode)
+      regs[ra].node = copyTree(regs[rb].node)
     of opcNDel:
-      decodeBC(nkMetaNode)
+      decodeBC(rkNode)
       let bb = regs[rb].intVal.int
       for i in countup(0, regs[rc].intVal.int-1):
-        delSon(regs[ra].uast, bb)
+        delSon(regs[ra].node, bb)
     of opcGenSym:
-      decodeBC(nkMetaNode)
+      decodeBC(rkNode)
       let k = regs[rb].intVal
-      let name = if regs[rc].strVal.len == 0: ":tmp" else: regs[rc].strVal
+      let name = if regs[rc].node.strVal.len == 0: ":tmp"
+                 else: regs[rc].node.strVal
       if k < 0 or k > ord(high(TSymKind)):
         internalError(c.debug[pc], "request to create symbol of invalid kind")
       var sym = newSym(k.TSymKind, name.getIdent, c.module, c.debug[pc])
       incl(sym.flags, sfGenSym)
-      setMeta(regs[ra], newSymNode(sym))
+      regs[ra].node = newSymNode(sym)
     of opcTypeTrait:
       # XXX only supports 'name' for now; we can use regC to encode the
       # type trait operation
-      decodeB(nkStrLit)
-      var typ = regs[rb].typ
+      decodeB(rkNode)
+      var typ = regs[rb].node.typ
       internalAssert typ != nil
       while typ.kind == tyTypeDesc and typ.len > 0: typ = typ.sons[0]
-      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
-    of opcGlobalAlias:
-      let rb = instr.regBx - wordExcess - 1
-      regs[ra] = c.globals.sons[rb]
+      createStr regs[ra]
+      regs[ra].node.strVal = typ.typeToString(preferExported)
     inc pc
 
-proc fixType(result, n: PNode) {.inline.} =
-  # XXX do it deeply for complex values; there seems to be no simple
-  # solution except to check it deeply here.
-  #if result.typ.isNil: result.typ = n.typ
-  discard
-
 proc execute(c: PCtx, start: int): PNode =
   var tos = PStackFrame(prc: nil, comesFrom: 0, next: nil)
   newSeq(tos.slots, c.prc.maxSlots)
-  for i in 0 .. <c.prc.maxSlots: tos.slots[i] = newNode(nkEmpty)
-  result = rawExecute(c, start, tos)
+  result = rawExecute(c, start, tos).regToNode
 
 proc evalStmt*(c: PCtx, n: PNode) =
   let n = transformExpr(c.module, n)
@@ -1090,9 +1225,6 @@ proc evalExpr*(c: PCtx, n: PNode): PNode =
   let start = genExpr(c, n)
   assert c.code[start].opcode != opcEof
   result = execute(c, start)
-  if not result.isNil:
-    result = result.skipMeta
-    fixType(result, n)
 
 # for now we share the 'globals' environment. XXX Coming soon: An API for
 # storing&loading the 'globals' environment to get what a component system
@@ -1136,11 +1268,11 @@ proc evalConstExprAux(module, prc: PSym, n: PNode, mode: TEvalMode): PNode =
   let start = genExpr(c, n, requiresValue = mode!=emStaticStmt)
   if c.code[start].opcode == opcEof: return emptyNode
   assert c.code[start].opcode != opcEof
+  when debugEchoCode: c.echoCode start
   var tos = PStackFrame(prc: prc, comesFrom: 0, next: nil)
   newSeq(tos.slots, c.prc.maxSlots)
-  for i in 0 .. <c.prc.maxSlots: tos.slots[i] = newNode(nkEmpty)
-  result = rawExecute(c, start, tos)
-  fixType(result, n)
+  #for i in 0 .. <c.prc.maxSlots: tos.slots[i] = newNode(nkEmpty)
+  result = rawExecute(c, start, tos).regToNode
 
 proc evalConstExpr*(module: PSym, e: PNode): PNode = 
   result = evalConstExprAux(module, nil, e, emConst)
@@ -1151,13 +1283,14 @@ proc evalStaticExpr*(module: PSym, e: PNode, prc: PSym): PNode =
 proc evalStaticStmt*(module: PSym, e: PNode, prc: PSym) =
   discard evalConstExprAux(module, prc, e, emStaticStmt)
 
+proc setupCompileTimeVar*(module: PSym, n: PNode) =
+  discard evalConstExprAux(module, nil, n, emStaticStmt)
+
 proc setupMacroParam(x: PNode): PNode =
   result = x
   if result.kind in {nkHiddenSubConv, nkHiddenStdConv}: result = result.sons[1]
-  let y = result
-  y.flags.incl nfIsRef
-  result = newNode(nkMetaNode)
-  result.add y
+  result = canonValue(result)
+  result.flags.incl nfIsRef
   result.typ = x.typ
 
 var evalMacroCounter: int
@@ -1183,15 +1316,16 @@ proc evalMacroCall*(module: PSym, n, nOrig: PNode, sym: PSym): PNode =
   # doesn't end up in the parameter:
   #InternalAssert tos.slots.len >= L
   # return value:
-  tos.slots[0] = newNodeIT(nkEmpty, n.info, sym.typ.sons[0])
+  tos.slots[0].kind = rkNode
+  tos.slots[0].node = newNodeIT(nkEmpty, n.info, sym.typ.sons[0])
   # setup parameters:
   for i in 1 .. < min(tos.slots.len, L):
-    tos.slots[i] = setupMacroParam(n.sons[i])
+    tos.slots[i].kind = rkNode
+    tos.slots[i].node = setupMacroParam(n.sons[i])
   # temporary storage:
-  for i in L .. <maxSlots: tos.slots[i] = newNode(nkEmpty)
-  result = rawExecute(c, start, tos)
+  #for i in L .. <maxSlots: tos.slots[i] = newNode(nkEmpty)
+  result = rawExecute(c, start, tos).regToNode
   if cyclicTree(result): globalError(n.info, errCyclicTree)
   dec(evalMacroCounter)
-  if result != nil:
-    result = result.skipMeta
   c.callsite = nil
+  #debug result