summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/ast.nim6
-rw-r--r--compiler/astalgo.nim10
-rw-r--r--compiler/canonicalizer.nim288
-rw-r--r--compiler/ccgexprs.nim1
-rw-r--r--compiler/jsgen.nim1
-rw-r--r--compiler/msgs.nim4
-rw-r--r--compiler/renderer.nim2
-rw-r--r--compiler/rodread.nim2
-rw-r--r--compiler/sem.nim2
-rw-r--r--compiler/semexprs.nim4
-rw-r--r--compiler/semfold.nim2
-rw-r--r--compiler/semstmts.nim9
-rw-r--r--compiler/types.nim2
-rw-r--r--compiler/vm.nim967
-rw-r--r--compiler/vmdef.nim23
-rw-r--r--compiler/vmgen.nim174
16 files changed, 948 insertions, 549 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index fe724f4dd..bd8bdb30b 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -62,7 +62,7 @@ type
     nkTripleStrLit,       # a triple string literal """
     nkNilLit,             # the nil literal
                           # end of atoms
-    nkMetaNode,           # difficult to explain; represents itself
+    nkMetaNode_Obsolete,  # difficult to explain; represents itself
                           # (used for macros)
     nkDotCall,            # used to temporarily flag a nkCall node; 
                           # this is used
@@ -1112,10 +1112,6 @@ proc newNodeIT(kind: TNodeKind, info: TLineInfo, typ: PType): PNode =
   result.info = info
   result.typ = typ
 
-proc newMetaNodeIT*(tree: PNode, info: TLineInfo, typ: PType): PNode =
-  result = newNodeIT(nkMetaNode, info, typ)
-  result.add(tree)
-
 var emptyParams = newNode(nkFormalParams)
 emptyParams.addSon(emptyNode)
 
diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim
index 64c1b717c..cce2cc215 100644
--- a/compiler/astalgo.nim
+++ b/compiler/astalgo.nim
@@ -337,7 +337,10 @@ proc treeToYamlAux(n: PNode, marker: var TIntSet, indent: int,
         appf(result, ",$N$1\"floatVal\": $2", 
             [istr, toRope(n.floatVal.toStrMaxPrecision)])
       of nkStrLit..nkTripleStrLit: 
-        appf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)])
+        if n.strVal.isNil:
+          appf(result, ",$N$1\"strVal\": null", [istr])
+        else:
+          appf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)])
       of nkSym: 
         appf(result, ",$N$1\"sym\": $2", 
              [istr, symToYamlAux(n.sym, marker, indent + 2, maxRecDepth)])
@@ -407,7 +410,10 @@ proc debugTree(n: PNode, indent: int, maxRecDepth: int): PRope =
         appf(result, ",$N$1\"floatVal\": $2", 
             [istr, toRope(n.floatVal.toStrMaxPrecision)])
       of nkStrLit..nkTripleStrLit: 
-        appf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)])
+        if n.strVal.isNil:
+          appf(result, ",$N$1\"strVal\": null", [istr])
+        else:
+          appf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)])
       of nkSym: 
         appf(result, ",$N$1\"sym\": $2_$3", 
             [istr, toRope(n.sym.name.s), toRope(n.sym.id)])
diff --git a/compiler/canonicalizer.nim b/compiler/canonicalizer.nim
new file mode 100644
index 000000000..fb5b3b9ce
--- /dev/null
+++ b/compiler/canonicalizer.nim
@@ -0,0 +1,288 @@
+#
+#
+#           The Nimrod Compiler
+#        (c) Copyright 2014 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements the canonalization for the various caching mechanisms.
+
+import strutils, db_sqlite, md5
+
+var db: TDbConn
+
+# We *hash* the relevant information into 128 bit hashes. This should be good enough
+# to prevent any collisions.
+
+type
+  TUid = distinct MD5Digest
+
+# For name mangling we encode these hashes via a variant of base64 (called
+# 'base64a') and prepend the *primary* identifier to ease the debugging pain.
+# So a signature like:
+#
+#   proc gABI(c: PCtx; n: PNode; opc: TOpcode; a, b: TRegister; imm: BiggestInt)
+#
+# is mangled into:
+#   gABI_MTdmOWY5MTQ1MDcyNGQ3ZA
+#
+# This is a good compromise between correctness and brevity. ;-)
+
+const

+  cb64 = [
+    "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N",
+    "O", "P", "Q", "R", "S", "T" "U", "V", "W", "X", "Y", "Z", 
+    "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", 
+    "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", 
+    "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
+    "_A", "_B"]

+

+proc toBase64a(s: cstring, len: int): string =

+  ## encodes `s` into base64 representation. After `lineLen` characters, a 

+  ## `newline` is added.

+  var total = ((len + 2) div 3) * 4

+  result = newStringOfCap(total)

+  var i = 0

+  while i < s.len - 2:

+    let a = ord(s[i])

+    let b = ord(s[i+1])

+    let c = ord(s[i+2])

+    result.add cb64[a shr 2]

+    result.add cb64[((a and 3) shl 4) or ((b and 0xF0) shr 4)]

+    result.add cb64[((b and 0x0F) shl 2) or ((c and 0xC0) shr 6)]

+    result.add cb64[c and 0x3F]

+    inc(i, 3)

+  if i < s.len-1:

+    let a = ord(s[i])

+    let b = ord(s[i+1])

+    result.add cb64[a shr 2]

+    result.add cb64[((a and 3) shl 4) or ((b and 0xF0) shr 4)]

+    result.add cb64[((b and 0x0F) shl 2)]

+  elif i < s.len:

+    let a = ord(s[i])

+    result.add cb64[a shr 2]

+    result.add cb64[(a and 3) shl 4]

+
+proc toBase64a(u: TUid): string = toBase64a(cast[cstring](u), sizeof(u))
+
+proc `&=`(c: var MD5Context, s: string) = md5Update(c, s, s.len)
+
+proc hashSym(c: var MD5Context, s: PSym) =
+  if sfAnon in s.flags or s.kind == skGenericParam:
+    c &= ":anon"
+  else:
+    var it = s.owner
+    while it != nil: 
+      hashSym(c, it)
+      c &= "."
+      it = s.owner
+    c &= s.name.s
+
+proc hashTree(c: var MD5Context, n: PNode) =
+  if n == nil:
+    c &= "null"
+    return
+  var k = n.kind
+  md5Update(c, cast[cstring](addr(k)), 1)
+  # we really must not hash line information. 'n.typ' is debatable but
+  # shouldn't be necessary for now and avoids potential infinite recursions.
+  case n.kind
+  of nkEmpty, nkNilLit, nkType: discard
+  of nkIdent:
+    c &= n.ident.s
+  of nkSym:
+    hashSym(c, n.sym)
+  of nkCharLit..nkUInt64Lit:
+    var v = n.intVal
+    md5Update(c, cast[cstring](addr(v)), sizeof(v))
+  of nkFloatLit..nkFloat64Lit:
+    var v = n.floatVal
+    md5Update(c, cast[cstring](addr(v)), sizeof(v))
+  of nkStrLit..nkTripleStrLit:
+    c &= n.strVal
+  else:
+    for i in 0.. <n.len: hashTree(c, n.sons[i])
+
+const 
+  typeToStr: array[TTypeKind, string] = ["None", "bool", "Char", "empty",
+    "Array Constructor [$1]", "nil", "expr", "stmt", "typeDesc",
+    "GenericInvokation", "GenericBody", "GenericInst", "GenericParam",
+    "distinct $1", "enum", "ordinal[$1]", "array[$1, $2]", "object", "tuple",
+    "set[$1]", "range[$1]", "ptr ", "ref ", "var ", "seq[$1]", "proc",
+    "pointer", "OpenArray[$1]", "string", "CString", "Forward",
+    "int", "int8", "int16", "int32", "int64",
+    "float", "float32", "float64", "float128",
+    "uint", "uint8", "uint16", "uint32", "uint64",
+    "bignum", "const ",
+    "!", "varargs[$1]", "iter[$1]", "Error Type",
+    "BuiltInTypeClass", "UserTypeClass",
+    "UserTypeClassInst", "CompositeTypeClass",
+    "and", "or", "not", "any", "static", "TypeFromExpr", "FieldAccessor"]
+
+proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
+  var t = typ
+  result = ""
+  if t == nil: return 
+  if prefer == preferName and t.sym != nil and sfAnon notin t.sym.flags:
+    if t.kind == tyInt and isIntLit(t):
+      return t.sym.name.s & " literal(" & $t.n.intVal & ")"
+    return t.sym.name.s
+  case t.kind
+  of tyInt:
+    if not isIntLit(t) or prefer == preferExported:
+      result = typeToStr[t.kind]
+    else:
+      result = "int literal(" & $t.n.intVal & ")"
+  of tyGenericBody, tyGenericInst, tyGenericInvokation:
+    result = typeToString(t.sons[0]) & '['
+    for i in countup(1, sonsLen(t) -1 -ord(t.kind != tyGenericInvokation)):
+      if i > 1: add(result, ", ")
+      add(result, typeToString(t.sons[i]))
+    add(result, ']')
+  of tyTypeDesc:
+    if t.base.kind == tyNone: result = "typedesc"
+    else: result = "typedesc[" & typeToString(t.base) & "]"
+  of tyStatic:
+    internalAssert t.len > 0
+    result = "static[" & typeToString(t.sons[0]) & "]"
+  of tyUserTypeClass:
+    internalAssert t.sym != nil and t.sym.owner != nil
+    return t.sym.owner.name.s
+  of tyBuiltInTypeClass:
+    result = case t.base.kind:
+      of tyVar: "var"
+      of tyRef: "ref"
+      of tyPtr: "ptr"
+      of tySequence: "seq"
+      of tyArray: "array"
+      of tySet: "set"
+      of tyRange: "range"
+      of tyDistinct: "distinct"
+      of tyProc: "proc"
+      of tyObject: "object"
+      of tyTuple: "tuple"
+      else: (internalAssert(false); "")
+  of tyUserTypeClassInst:
+    let body = t.base
+    result = body.sym.name.s & "["
+    for i in countup(1, sonsLen(t) - 2):
+      if i > 1: add(result, ", ")
+      add(result, typeToString(t.sons[i]))
+    result.add "]"
+  of tyAnd:
+    result = typeToString(t.sons[0]) & " and " & typeToString(t.sons[1])
+  of tyOr:
+    result = typeToString(t.sons[0]) & " or " & typeToString(t.sons[1])
+  of tyNot:
+    result = "not " & typeToString(t.sons[0])
+  of tyExpr:
+    internalAssert t.len == 0
+    result = "expr"
+  of tyFromExpr, tyFieldAccessor:
+    result = renderTree(t.n)
+  of tyArray: 
+    if t.sons[0].kind == tyRange: 
+      result = "array[" & hashTree(t.sons[0].n) & ", " &
+          typeToString(t.sons[1]) & ']'
+    else: 
+      result = "array[" & typeToString(t.sons[0]) & ", " &
+          typeToString(t.sons[1]) & ']'
+  of tyArrayConstr: 
+    result = "Array constructor[" & hashTree(t.sons[0].n) & ", " &
+        typeToString(t.sons[1]) & ']'
+  of tySequence: 
+    result = "seq[" & typeToString(t.sons[0]) & ']'
+  of tyOrdinal: 
+    result = "ordinal[" & typeToString(t.sons[0]) & ']'
+  of tySet: 
+    result = "set[" & typeToString(t.sons[0]) & ']'
+  of tyOpenArray: 
+    result = "openarray[" & typeToString(t.sons[0]) & ']'
+  of tyDistinct: 
+    result = "distinct " & typeToString(t.sons[0], preferName)
+  of tyTuple: 
+    # we iterate over t.sons here, because t.n may be nil
+    result = "tuple["
+    if t.n != nil: 
+      assert(sonsLen(t.n) == sonsLen(t))
+      for i in countup(0, sonsLen(t.n) - 1): 
+        assert(t.n.sons[i].kind == nkSym)
+        add(result, t.n.sons[i].sym.name.s & ": " & typeToString(t.sons[i]))
+        if i < sonsLen(t.n) - 1: add(result, ", ")
+    else: 
+      for i in countup(0, sonsLen(t) - 1): 
+        add(result, typeToString(t.sons[i]))
+        if i < sonsLen(t) - 1: add(result, ", ")
+    add(result, ']')
+  of tyPtr, tyRef, tyVar, tyMutable, tyConst: 
+    result = typeToStr[t.kind] & typeToString(t.sons[0])
+  of tyRange:
+    result = "range " & hashTree(t.n)
+    if prefer != preferExported:
+      result.add("(" & typeToString(t.sons[0]) & ")")
+  of tyProc:
+    result = if tfIterator in t.flags: "iterator (" else: "proc ("
+    for i in countup(1, sonsLen(t) - 1): 
+      add(result, typeToString(t.sons[i]))
+      if i < sonsLen(t) - 1: add(result, ", ")
+    add(result, ')')
+    if t.sons[0] != nil: add(result, ": " & typeToString(t.sons[0]))
+    var prag: string
+    if t.callConv != ccDefault: prag = CallingConvToStr[t.callConv]
+    else: prag = ""
+    if tfNoSideEffect in t.flags: 
+      addSep(prag)
+      add(prag, "noSideEffect")
+    if tfThread in t.flags:
+      addSep(prag)
+      add(prag, "thread")
+    if len(prag) != 0: add(result, "{." & prag & ".}")
+  of tyVarargs, tyIter:
+    result = typeToStr[t.kind] % typeToString(t.sons[0])
+  else: 
+    result = typeToStr[t.kind]
+  if tfShared in t.flags: result = "shared " & result
+  if tfNotNil in t.flags: result.add(" not nil")
+
+
+proc createDb() =
+  db.exec(sql"""
+    create table if not exists Module(
+      id integer primary key,
+      name varchar(256) not null,
+      fullpath varchar(256) not null,
+      interfHash varchar(256) not null,
+      fullHash varchar(256) not null,
+      
+      created timestamp not null default (DATETIME('now')),
+    );""")
+
+  db.exec(sql"""
+    create table if not exists Symbol(
+      id integer primary key,
+      module integer not null,
+      name varchar(max) not null,
+      data varchar(max) not null,
+      created timestamp not null default (DATETIME('now')),
+
+      foreign key (module) references module(id)
+    );""")
+    
+  db.exec(sql"""
+    create table if not exists Type(
+      id integer primary key,
+      module integer not null,
+      name varchar(max) not null,
+      data varchar(max) not null,
+      created timestamp not null default (DATETIME('now')),
+
+      foreign key (module) references module(id)
+    );""")
+
+
+  #db.exec(sql"""
+  #  --create unique index if not exists TsstNameIx on TestResult(name);
+  #  """, [])
+
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index 27f7f4ba5..8cb423688 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -1915,7 +1915,6 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
       internalError(n.info, "expr: proc not init " & sym.name.s)
     putLocIntoDest(p, d, sym.loc)
   of nkClosure: genClosure(p, n, d)
-  of nkMetaNode: expr(p, n.sons[0], d)
 
   of nkEmpty: discard
   of nkWhileStmt: genWhileStmt(p, n)
diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim
index c0fc4131a..a8a15f542 100644
--- a/compiler/jsgen.nim
+++ b/compiler/jsgen.nim
@@ -1600,7 +1600,6 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
     if lfNoDecl in s.loc.flags or s.magic != mNone: discard
     elif not p.g.generatedSyms.containsOrIncl(s.id):
       app(p.locals, genProc(p, s))
-  of nkMetaNode: gen(p, n.sons[0], r)
   of nkType: r.res = genTypeInfo(p, n.typ)
   of nkStmtList, nkStmtListExpr:
     # this shows the distinction is nice for backends and should be kept
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index b44ca2ff0..66763e7f5 100644
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -67,7 +67,7 @@ type
     errAmbiguousCallXYZ, errWrongNumberOfArguments, 
     errXCannotBePassedToProcVar, 
     errXCannotBeInParamDecl, errPragmaOnlyInHeaderOfProc, errImplOfXNotAllowed, 
-    errImplOfXexpected, errNoSymbolToBorrowFromFound, errDiscardValue, 
+    errImplOfXexpected, errNoSymbolToBorrowFromFound, errDiscardValueX, 
     errInvalidDiscard, errIllegalConvFromXtoY, errCannotBindXTwice, 
     errInvalidOrderInArrayConstructor,
     errInvalidOrderInEnumX, errEnumXHasHoles, errExceptExpected, errInvalidTry, 
@@ -266,7 +266,7 @@ const
     errImplOfXNotAllowed: "implementation of \'$1\' is not allowed", 
     errImplOfXexpected: "implementation of \'$1\' expected", 
     errNoSymbolToBorrowFromFound: "no symbol to borrow from found", 
-    errDiscardValue: "value returned by statement has to be discarded", 
+    errDiscardValueX: "value of type '$1' has to be discarded", 
     errInvalidDiscard: "statement returns no value that can be discarded", 
     errIllegalConvFromXtoY: "conversion from $1 to $2 is invalid",
     errCannotBindXTwice: "cannot bind parameter \'$1\' twice", 
diff --git a/compiler/renderer.nim b/compiler/renderer.nim
index 1afb5961e..509c815c1 100644
--- a/compiler/renderer.nim
+++ b/compiler/renderer.nim
@@ -1268,7 +1268,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
       put(g, tkBracketLe, "[")
       gcomma(g, n)
       put(g, tkBracketRi, "]")
-  of nkMetaNode:
+  of nkMetaNode_Obsolete:
     put(g, tkParLe, "(META|")
     gsub(g, n.sons[0])
     put(g, tkParRi, ")")
diff --git a/compiler/rodread.nim b/compiler/rodread.nim
index b53135a95..036e6cc3c 100644
--- a/compiler/rodread.nim
+++ b/compiler/rodread.nim
@@ -890,7 +890,7 @@ proc loadStub*(s: PSym) =
   
   # deactivate the GC here because we do a deep recursion and generate no
   # garbage when restoring parts of the object graph anyway.
-  # Since we die with internal errors if this fails, so no try-finally is
+  # Since we die with internal errors if this fails, no try-finally is
   # necessary.
   GC_disable()
   rawLoadStub(s)
diff --git a/compiler/sem.nim b/compiler/sem.nim
index 09b2511f1..5ee46654e 100644
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -220,7 +220,7 @@ proc tryConstExpr(c: PContext, n: PNode): PNode =
       return nil
 
     result = fixupTypeAfterEval(c, result, e)
-  except:
+  except ERecoverableError:
     return nil
 
 proc semConstExpr(c: PContext, n: PNode): PNode =
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index c271911ab..538489490 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -641,9 +641,11 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
       result = evalStaticExpr(c.module, call, c.p.owner)
       if result.isNil: 
         localError(n.info, errCannotInterpretNodeX, renderTree(call))
+      else: result = fixupTypeAfterEval(c, result, n)
     else:
       result = evalConstExpr(c.module, call)
       if result.isNil: result = n
+      else: result = fixupTypeAfterEval(c, result, n)
     #if result != n:
     #  echo "SUCCESS evaluated at compile time: ", call.renderTree
 
@@ -653,6 +655,8 @@ proc semStaticExpr(c: PContext, n: PNode): PNode =
   if result.isNil:
     localError(n.info, errCannotInterpretNodeX, renderTree(n))
     result = emptyNode
+  else:
+    result = fixupTypeAfterEval(c, result, a)
 
 proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
                                      flags: TExprFlags): PNode =
diff --git a/compiler/semfold.nim b/compiler/semfold.nim
index 4740ddcb3..925a80832 100644
--- a/compiler/semfold.nim
+++ b/compiler/semfold.nim
@@ -537,7 +537,7 @@ proc foldArrayAccess(m: PSym, n: PNode): PNode =
       if result.kind == nkExprColonExpr: result = result.sons[1]
     else:
       localError(n.info, errIndexOutOfBounds)
-  of nkBracket, nkMetaNode: 
+  of nkBracket: 
     if (idx >= 0) and (idx < sonsLen(x)): result = x.sons[int(idx)]
     else: localError(n.info, errIndexOutOfBounds)
   of nkStrLit..nkTripleStrLit: 
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 6c4e29f29..c8d9e353a 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -126,7 +126,7 @@ proc implicitlyDiscardable(n: PNode): bool =
 proc fixNilType(n: PNode) =
   if isAtom(n):
     if n.kind != nkNilLit and n.typ != nil:
-      localError(n.info, errDiscardValue)
+      localError(n.info, errDiscardValueX, n.typ.typeToString)
   elif n.kind in {nkStmtList, nkStmtListExpr}:
     n.kind = nkStmtList
     for it in n: fixNilType(it)
@@ -155,7 +155,7 @@ proc discardCheck(c: PContext, result: PNode) =
       else:
         var n = result
         while n.kind in skipForDiscardable: n = n.lastSon
-        localError(n.info, errDiscardValue)
+        localError(n.info, errDiscardValueX, result.typ.typeToString)
 
 proc semIf(c: PContext, n: PNode): PNode = 
   result = n
@@ -332,6 +332,7 @@ proc checkNilable(v: PSym) =
 proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = 
   var b: PNode
   result = copyNode(n)
+  var hasCompileTime = false
   for i in countup(0, sonsLen(n)-1): 
     var a = n.sons[i]
     if gCmd == cmdIdeTools: suggestStmt(c, a)
@@ -411,7 +412,9 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
         v.typ = tup.sons[j]
         b.sons[j] = newSymNode(v)
       checkNilable(v)
-    
+      if sfCompileTime in v.flags: hasCompileTime = true
+  if hasCompileTime: vm.setupCompileTimeVar(c.module, result)
+
 proc semConst(c: PContext, n: PNode): PNode = 
   result = copyNode(n)
   for i in countup(0, sonsLen(n) - 1): 
diff --git a/compiler/types.nim b/compiler/types.nim
index d7148f110..e6178f446 100644
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -463,7 +463,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
   of tyAnd:
     result = typeToString(t.sons[0]) & " and " & typeToString(t.sons[1])
   of tyOr:
-    result = typeToString(t.sons[0]) & " and " & typeToString(t.sons[1])
+    result = typeToString(t.sons[0]) & " or " & typeToString(t.sons[1])
   of tyNot:
     result = "not " & typeToString(t.sons[0])
   of tyExpr:
diff --git a/compiler/vm.nim b/compiler/vm.nim
index 0929e072b..6277b2dc6 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -8,7 +8,7 @@
 #
 
 ## 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.
 
 import ast except getstr
 
@@ -23,10 +23,22 @@ when hasFFI:
   import evalffi
 
 type
+  TRegisterKind = enum
+    rkNone, rkNode, rkInt, rkFloat, rkRegisterAddr, rkNodeAddr
+  TRegister = 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 TRegister
+    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[TRegister]     # parameters passed to the proc + locals;
                               # parameters come first
     next: PStackFrame         # for stacking
     comesFrom: int
@@ -63,24 +75,9 @@ proc bailOut(c: PCtx; tos: PStackFrame) =
 when not defined(nimComputedGoto):
   {.pragma: computedGoto.}
 
-proc myreset(n: PNode) =
+proc myreset(n: var TRegister) =
   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 +109,29 @@ 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) =
+template createStrKeepNode(x) =
+  if x.node.isNil:
+    x.node = newNode(nkStrLit)
+  elif x.node.kind == nkNilLit:
+    system.reset(x.node[])
+    x.node.kind = nkStrLit
+  else:
+    assert x.node.kind in {nkStrLit..nkTripleStrLit}
+
+template createStr(x) =
+  x.node = newNode(nkStrLit)
+
+proc moveConst(x: var TRegister, y: TRegister) =
   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 +158,54 @@ 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 TRegister, y: TRegister) =
   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: PNode; x: TRegister) =
+  case x.kind
+  of rkNone: discard
+  of rkInt: n.intVal = x.intVal
+  of rkFloat: n.floatVal = x.floatVal
+  of rkNode: n[] = x.node[]
+  of rkRegisterAddr: putIntoNode(n, x.regAddr[])
+  of rkNodeAddr: n[] = x.nodeAddr[][]
+
+proc putIntoReg(dest: var TRegister; 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: TRegister): 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 +213,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[TRegister]): int =
   let raisedType = c.currentExceptionA.typ.skipTypes(abstractPtrs)
   var f = tos
   while true:
@@ -227,50 +255,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 TRegister, src: TRegister, 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)-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:
@@ -282,23 +325,19 @@ proc compile(c: PCtx, s: PSym): int =
   result = vmgen.genProc(c, s)
   #c.echoCode
 
-proc regsContents(regs: TNodeSeq) =
-  for i in 0.. <regs.len:
-    echo "Register ", i
-    #debug regs[i]
-
-proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
+proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TRegister =
   var pc = start
   var tos = tos
-  var regs: TNodeSeq # alias to tos.slots for performance
+  var regs: seq[TRegister] # 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 +357,333 @@ 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
+      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
-      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
+      decodeBC(rkNode)
       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}:
+        regs[ra].node = src.sons[rc]
+      else:
+        stackTrace(c, tos, pc, errIndexOutOfBounds)
     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:
-        stackTrace(c, tos, pc, errNilAccess)
-      assert regs[rb].kind == nkRefTy
-      # XXX this is not correct
-      regs[ra] = regs[rb].sons[0]
+      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, errIndexOutOfBounds)
+    of opcWrDeref:
+      # a[] = b
+      decodeBC(rkNode)
+      putIntoNode(regs[ra].node, regs[rb])
     of opcAddInt:
-      decodeBC(nkIntLit)
+      decodeBC(rkInt)
       regs[ra].intVal = regs[rb].intVal + regs[rc].intVal
     of opcAddImmInt:
-      decodeBImm(nkIntLit)
+      decodeBImm(rkInt)
       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.safeLen - 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)
+      decodeBC(rkInt)
       regs[ra].intVal = regs[rb].intVal div regs[rc].intVal
     of opcModInt:
-      decodeBC(nkIntLit)
+      decodeBC(rkInt)
       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 +691,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,7 +707,7 @@ 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:
@@ -668,15 +716,15 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
         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 +737,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'
@@ -712,7 +760,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
       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 +789,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,319 +798,345 @@ 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 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 TRegister(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)
+      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, opcReset:
       internalError(c.debug[pc], "too implement")
     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].skipMeta))
+      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.} =
@@ -1074,8 +1148,7 @@ proc fixType(result, n: PNode) {.inline.} =
 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)
@@ -1091,7 +1164,6 @@ proc evalExpr*(c: PCtx, n: PNode): PNode =
   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
@@ -1138,8 +1210,8 @@ proc evalConstExprAux(module, prc: PSym, n: PNode, mode: TEvalMode): PNode =
   assert c.code[start].opcode != opcEof
   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)
+  #for i in 0 .. <c.prc.maxSlots: tos.slots[i] = newNode(nkEmpty)
+  result = rawExecute(c, start, tos).regToNode
   fixType(result, n)
 
 proc evalConstExpr*(module: PSym, e: PNode): PNode = 
@@ -1151,13 +1223,13 @@ 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.flags.incl nfIsRef
   result.typ = x.typ
 
 var evalMacroCounter: int
@@ -1183,15 +1255,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
diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim
index 87159c813..72689c879 100644
--- a/compiler/vmdef.nim
+++ b/compiler/vmdef.nim
@@ -8,7 +8,7 @@
 #
 
 ## This module contains the type definitions for the new evaluation engine.
-## 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.
 
 import ast, passes, msgs, intsets
 
@@ -32,17 +32,17 @@ type
     opcAsgnFloat,
     opcAsgnRef,
     opcAsgnComplex,
+    opcRegToNode,
+    opcNodeToReg,
 
     opcLdArr,  # a = b[c]
-    opcLdArrRef,
     opcWrArr,  # a[b] = c
-    opcWrArrRef,
     opcLdObj,  # a = b.c
-    opcLdObjRef,
     opcWrObj,  # a.b = c
-    opcWrObjRef,
-    opcAddr,
-    opcDeref,
+    opcAddrReg,
+    opcAddrNode,
+    opcLdDeref,
+    opcWrDeref,
     opcWrStrIdx,
     opcLdStrIdx, # a = b[c]
     
@@ -117,15 +117,13 @@ type
     opcNew,
     opcNewSeq,
     opcLdNull,    # dest = nullvalue(types[Bx])
+    opcLdNullReg,
     opcLdConst,   # dest = constants[Bx]
     opcAsgnConst, # dest = copy(constants[Bx])
     opcLdGlobal,  # dest = globals[Bx]
+
     opcLdImmInt,  # dest = immediate value
     opcNBindSym,
-    opcWrGlobal,
-    opcWrGlobalRef,
-    opcGlobalAlias, # load an alias to a global into a register
-    opcGlobalOnce,  # used to introduce an assignment to a global once
     opcSetType,   # dest.typ = types[Bx]
     opcTypeTrait
 
@@ -165,8 +163,6 @@ type
     blocks*: seq[TBlock]    # blocks; temp data structure
     slots*: array[TRegister, tuple[inUse: bool, kind: TSlotKind]]
     maxSlots*: int
-    globals*: array[TRegister, int] # hack: to support passing globals byref
-                                    # we map a slot persistently to a global
     
   PCtx* = ref TCtx
   TCtx* = object of passes.TPassContext # code gen context
@@ -183,6 +179,7 @@ type
     callsite*: PNode
     mode*: TEvalMode
     features*: TSandboxFlags
+    traceActive*: bool
 
   TPosition* = distinct int
 
diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim
index 206cca0d7..b594c00a9 100644
--- a/compiler/vmgen.nim
+++ b/compiler/vmgen.nim
@@ -139,25 +139,12 @@ proc getTemp(c: PCtx; typ: PType): TRegister =
       if not c.slots[i].inUse:
         c.slots[i] = (inUse: true, kind: k)
         return TRegister(i)
+  if c.maxSlots >= high(TRegister):
+    internalError("cannot generate code; too many registers required")
   result = TRegister(c.maxSlots)
   c.slots[c.maxSlots] = (inUse: true, kind: k)
   inc c.maxSlots
 
-proc getGlobalSlot(c: PCtx; n: PNode; s: PSym): TRegister =
-  let p = c.prc
-  for i in 0 .. p.maxSlots-1:
-    if p.globals[i] == s.id: return TRegister(i)
-
-  result = TRegister(p.maxSlots)
-  p.slots[p.maxSlots] = (inUse: true, kind: slotFixedVar)
-  p.globals[p.maxSlots] = s.id
-  inc p.maxSlots
-  # XXX this is still not correct! We need to load the global in a proc init
-  # section, otherwise control flow could lead to a usage before it's been
-  # loaded.
-  c.gABx(n, opcGlobalAlias, result, s.position)
-  # XXX add some internal asserts here
-
 proc freeTemp(c: PCtx; r: TRegister) =
   let c = c.prc
   if c.slots[r].kind >= slotSomeTemp: c.slots[r].inUse = false
@@ -322,13 +309,7 @@ proc genAndOr(c: PCtx; n: PNode; opc: TOpcode; dest: var TDest) =
   c.patch(L1)
 
 proc nilLiteral(n: PNode): PNode =
-  if n.kind == nkNilLit and n.typ.sym != nil and
-       n.typ.sym.magic == mPNimrodNode:
-    let nilo = newNodeIT(nkNilLit, n.info, n.typ)
-    result = newNodeIT(nkMetaNode, n.info, n.typ)
-    result.add nilo
-  else:
-    result = n
+  result = n
 
 proc rawGenLiteral(c: PCtx; n: PNode): int =
   result = c.constants.len
@@ -470,21 +451,37 @@ proc genCall(c: PCtx; n: PNode; dest: var TDest) =
     c.gABC(n, opcIndCallAsgn, dest, x, n.len)
   c.freeTempRange(x, n.len)
 
+template isGlobal(s: PSym): bool = sfGlobal in s.flags and s.kind != skForVar
+
 proc needsAsgnPatch(n: PNode): bool = 
-  n.kind in {nkBracketExpr, nkDotExpr, nkCheckedFieldExpr}
+  n.kind in {nkBracketExpr, nkDotExpr, nkCheckedFieldExpr,
+             nkDerefExpr, nkHiddenDeref} or (n.kind == nkSym and n.sym.isGlobal)
 
 proc genAsgnPatch(c: PCtx; le: PNode, value: TRegister) =
   case le.kind
   of nkBracketExpr:
-    let dest = c.genx(le.sons[0])
+    let dest = c.genx(le.sons[0], {gfAddrOf})
     let idx = c.genx(le.sons[1])
-    c.gABC(le, opcWrArrRef, dest, idx, value)
+    c.gABC(le, opcWrArr, dest, idx, value)
+    c.freeTemp(dest)
+    c.freeTemp(idx)
   of nkDotExpr, nkCheckedFieldExpr:
     # XXX field checks here
     let left = if le.kind == nkDotExpr: le else: le.sons[0]
-    let dest = c.genx(left.sons[0])
+    let dest = c.genx(left.sons[0], {gfAddrOf})
     let idx = c.genx(left.sons[1])
-    c.gABC(left, opcWrObjRef, dest, idx, value)
+    c.gABC(left, opcWrObj, dest, idx, value)
+    c.freeTemp(dest)
+    c.freeTemp(idx)
+  of nkDerefExpr, nkHiddenDeref:
+    let dest = c.genx(le.sons[0], {gfAddrOf})
+    c.gABC(le, opcWrDeref, dest, value)
+    c.freeTemp(dest)
+  of nkSym:
+    if le.sym.isGlobal:
+      let dest = c.genx(le, {gfAddrOf})
+      c.gABC(le, opcWrDeref, dest, value)
+      c.freeTemp(dest)
   else:
     discard
 
@@ -594,10 +591,10 @@ proc genAddSubInt(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
 
 proc genConv(c: PCtx; n, arg: PNode; dest: var TDest; opc=opcConv) =  
   let tmp = c.genx(arg)
-  c.gABx(n, opcSetType, tmp, genType(c, arg.typ))
   if dest < 0: dest = c.getTemp(n.typ)
   c.gABC(n, opc, dest, tmp)
   c.gABx(n, opc, 0, genType(c, n.typ))
+  c.gABx(n, opc, 0, genType(c, arg.typ))
   c.freeTemp(tmp)
 
 proc genCard(c: PCtx; n: PNode; dest: var TDest) =
@@ -623,6 +620,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
     c.genAddSubInt(n, dest, opcAddInt)
   of mInc, mDec:
     unused(n, dest)
+    # XXX generates inefficient code for globals
     var d = c.genx(n.sons[1]).TDest
     c.genAddSubInt(n, d, if m == mInc: opcAddInt else: opcSubInt)
     c.genAsgnPatch(n.sons[1], d)
@@ -636,6 +634,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
     c.genNewSeq(n)
   of mNewString:
     genUnaryABC(c, n, dest, opcNewStr)
+    # XXX buggy
   of mNewStringOfCap:
     # we ignore the 'cap' argument and translate it as 'newString(0)'.
     # eval n.sons[1] for possible side effects:
@@ -644,6 +643,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
     if dest < 0: dest = c.getTemp(n.typ)
     c.gABC(n, opcNewStr, dest, tmp)
     c.freeTemp(tmp)
+    # XXX buggy
   of mLengthOpenArray, mLengthArray, mLengthSeq:
     genUnaryABI(c, n, dest, opcLenSeq)
   of mLengthStr:
@@ -905,6 +905,10 @@ const
     tyFloat, tyFloat32, tyFloat64, tyFloat128,
     tyUInt, tyUInt8, tyUInt16, tyUInt32, tyUInt64}
 
+proc fitsRegister*(t: PType): bool =
+  t.skipTypes(abstractInst-{tyTypeDesc}).kind in {
+    tyRange, tyEnum, tyBool, tyInt..tyUInt64}
+
 proc requiresCopy(n: PNode): bool =
   if n.typ.skipTypes(abstractInst-{tyTypeDesc}).kind in atomicTypes:
     result = false
@@ -919,7 +923,8 @@ proc unneededIndirection(n: PNode): bool =
 proc genAddrDeref(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode;
                   flags: TGenFlags) = 
   # a nop for certain types
-  let flags = if opc == opcAddr: flags+{gfAddrOf} else: flags
+  let isAddr = opc in {opcAddrNode, opcAddrReg}
+  let flags = if isAddr: flags+{gfAddrOf} else: flags
   # consider:
   # proc foo(f: var ref int) =
   #   f = new(int)
@@ -929,12 +934,17 @@ proc genAddrDeref(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode;
   #
   # The type of 'f' is 'var ref int' and of 'x' is 'ref int'. Hence for
   # nkAddr we must not use 'unneededIndirection', but for deref we use it.
-  if opc != opcAddr and unneededIndirection(n.sons[0]):
+  if not isAddr and unneededIndirection(n.sons[0]):
     gen(c, n.sons[0], dest, flags)
   else:
     let tmp = c.genx(n.sons[0], flags)
     if dest < 0: dest = c.getTemp(n.typ)
-    gABC(c, n, opc, dest, tmp)
+    if not isAddr:
+      gABC(c, n, opc, dest, tmp)
+    elif c.prc.slots[tmp].kind >= slotTempUnknown:
+      gABC(c, n, opcAddrReg, dest, tmp)
+    else:
+      gABC(c, n, opcAddrNode, dest, tmp)
     c.freeTemp(tmp)
 
 proc whichAsgnOpc(n: PNode): TOpcode =
@@ -952,8 +962,7 @@ proc whichAsgnOpc(n: PNode): TOpcode =
 
 proc isRef(t: PType): bool = t.skipTypes(abstractRange-{tyTypeDesc}).kind == tyRef
 
-proc whichAsgnOpc(n: PNode; opc: TOpcode): TOpcode =
-  if isRef(n.typ): succ(opc) else: opc
+proc whichAsgnOpc(n: PNode; opc: TOpcode): TOpcode = opc
 
 proc genAsgn(c: PCtx; dest: TDest; ri: PNode; requiresCopy: bool) =
   let tmp = c.genx(ri)
@@ -961,8 +970,6 @@ proc genAsgn(c: PCtx; dest: TDest; ri: PNode; requiresCopy: bool) =
   gABC(c, ri, whichAsgnOpc(ri), dest, tmp)
   c.freeTemp(tmp)
 
-template isGlobal(s: PSym): bool = sfGlobal in s.flags and s.kind != skForVar
-
 proc setSlot(c: PCtx; v: PSym) =
   # XXX generate type initialization here?
   if v.position == 0:
@@ -974,29 +981,36 @@ proc setSlot(c: PCtx; v: PSym) =
 proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
   case le.kind
   of nkBracketExpr:
-    let dest = c.genx(le.sons[0])
+    let dest = c.genx(le.sons[0], {gfAddrOf})
     let idx = c.genx(le.sons[1])
     let tmp = c.genx(ri)
     if le.sons[0].typ.skipTypes(abstractVarRange-{tyTypeDesc}).kind in {
         tyString, tyCString}:
       c.gABC(le, opcWrStrIdx, dest, idx, tmp)
     else:
-      c.gABC(le, whichAsgnOpc(le, opcWrArr), dest, idx, tmp)
+      c.gABC(le, opcWrArr, dest, idx, tmp)
     c.freeTemp(tmp)
   of nkDotExpr, nkCheckedFieldExpr:
     # XXX field checks here
     let left = if le.kind == nkDotExpr: le else: le.sons[0]
-    let dest = c.genx(left.sons[0])
+    let dest = c.genx(left.sons[0], {gfAddrOf})
     let idx = c.genx(left.sons[1])
     let tmp = c.genx(ri)
-    c.gABC(left, whichAsgnOpc(left, opcWrObj), dest, idx, tmp)
+    c.gABC(left, opcWrObj, dest, idx, tmp)
+    c.freeTemp(tmp)
+  of nkDerefExpr, nkHiddenDeref:
+    let dest = c.genx(le, {gfAddrOf})
+    let tmp = c.genx(ri)
+    c.gABC(le, opcWrDeref, dest, tmp)
     c.freeTemp(tmp)
   of nkSym:
     let s = le.sym
     if s.isGlobal:
       withTemp(tmp, le.typ):
-        gen(c, ri, tmp)
-        c.gABx(le, whichAsgnOpc(le, opcWrGlobal), tmp, s.position)
+        c.gen(le, tmp, {gfAddrOf})
+        let val = c.genx(ri)
+        c.gABC(le, opcWrDeref, tmp, val)
+        c.freeTemp(val)
     else:
       if s.kind == skForVar and c.mode == emRepl: c.setSlot s
       internalAssert s.position > 0 or (s.position == 0 and
@@ -1004,7 +1018,7 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
       var dest: TRegister = s.position + ord(s.kind == skParam)
       gen(c, ri, dest)
   else:
-    let dest = c.genx(le)
+    let dest = c.genx(le, {gfAddrOf})
     genAsgn(c, dest, ri, requiresCopy)
 
 proc genLit(c: PCtx; n: PNode; dest: var TDest) =
@@ -1034,18 +1048,22 @@ proc cannotEval(n: PNode) {.noinline.} =
   globalError(n.info, errGenerated, "cannot evaluate at compile time: " &
     n.renderTree)
 
+proc getNullValue*(typ: PType, info: TLineInfo): PNode
+
 proc genGlobalInit(c: PCtx; n: PNode; s: PSym) =
-  c.globals.add(emptyNode.copyNode)
+  c.globals.add(getNullValue(s.typ, n.info))
   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 dest = c.getTemp(s.typ)
+  c.gABx(n, opcLdGlobal, dest, s.position)
   let tmp = c.genx(s.ast)
-  c.gABx(n, whichAsgnOpc(n, opcWrGlobal), tmp, s.position)
+  c.gABC(n, opcWrDeref, dest, tmp)
+  c.freeTemp(dest)
   c.freeTemp(tmp)
 
-proc genRdVar(c: PCtx; n: PNode; dest: var TDest) =
+proc genRdVar(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
   let s = n.sym
   if s.isGlobal:
     if sfCompileTime in s.flags or c.mode == emRepl:
@@ -1055,9 +1073,12 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest) =
     if s.position == 0:
       if sfImportc in s.flags: c.importcSym(n.info, s)
       else: genGlobalInit(c, n, s)
-    if dest < 0:
-      dest = c.getGlobalSlot(n, s)
-      #c.gABx(n, opcAliasGlobal, dest, s.position)
+    if dest < 0: dest = c.getTemp(n.typ)
+    if gfAddrOf notin flags and fitsRegister(s.typ):
+      var cc = c.getTemp(n.typ)
+      c.gABx(n, opcLdGlobal, cc, s.position)
+      c.gABC(n, opcNodeToReg, dest, cc)
+      c.freeTemp(cc)
     else:
       c.gABx(n, opcLdGlobal, dest, s.position)
   else:
@@ -1078,7 +1099,13 @@ proc genAccess(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode;
   let a = c.genx(n.sons[0], flags)
   let b = c.genx(n.sons[1], {})
   if dest < 0: dest = c.getTemp(n.typ)
-  c.gABC(n, (if gfAddrOf in flags: succ(opc) else: opc), dest, a, b)
+  if gfAddrOf notin flags and fitsRegister(n.typ):
+    var cc = c.getTemp(n.typ)
+    c.gABC(n, opc, cc, a, b)
+    c.gABC(n, opcNodeToReg, dest, cc)
+    c.freeTemp(cc)
+  else:
+    c.gABC(n, opc, dest, a, b)
   c.freeTemp(a)
   c.freeTemp(b)
 
@@ -1096,7 +1123,6 @@ proc genArrAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
   else:
     genAccess(c, n, dest, opcLdArr, flags)
 
-proc getNullValue*(typ: PType, info: TLineInfo): PNode
 proc getNullValueAux(obj: PNode, result: PNode) = 
   case obj.kind
   of nkRecList:
@@ -1121,12 +1147,7 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode =
     result = newNodeIT(nkFloatLit, info, t)
   of tyVar, tyPointer, tyPtr, tyCString, tySequence, tyString, tyExpr,
      tyStmt, tyTypeDesc, tyStatic, tyRef:
-    if t.sym != nil and t.sym.magic == mPNimrodNode:
-      let nilo = newNodeIT(nkNilLit, info, t)
-      result = newNodeIT(nkMetaNode, info, t)
-      result.add nilo
-    else:
-      result = newNodeIT(nkNilLit, info, t)
+    result = newNodeIT(nkNilLit, info, t)
   of tyProc:
     if t.callConv != ccClosure:
       result = newNodeIT(nkNilLit, info, t)
@@ -1154,6 +1175,9 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode =
     result = newNodeIT(nkCurly, info, t)
   else: internalError("getNullValue: " & $t.kind)
 
+proc ldNullOpcode(t: PType): TOpcode =
+  if fitsRegister(t): opcLdNullReg else: opcLdNull
+
 proc genVarSection(c: PCtx; n: PNode) =
   for a in n:
     if a.kind == nkCommentStmt: continue
@@ -1164,8 +1188,8 @@ proc genVarSection(c: PCtx; n: PNode) =
         setSlot(c, a[i].sym)
         # v = t[i]
         var v: TDest = -1
-        genRdVar(c, a[i], v)
-        c.gABC(n, opcLdObj, v, tmp, i)
+        genRdVar(c, a[i], v, {gfAddrOf})
+        c.gABC(n, opcWrObj, v, tmp, i)
         # XXX globals?
       c.freeTemp(tmp)
     elif a.sons[0].kind == nkSym:
@@ -1177,27 +1201,28 @@ 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):
               c.gABx(a, opcLdNull, tmp, c.genType(s.typ))
               c.gABx(a, whichAsgnOpc(a.sons[0], opcWrGlobal), tmp, s.position)
         else:
-          let tmp = genx(c, a.sons[2])
-          c.gABx(a, whichAsgnOpc(a.sons[0], opcWrGlobal), tmp, s.position)
+          let tmp = c.genx(a.sons[0], {gfAddrOf})
+          let val = c.genx(a.sons[2])
+          c.gABC(a, opcWrDeref, tmp, val)
+          c.freeTemp(val)
           c.freeTemp(tmp)
       else:
         setSlot(c, s)
         if a.sons[2].kind == nkEmpty:
-          c.gABx(a, opcLdNull, s.position, c.genType(s.typ))
+          c.gABx(a, ldNullOpcode(s.typ), s.position, c.genType(s.typ))
         else:
           gen(c, a.sons[2], s.position.TRegister)
     else:
       # assign to a.sons[0]; happens for closures
       if a.sons[2].kind == nkEmpty:
         let tmp = genx(c, a.sons[0])
-        c.gABx(a, opcLdNull, tmp, c.genType(a.sons[0].typ))
+        c.gABx(a, ldNullOpcode(a[0].typ), tmp, c.genType(a.sons[0].typ))
         c.freeTemp(tmp)
       else:
         genAsgn(c, a.sons[0], a.sons[2], true)
@@ -1205,10 +1230,19 @@ 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)
+  let seqType = n.typ.skipTypes(abstractVar-{tyTypeDesc})
+  if seqType.kind == tySequence:
+    var tmp = c.getTemp(intType)
+    c.gABx(n, opcLdImmInt, tmp, n.len)
+    c.gABx(n, opcNewSeq, dest, c.genType(seqType))
+    c.gABx(n, opcNewSeq, tmp, 0)
+    c.freeTemp(tmp)
+  
   if n.len > 0:
-    let intType = getSysType(tyInt)
     var tmp = getTemp(c, intType)
-    c.gABx(n, opcLdNull, tmp, c.genType(intType))
+    c.gABx(n, opcLdNullReg, tmp, c.genType(intType))
     for x in n:
       let a = c.genx(x)
       c.gABC(n, whichAsgnOpc(x, opcWrArr), dest, tmp, a)
@@ -1274,7 +1308,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
     let s = n.sym
     case s.kind
     of skVar, skForVar, skTemp, skLet, skParam, skResult:
-      genRdVar(c, n, dest)
+      genRdVar(c, n, dest, flags)
     of skProc, skConverter, skMacro, skTemplate, skMethod, skIterator:
       # 'skTemplate' is only allowed for 'getAst' support:
       if sfImportc in s.flags: c.importcSym(n.info, s)
@@ -1320,8 +1354,8 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
   of nkDotExpr: genObjAccess(c, n, dest, flags)
   of nkCheckedFieldExpr: genCheckedObjAccess(c, n, dest, flags)
   of nkBracketExpr: genArrAccess(c, n, dest, flags)
-  of nkDerefExpr, nkHiddenDeref: genAddrDeref(c, n, dest, opcDeref, flags)
-  of nkAddr, nkHiddenAddr: genAddrDeref(c, n, dest, opcAddr, flags)
+  of nkDerefExpr, nkHiddenDeref: genAddrDeref(c, n, dest, opcLdDeref, flags)
+  of nkAddr, nkHiddenAddr: genAddrDeref(c, n, dest, opcAddrNode, flags)
   of nkWhenStmt, nkIfStmt, nkIfExpr: genIf(c, n, dest)
   of nkCaseStmt: genCase(c, n, dest)
   of nkWhileStmt:
@@ -1506,7 +1540,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 == "concatStyleInterpolation":
+    #if s.name.s == "importImpl_forward" or s.name.s == "importImpl":
     #  c.echoCode(result)
     # echo renderTree(body)
     c.prc = oldPrc