summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2023-10-31 21:32:09 +0100
committerGitHub <noreply@github.com>2023-10-31 21:32:09 +0100
commit801c02bf48b1612c8bf58ed113f944c9d6e32ead (patch)
tree750b978864d2d47b2dc22d38ee3feacb15871ba6
parent2ae344f1c204f92a944afeb70fe6b1ca1c419f62 (diff)
downloadNim-801c02bf48b1612c8bf58ed113f944c9d6e32ead.tar.gz
so close... (#22885)
-rw-r--r--compiler/main.nim4
-rw-r--r--compiler/modulegraphs.nim1
-rw-r--r--compiler/nir/ast2ir.nim94
-rw-r--r--compiler/nir/nir.nim1
-rw-r--r--compiler/nir/nirinsts.nim28
-rw-r--r--compiler/nir/nirvm.nim283
-rw-r--r--compiler/pipelines.nim3
7 files changed, 255 insertions, 159 deletions
diff --git a/compiler/main.nim b/compiler/main.nim
index 0627a61bb..6651128eb 100644
--- a/compiler/main.nim
+++ b/compiler/main.nim
@@ -201,7 +201,9 @@ proc commandCompileToJS(graph: ModuleGraph) =
 proc commandInteractive(graph: ModuleGraph; useNir: bool) =
   graph.config.setErrorMaxHighMaybe
   initDefines(graph.config.symbols)
-  if not useNir:
+  if useNir:
+    defineSymbol(graph.config.symbols, "noSignalHandler")
+  else:
     defineSymbol(graph.config.symbols, "nimscript")
   # note: seems redundant with -d:nimHasLibFFI
   when hasFFI: defineSymbol(graph.config.symbols, "nimffi")
diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim
index 325c0adb1..ba636eb5a 100644
--- a/compiler/modulegraphs.nim
+++ b/compiler/modulegraphs.nim
@@ -92,6 +92,7 @@ type
     importDeps*: Table[FileIndex, seq[FileIndex]] # explicit import module dependencies
     suggestMode*: bool # whether we are in nimsuggest mode or not.
     invalidTransitiveClosure: bool
+    interactive*: bool
     inclToMod*: Table[FileIndex, FileIndex] # mapping of include file to the
                                             # first module that included it
     importStack*: seq[FileIndex]  # The current import stack. Used for detecting recursive
diff --git a/compiler/nir/ast2ir.nim b/compiler/nir/ast2ir.nim
index f3b68474b..ad04dc103 100644
--- a/compiler/nir/ast2ir.nim
+++ b/compiler/nir/ast2ir.nim
@@ -205,7 +205,7 @@ proc xjmp(c: var ProcCon; n: PNode; jk: JmpKind; v: Value): LabelId =
     c.code.copyTree Tree(v)
     build c.code, info, SelectPair:
       build c.code, info, SelectValue:
-        c.code.boolVal(info, jk == opcTJmp)
+        c.code.boolVal(c.lit.numbers, info, jk == opcTJmp)
       c.code.gotoLabel info, Goto, result
 
 proc patch(c: var ProcCon; n: PNode; L: LabelId) =
@@ -311,8 +311,7 @@ proc tempToDest(c: var ProcCon; n: PNode; d: var Value; tmp: Value) =
     d = tmp
   else:
     let info = toLineInfo(c, n.info)
-    build c.code, info, Asgn:
-      c.code.addTyped info, typeToIr(c.m, n.typ)
+    buildTyped c.code, info, Asgn, typeToIr(c.m, n.typ):
       c.code.copyTree d
       c.code.copyTree tmp
     freeTemp(c, tmp)
@@ -362,7 +361,7 @@ template buildCond(useNegation: bool; cond: typed; body: untyped) =
     c.code.copyTree cond
     build c.code, info, SelectPair:
       build c.code, info, SelectValue:
-        c.code.boolVal(info, useNegation)
+        c.code.boolVal(c.lit.numbers, info, useNegation)
       c.code.gotoLabel info, Goto, lab
 
   body
@@ -381,7 +380,7 @@ template buildIfThenElse(cond: typed; then, otherwise: untyped) =
     c.code.copyTree cond
     build c.code, info, SelectPair:
       build c.code, info, SelectValue:
-        c.code.boolVal(info, false)
+        c.code.boolVal(c.lit.numbers, info, false)
       c.code.gotoLabel info, Goto, lelse
 
   then()
@@ -406,8 +405,7 @@ proc genCase(c: var ProcCon; n: PNode; d: var Value) =
   let ending = newLabel(c.labelGen)
   let info = toLineInfo(c, n.info)
   withTemp(tmp, n[0]):
-    build c.code, info, Select:
-      c.code.addTyped info, typeToIr(c.m, n[0].typ)
+    buildTyped c.code, info, Select, typeToIr(c.m, n[0].typ):
       c.gen(n[0], tmp)
       for i in 1..<n.len:
         let section = newLabel(c.labelGen)
@@ -432,8 +430,7 @@ proc genCase(c: var ProcCon; n: PNode; d: var Value) =
   c.code.addLabel info, Label, ending
 
 proc rawCall(c: var ProcCon; info: PackedLineInfo; opc: Opcode; t: TypeId; args: var openArray[Value]) =
-  build c.code, info, opc:
-    c.code.addTyped info, t
+  buildTyped c.code, info, opc, t:
     if opc in {CheckedCall, CheckedIndirectCall}:
       c.code.addLabel info, CheckedGoto, c.exitLabel
     for a in mitems(args):
@@ -479,8 +476,7 @@ proc genCall(c: var ProcCon; n: PNode; d: var Value) =
   if not isEmptyType(n.typ):
     if isEmpty(d): d = getTemp(c, n)
     # XXX Handle problematic aliasing here: `a = f_canRaise(a)`.
-    build c.code, info, Asgn:
-      c.code.addTyped info, tb
+    buildTyped c.code, info, Asgn, tb:
       c.code.copyTree d
       rawCall c, info, opc, tb, args
   else:
@@ -492,8 +488,7 @@ proc genRaise(c: var ProcCon; n: PNode) =
   let tb = typeToIr(c.m, n[0].typ)
 
   let d = genx(c, n[0])
-  build c.code, info, SetExc:
-    c.code.addTyped info, tb
+  buildTyped c.code, info, SetExc, tb:
     c.code.copyTree d
   c.freeTemp(d)
   c.code.addLabel info, Goto, c.exitLabel
@@ -583,10 +578,10 @@ proc genIndex(c: var ProcCon; n: PNode; arr: PType; d: var Value) =
   if optBoundsCheck in c.options:
     let idx = move d
     build d, info, CheckedIndex:
+      d.Tree.addLabel info, CheckedGoto, c.exitLabel
       copyTree d.Tree, idx
       let x = toInt64 lengthOrd(c.config, arr)
       d.addIntVal c.lit.numbers, info, c.m.nativeIntId, x
-      d.Tree.addLabel info, CheckedGoto, c.exitLabel
 
 proc rawGenNew(c: var ProcCon; d: Value; refType: PType; ninfo: TLineInfo; needsInit: bool) =
   assert refType.kind == tyRef
@@ -715,7 +710,7 @@ proc genBinaryOp(c: var ProcCon; n: PNode; d: var Value; opc: Opcode) =
   let t = typeToIr(c.m, n.typ)
   template body(target) =
     buildTyped target, info, opc, t:
-      if optOverflowCheck in c.options and opc in {CheckedAdd, CheckedSub, CheckedMul, CheckedDiv, CheckedMod}:
+      if opc in {CheckedAdd, CheckedSub, CheckedMul, CheckedDiv, CheckedMod}:
         target.addLabel info, CheckedGoto, c.exitLabel
       copyTree target, tmp
       copyTree target, tmp2
@@ -756,6 +751,8 @@ proc genIncDec(c: var ProcCon; n: PNode; opc: Opcode) =
   buildTyped c.code, info, Asgn, t:
     copyTree c.code, d
     buildTyped c.code, info, opc, t:
+      if opc in {CheckedAdd, CheckedSub}:
+        c.code.addLabel info, CheckedGoto, c.exitLabel
       copyTree c.code, d
       copyTree c.code, tmp
   c.freeTemp(tmp)
@@ -974,7 +971,7 @@ proc genInSet(c: var ProcCon; n: PNode; d: var Value) =
     if ex == nil:
       let info = toLineInfo(c, n.info)
       template body(target) =
-        boolVal target, info, false
+        boolVal target, c.lit.numbers, info, false
       intoDest d, info, Bool8Id, body
     else:
       gen c, ex, d
@@ -1062,7 +1059,7 @@ proc beginCountLoop(c: var ProcCon; info: PackedLineInfo; first, last: int): (Sy
       c.code.addIntVal c.lit.numbers, info, c.m.nativeIntId, last
     build c.code, info, SelectPair:
       build c.code, info, SelectValue:
-        c.code.boolVal(info, false)
+        c.code.boolVal(c.lit.numbers, info, false)
       c.code.gotoLabel info, Goto, result[2]
 
 proc beginCountLoop(c: var ProcCon; info: PackedLineInfo; first, last: Value): (SymId, LabelId, LabelId) =
@@ -1080,7 +1077,7 @@ proc beginCountLoop(c: var ProcCon; info: PackedLineInfo; first, last: Value): (
       copyTree c.code, last
     build c.code, info, SelectPair:
       build c.code, info, SelectValue:
-        c.code.boolVal(info, false)
+        c.code.boolVal(c.lit.numbers, info, false)
       c.code.gotoLabel info, Goto, result[2]
 
 proc endLoop(c: var ProcCon; info: PackedLineInfo; s: SymId; back, exit: LabelId) =
@@ -1126,7 +1123,7 @@ proc genLeSet(c: var ProcCon; n: PNode; d: var Value) =
       c.code.copyTree d
       build c.code, info, SelectPair:
         build c.code, info, SelectValue:
-          c.code.boolVal(info, false)
+          c.code.boolVal(c.lit.numbers, info, false)
         c.code.gotoLabel info, Goto, endLabel
 
     endLoop(c, info, idx, backLabel, endLabel)
@@ -1462,6 +1459,7 @@ proc genStrConcat(c: var ProcCon; n: PNode; d: var Value) =
     buildTyped c.code, info, Asgn, c.m.nativeIntId:
       c.code.addSymUse info, tmpLen
       buildTyped c.code, info, CheckedAdd, c.m.nativeIntId:
+        c.code.addLabel info, CheckedGoto, c.exitLabel
         c.code.addSymUse info, tmpLen
         buildTyped c.code, info, FieldAt, typeToIr(c.m, n.typ):
           copyTree c.code, a
@@ -1539,7 +1537,7 @@ proc genMove(c: var ProcCon; n: PNode; d: var Value) =
 
       build c.code, info, SelectPair:
         build c.code, info, SelectValue:
-          c.code.boolVal(info, true)
+          c.code.boolVal(c.lit.numbers, info, true)
         c.code.gotoLabel info, Goto, lab1
 
     gen(c, n[3])
@@ -1636,6 +1634,7 @@ proc genIndexCheck(c: var ProcCon; n: PNode; a: Value; kind: IndexFor; arr: PTyp
     result = default(Value)
     let idx = genx(c, n)
     build result, info, CheckedIndex:
+      result.Tree.addLabel info, CheckedGoto, c.exitLabel
       copyTree result.Tree, idx
       case kind
       of ForSeq, ForStr:
@@ -1649,7 +1648,6 @@ proc genIndexCheck(c: var ProcCon; n: PNode; a: Value; kind: IndexFor; arr: PTyp
       of ForArray:
         let x = toInt64 lengthOrd(c.config, arr)
         result.addIntVal c.lit.numbers, info, c.m.nativeIntId, x
-      result.Tree.addLabel info, CheckedGoto, c.exitLabel
     freeTemp c, idx
   else:
     result = genx(c, n)
@@ -1669,7 +1667,7 @@ proc addSliceFields(c: var ProcCon; target: var Tree; info: PackedLineInfo;
     buildTyped target, info, ObjConstr, typeToIr(c.m, n.typ):
       target.addImmediateVal info, 0
       buildTyped target, info, AddrOf, elemType:
-        buildTyped target, info, ArrayAt, pay[1]:
+        buildTyped target, info, DerefArrayAt, pay[1]:
           buildTyped target, info, FieldAt, typeToIr(c.m, arrType):
             copyTree target, x
             target.addImmediateVal info, 1 # (len, p)-pair
@@ -1716,7 +1714,7 @@ proc addSliceFields(c: var ProcCon; target: var Tree; info: PackedLineInfo;
     buildTyped target, info, ObjConstr, typeToIr(c.m, n.typ):
       target.addImmediateVal info, 0
       buildTyped target, info, AddrOf, elemType:
-        buildTyped target, info, ArrayAt, pay:
+        buildTyped target, info, DerefArrayAt, pay:
           buildTyped target, info, FieldAt, typeToIr(c.m, arrType):
             copyTree target, x
             target.addImmediateVal info, 0 # (p, len)-pair
@@ -1751,14 +1749,14 @@ proc genMagic(c: var ProcCon; n: PNode; d: var Value; m: TMagic) =
   case m
   of mAnd: c.genAndOr(n, opcFJmp, d)
   of mOr: c.genAndOr(n, opcTJmp, d)
-  of mPred, mSubI: c.genBinaryOp(n, d, CheckedSub)
-  of mSucc, mAddI: c.genBinaryOp(n, d, CheckedAdd)
+  of mPred, mSubI: c.genBinaryOp(n, d, if optOverflowCheck in c.options: CheckedSub else: Sub)
+  of mSucc, mAddI: c.genBinaryOp(n, d, if optOverflowCheck in c.options: CheckedAdd else: Add)
   of mInc:
     unused(c, n, d)
-    c.genIncDec(n, CheckedAdd)
+    c.genIncDec(n, if optOverflowCheck in c.options: CheckedAdd else: Add)
   of mDec:
     unused(c, n, d)
-    c.genIncDec(n, CheckedSub)
+    c.genIncDec(n, if optOverflowCheck in c.options: CheckedSub else: Sub)
   of mOrd, mChr, mUnown:
     c.gen(n[1], d)
   of generatedMagics:
@@ -1773,9 +1771,9 @@ proc genMagic(c: var ProcCon; n: PNode; d: var Value; m: TMagic) =
   of mNewString, mNewStringOfCap, mExit: c.genCall(n, d)
   of mLengthOpenArray, mLengthArray, mLengthSeq, mLengthStr:
     genArrayLen(c, n, d)
-  of mMulI: genBinaryOp(c, n, d, CheckedMul)
-  of mDivI: genBinaryOp(c, n, d, CheckedDiv)
-  of mModI: genBinaryOp(c, n, d, CheckedMod)
+  of mMulI: genBinaryOp(c, n, d, if optOverflowCheck in c.options: CheckedMul else: Mul)
+  of mDivI: genBinaryOp(c, n, d, if optOverflowCheck in c.options: CheckedDiv else: Div)
+  of mModI: genBinaryOp(c, n, d, if optOverflowCheck in c.options: CheckedMod else: Mod)
   of mAddF64: genBinaryOp(c, n, d, Add)
   of mSubF64: genBinaryOp(c, n, d, Sub)
   of mMulF64: genBinaryOp(c, n, d, Mul)
@@ -1977,7 +1975,7 @@ proc addAddrOfFirstElem(c: var ProcCon; target: var Tree; info: PackedLineInfo;
     let t = typeToIr(c.m, typ)
     target.addImmediateVal info, 0
     buildTyped target, info, AddrOf, elemType:
-      buildTyped target, info, ArrayAt, c.m.strPayloadId[1]:
+      buildTyped target, info, DerefArrayAt, c.m.strPayloadId[1]:
         buildTyped target, info, FieldAt, typeToIr(c.m, arrType):
           copyTree target, tmp
           target.addImmediateVal info, 1 # (len, p)-pair
@@ -1992,7 +1990,7 @@ proc addAddrOfFirstElem(c: var ProcCon; target: var Tree; info: PackedLineInfo;
     let t = typeToIr(c.m, typ)
     target.addImmediateVal info, 0
     buildTyped target, info, AddrOf, elemType:
-      buildTyped target, info, ArrayAt, seqPayloadPtrType(c.m.types, c.m.nirm.types, typ)[1]:
+      buildTyped target, info, DerefArrayAt, seqPayloadPtrType(c.m.types, c.m.nirm.types, typ)[1]:
         buildTyped target, info, FieldAt, typeToIr(c.m, arrType):
           copyTree target, tmp
           target.addImmediateVal info, 1 # (len, p)-pair
@@ -2102,10 +2100,11 @@ proc genSeqConstr(c: var ProcCon; n: PNode; d: var Value) =
 
   for i in 0..<n.len:
     var dd = default(Value)
-    buildTyped dd, info, ArrayAt, seqPayloadPtrType(c.m.types, c.m.nirm.types, seqtype)[1]:
+    buildTyped dd, info, DerefArrayAt, seqPayloadPtrType(c.m.types, c.m.nirm.types, seqtype)[1]:
       buildTyped dd, info, FieldAt, typeToIr(c.m, seqtype):
         copyTree Tree(dd), d
-        dd.addIntVal c.lit.numbers, info, c.m.nativeIntId, i
+        dd.addImmediateVal info, 1 # (len, p)-pair
+      dd.addIntVal c.lit.numbers, info, c.m.nativeIntId, i
     gen(c, n[i], dd)
 
   freeTemp c, d
@@ -2242,10 +2241,10 @@ proc genRangeCheck(c: var ProcCon; n: PNode; d: var Value) =
     let b = c.genx n[2]
     template body(target) =
       buildTyped target, info, CheckedRange, typeToIr(c.m, n.typ):
+        target.addLabel info, CheckedGoto, c.exitLabel
         copyTree target, tmp
         copyTree target, a
         copyTree target, b
-        target.addLabel info, CheckedGoto, c.exitLabel
     valueIntoDest c, info, d, n.typ, body
     freeTemp c, tmp
     freeTemp c, a
@@ -2263,7 +2262,7 @@ proc genArrAccess(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) =
     let b = genIndexCheck(c, n[1], a, ForStr, arrayType)
     let t = typeToIr(c.m, n.typ)
     template body(target) =
-      buildTyped target, info, ArrayAt, c.m.strPayloadId[1]:
+      buildTyped target, info, DerefArrayAt, c.m.strPayloadId[1]:
         buildTyped target, info, FieldAt, typeToIr(c.m, arrayType):
           copyTree target, a
           target.addImmediateVal info, 1 # (len, p)-pair
@@ -2276,7 +2275,7 @@ proc genArrAccess(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) =
     let a = genx(c, n[0], flags)
     let b = genx(c, n[1])
     template body(target) =
-      buildTyped target, info, ArrayAt, typeToIr(c.m, arrayType):
+      buildTyped target, info, DerefArrayAt, typeToIr(c.m, arrayType):
         copyTree target, a
         copyTree target, b
     valueIntoDest c, info, d, n.typ, body
@@ -2298,7 +2297,7 @@ proc genArrAccess(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) =
     let b = genIndexCheck(c, n[1], a, ForOpenArray, arrayType)
     let t = typeToIr(c.m, n.typ)
     template body(target) =
-      buildTyped target, info, ArrayAt, openArrayPayloadType(c.m.types, c.m.nirm.types, n[0].typ):
+      buildTyped target, info, DerefArrayAt, openArrayPayloadType(c.m.types, c.m.nirm.types, n[0].typ):
         buildTyped target, info, FieldAt, typeToIr(c.m, arrayType):
           copyTree target, a
           target.addImmediateVal info, 0 # (p, len)-pair
@@ -2324,7 +2323,7 @@ proc genArrAccess(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) =
     let b = genIndexCheck(c, n[1], a, ForSeq, arrayType)
     let t = typeToIr(c.m, n.typ)
     template body(target) =
-      buildTyped target, info, ArrayAt, seqPayloadPtrType(c.m.types, c.m.nirm.types, n[0].typ)[1]:
+      buildTyped target, info, DerefArrayAt, seqPayloadPtrType(c.m.types, c.m.nirm.types, n[0].typ)[1]:
         buildTyped target, info, FieldAt, t:
           copyTree target, a
           target.addImmediateVal info, 1 # (len, p)-pair
@@ -2337,10 +2336,18 @@ proc genArrAccess(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) =
 
 proc genObjAccess(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) =
   let info = toLineInfo(c, n.info)
-  let a = genx(c, n[0], flags)
+
+  var n0 = n[0]
+  var opc = FieldAt
+  if n0.kind == nkDotExpr:
+    # obj[].a --> DerefFieldAt instead of FieldAt:
+    n0 = n[0]
+    opc = DerefFieldAt
+
+  let a = genx(c, n0, flags)
 
   template body(target) =
-    buildTyped target, info, FieldAt, typeToIr(c.m, n[0].typ):
+    buildTyped target, info, opc, typeToIr(c.m, n0.typ):
       copyTree target, a
       genField c, n[1], Value(target)
 
@@ -2353,6 +2360,11 @@ proc genParams(c: var ProcCon; params: PNode; prc: PSym) =
     let res = resNode.sym # get result symbol
     c.code.addSummon toLineInfo(c, res.info), toSymId(c, res),
       typeToIr(c.m, res.typ), SummonResult
+  elif prc.typ.len > 0 and not isEmptyType(prc.typ[0]) and not isCompileTimeOnly(prc.typ[0]):
+    # happens for procs without bodies:
+    let t = typeToIr(c.m, prc.typ[0])
+    let tmp = allocTemp(c, t)
+    c.code.addSummon toLineInfo(c, params.info), tmp, t, SummonResult
 
   for i in 1..<params.len:
     let s = params[i].sym
diff --git a/compiler/nir/nir.nim b/compiler/nir/nir.nim
index 1efa6719a..6f7077fb0 100644
--- a/compiler/nir/nir.nim
+++ b/compiler/nir/nir.nim
@@ -57,6 +57,7 @@ proc evalStmt(c: PCtx; n: PNode) =
   #res.add "\n--------------------------\n"
   #toString res, c.m.types.g
   if pc.int < c.m.nirm.code.len:
+    c.bytecode.interactive = c.m.graph.interactive
     execCode c.bytecode, c.m.nirm.code, pc
   #echo res
 
diff --git a/compiler/nir/nirinsts.nim b/compiler/nir/nirinsts.nim
index 873004408..5c2901540 100644
--- a/compiler/nir/nirinsts.nim
+++ b/compiler/nir/nirinsts.nim
@@ -63,8 +63,10 @@ type
     Kill, # `Kill x`: scope end for `x`
 
     AddrOf,
-    ArrayAt, # addr(a[i])
-    FieldAt, # addr(obj.field)
+    ArrayAt, # a[i]
+    DerefArrayAt, # a[i] where `a` is a PtrArray; `a[][i]`
+    FieldAt, # obj.field
+    DerefFieldAt, # obj[].field
 
     Load, # a[]
     Store, # a[] = b
@@ -162,7 +164,9 @@ const
     AddrOf,
     Load,
     ArrayAt,
+    DerefArrayAt,
     FieldAt,
+    DerefFieldAt,
     TestOf
   }
 
@@ -240,6 +244,8 @@ proc next*(tree: Tree; pos: var NodePos) {.inline.} = nextChild tree, int(pos)
 
 template firstSon*(n: NodePos): NodePos = NodePos(n.int+1)
 
+template skipTyped*(n: NodePos): NodePos = NodePos(n.int+2)
+
 iterator sons*(tree: Tree; n: NodePos): NodePos =
   var pos = n.int
   assert tree.nodes[pos].kind > LastAtomicValue
@@ -259,6 +265,17 @@ iterator sonsFrom1*(tree: Tree; n: NodePos): NodePos =
     yield NodePos pos
     nextChild tree, pos
 
+iterator sonsFromN*(tree: Tree; n: NodePos; toSkip = 2): NodePos =
+  var pos = n.int
+  assert tree.nodes[pos].kind > LastAtomicValue
+  let last = pos + tree.nodes[pos].rawSpan
+  inc pos
+  for i in 1..toSkip:
+    nextChild tree, pos
+  while pos < last:
+    yield NodePos pos
+    nextChild tree, pos
+
 template `[]`*(t: Tree; n: NodePos): Instr = t.nodes[n.int]
 
 proc span(tree: Tree; pos: int): int {.inline.} =
@@ -327,9 +344,6 @@ proc addNewLabel*(t: var Tree; labelGen: var int; info: PackedLineInfo; k: Opcod
   t.nodes.add Instr(x: toX(k, uint32(result)), info: info)
   inc labelGen
 
-proc boolVal*(t: var Tree; info: PackedLineInfo; b: bool) =
-  t.nodes.add Instr(x: toX(ImmediateVal, uint32(b)), info: info)
-
 proc gotoLabel*(t: var Tree; info: PackedLineInfo; k: Opcode; L: LabelId) =
   assert k in {Goto, GotoLoop, CheckedGoto}
   t.nodes.add Instr(x: toX(k, uint32(L)), info: info)
@@ -367,6 +381,10 @@ proc addIntVal*(t: var Tree; integers: var BiTable[int64]; info: PackedLineInfo;
   buildTyped t, info, NumberConv, typ:
     t.nodes.add Instr(x: toX(IntVal, uint32(integers.getOrIncl(x))), info: info)
 
+proc boolVal*(t: var Tree; integers: var BiTable[int64]; info: PackedLineInfo; b: bool) =
+  buildTyped t, info, NumberConv, Bool8Id:
+    t.nodes.add Instr(x: toX(IntVal, uint32(integers.getOrIncl(ord b))), info: info)
+
 proc addStrVal*(t: var Tree; strings: var BiTable[string]; info: PackedLineInfo; s: string) =
   t.nodes.add Instr(x: toX(StrVal, uint32(strings.getOrIncl(s))), info: info)
 
diff --git a/compiler/nir/nirvm.nim b/compiler/nir/nirvm.nim
index 4b2c7e548..a3d69a296 100644
--- a/compiler/nir/nirvm.nim
+++ b/compiler/nir/nirvm.nim
@@ -48,7 +48,9 @@ type
 
     AddrOfM,
     ArrayAtM, # (elemSize, addr(a), i)
+    DerefArrayAtM,
     FieldAtM, # addr(obj.field)
+    DerefFieldAtM,
 
     LoadM, # a[]
     AsgnM,  # a = b
@@ -60,7 +62,6 @@ type
     CheckedIndexM,
 
     CallM,
-    CheckedCallM, # call that can raise
     CheckedAddM, # with overflow checking etc.
     CheckedSubM,
     CheckedMulM,
@@ -107,6 +108,14 @@ template toIns(k: OpcodeM; operand: uint32): Instr =
 template toIns(k: OpcodeM; operand: LitId): Instr =
   Instr(uint32(k) or (operand.uint32 shl OpcodeBits))
 
+type
+  NimStrPayloadVM = object
+    cap: int
+    data: UncheckedArray[char]
+  NimStringVM = object
+    len: int
+    p: ptr NimStrPayloadVM
+
 const
   GlobalsSize = 1024*24
 
@@ -119,7 +128,8 @@ type
     debug: seq[PackedLineInfo]
     m: ref NirModule
     procs: Table[SymId, CodePos]
-    globals: Table[SymId, uint32]
+    globals: Table[SymId, (uint32, int)]
+    strings: Table[LitId, NimStringVM]
     globalData: pointer
     globalsAddr: uint32
     typeImpls: Table[string, TypeId]
@@ -127,6 +137,7 @@ type
     sizes: Table[TypeId, (int, int)] # (size, alignment)
     oldTypeLen: int
     procUsagesToPatch: Table[SymId, seq[CodePos]]
+    interactive*: bool
 
   Universe* = object ## all units: For interpretation we need that
     units: seq[Bytecode]
@@ -325,7 +336,7 @@ proc toString*(t: Bytecode; pos: CodePos;
     r.add $t.m.lit.numbers[LitId t[pos].operand]
   of StrValM:
     escapeToNimLit(t.m.lit.strings[LitId t[pos].operand], r)
-  of LoadLocalM, LoadGlobalM, LoadProcM, AllocLocals:
+  of LoadLocalM, LoadGlobalM, LoadProcM, AllocLocals, SummonParamM:
     r.add $t[pos].kind
     r.add ' '
     r.add $t[pos].operand
@@ -361,7 +372,7 @@ type
     u: ref Universe
     known: Table[LabelId, CodePos]
     toPatch: Table[LabelId, seq[CodePos]]
-    locals: Table[SymId, uint32]
+    locals: Table[SymId, (uint32, int)] # address, size
     thisModule: uint32
     localsAddr: uint32
     markedWithLabel: IntSet
@@ -382,15 +393,23 @@ type
   AddrMode = enum
     InDotExpr, WantAddr
 
-template maybeDeref(doDeref: bool; body: untyped) =
+template maybeDeref(doDeref: bool; size: int; body: untyped) =
   var pos = PatchPos(-1)
   if doDeref:
     pos = prepare(bc, info, LoadM)
-    bc.add info, TypedM, 0'u32
+    bc.add info, ImmediateValM, uint32 size
   body
   if doDeref:
     patch(bc, pos)
 
+proc toReadonlyString(s: string): NimStringVM =
+  if s.len == 0:
+    result = NimStringVM(len: 0, p: nil)
+  else:
+    result = NimStringVM(len: s.len, p: cast[ptr NimStrPayloadVM](alloc(s.len+1+sizeof(int))))
+    copyMem(addr result.p.data[0], addr s[0], s.len+1)
+    result.p.cap = s.len or (1 shl (8 * 8 - 2)) # see also NIM_STRLIT_FLAG
+
 const
   ForwardedProc = 10_000_000'u32
 
@@ -409,19 +428,24 @@ proc preprocess(c: var Preprocessing; bc: var Bytecode; t: Tree; n: NodePos; fla
   of IntVal:
     bc.add info, IntValM, t[n].rawOperand
   of StrVal:
+    let litId = LitId t[n].rawOperand
+    if not bc.strings.hasKey(litId):
+      bc.strings[litId] = toReadonlyString(bc.m.lit.strings[litId])
     bc.add info, StrValM, t[n].rawOperand
   of SymDef:
     discard "happens for proc decls. Don't copy the node as we don't need it"
   of SymUse:
     let s = t[n].symId
     if c.locals.hasKey(s):
-      maybeDeref(WantAddr notin flags):
-        bc.add info, LoadLocalM, c.locals[s]
+      let (address, size) = c.locals[s]
+      maybeDeref(WantAddr notin flags, size):
+        bc.add info, LoadLocalM, address
     elif bc.procs.hasKey(s):
       bc.add info, LoadProcM, uint32 bc.procs[s]
     elif bc.globals.hasKey(s):
-      maybeDeref(WantAddr notin flags):
-        bc.add info, LoadGlobalM, uint32 s
+      let (address, size) = bc.globals[s]
+      maybeDeref(WantAddr notin flags, size):
+        bc.add info, LoadGlobalM, address
     else:
       let here = CodePos(bc.code.len)
       bc.add info, LoadProcM, ForwardedProc + uint32(s)
@@ -452,7 +476,7 @@ proc preprocess(c: var Preprocessing; bc: var Bytecode; t: Tree; n: NodePos; fla
     bc.add info, NilValM, t[n].rawOperand
   of LoopLabel, Label:
     let lab = t[n].label
-    let here = CodePos(bc.code.len-1)
+    let here = CodePos(bc.code.len)
     c.known[lab] = here
     var p: seq[CodePos] = @[]
     if c.toPatch.take(lab, p):
@@ -506,7 +530,7 @@ proc preprocess(c: var Preprocessing; bc: var Bytecode; t: Tree; n: NodePos; fla
     let (size, alignment) = computeSize(bc, tid)
 
     let global = align(bc.globalsAddr, uint32 alignment)
-    bc.globals[s] = global
+    bc.globals[s] = (global, size)
     bc.globalsAddr += uint32 size
     assert bc.globalsAddr < GlobalsSize
 
@@ -518,7 +542,7 @@ proc preprocess(c: var Preprocessing; bc: var Bytecode; t: Tree; n: NodePos; fla
     let (size, alignment) = computeSize(bc, tid)
 
     let local = align(c.localsAddr, uint32 alignment)
-    c.locals[s] = local
+    c.locals[s] = (local, size)
     c.localsAddr += uint32 size
     # allocation is combined into the frame allocation so there is no
     # instruction to emit
@@ -530,7 +554,7 @@ proc preprocess(c: var Preprocessing; bc: var Bytecode; t: Tree; n: NodePos; fla
     let (size, alignment) = computeSize(bc, tid)
 
     let local = align(c.localsAddr, uint32 alignment)
-    c.locals[s] = local
+    c.locals[s] = (local, size)
     c.localsAddr += uint32 size
     bc.add info, SummonParamM, local
     bc.add info, ImmediateValM, uint32 size
@@ -545,39 +569,30 @@ proc preprocess(c: var Preprocessing; bc: var Bytecode; t: Tree; n: NodePos; fla
     let (arrayType, a, i) = sons3(t, n)
     let tid = t[arrayType].typeId
     let size = uint32 computeElemSize(bc, tid)
-    if t[a].kind == Load:
-      let (_, arg) = sons2(t, a)
-      build bc, info, LoadM:
-        bc.add info, ImmediateValM, size
-        build bc, info, ArrayAtM:
-          bc.add info, ImmediateValM, size
-          preprocess(c, bc, t, arg, {WantAddr})
-          preprocess(c, bc, t, i, {WantAddr})
-    else:
-      build bc, info, ArrayAtM:
-        bc.add info, ImmediateValM, size
-        preprocess(c, bc, t, a, {WantAddr})
-        preprocess(c, bc, t, i, {WantAddr})
+    build bc, info, ArrayAtM:
+      bc.add info, ImmediateValM, size
+      preprocess(c, bc, t, a, {WantAddr})
+      preprocess(c, bc, t, i, {WantAddr})
+  of DerefArrayAt:
+    let (arrayType, a, i) = sons3(t, n)
+    let tid = t[arrayType].typeId
+    let size = uint32 computeElemSize(bc, tid)
+    build bc, info, DerefArrayAtM:
+      bc.add info, ImmediateValM, size
+      preprocess(c, bc, t, a, {WantAddr})
+      preprocess(c, bc, t, i, {WantAddr})
   of FieldAt:
-    # a[] conceptually loads a block of size of T. But when applied to an object selector
-    # only a subset of the data is really requested so `(a[] : T).field`
-    # becomes `(a+offset(field))[] : T_Field`
-    # And now if this is paired with `addr` the deref disappears, as usual: `addr x.field[]`
-    # is `(x+offset(field))`.
     let (typ, a, b) = sons3(t, n)
-    if t[a].kind == Load:
-      let (_, arg) = sons2(t, a)
-      build bc, info, LoadM:
-        bc.add info, ImmediateValM, uint32 computeSize(bc, t[typ].typeId)[0]
-        let offset = bc.offsets[t[typ].typeId][t[b].immediateVal][0]
-        build bc, info, FieldAtM:
-          preprocess(c, bc, t, arg, flags+{WantAddr})
-          bc.add info, ImmediateValM, uint32(offset)
-    else:
-      let offset = bc.offsets[t[typ].typeId][t[b].immediateVal][0]
-      build bc, info, FieldAtM:
-        preprocess(c, bc, t, a, flags+{WantAddr})
-        bc.add info, ImmediateValM, uint32(offset)
+    let offset = bc.offsets[t[typ].typeId][t[b].immediateVal][0]
+    build bc, info, FieldAtM:
+      preprocess(c, bc, t, a, flags+{WantAddr})
+      bc.add info, ImmediateValM, uint32(offset)
+  of DerefFieldAt:
+    let (typ, a, b) = sons3(t, n)
+    let offset = bc.offsets[t[typ].typeId][t[b].immediateVal][0]
+    build bc, info, DerefFieldAtM:
+      preprocess(c, bc, t, a, flags+{WantAddr})
+      bc.add info, ImmediateValM, uint32(offset)
   of Load:
     let (elemType, a) = sons2(t, n)
     let tid = t[elemType].typeId
@@ -593,14 +608,16 @@ proc preprocess(c: var Preprocessing; bc: var Bytecode; t: Tree; n: NodePos; fla
     if t[src].kind in {Call, IndirectCall}:
       # No support for return values, these are mapped to `var T` parameters!
       build bc, info, CallM:
-        preprocess(c, bc, t, src.firstSon, {WantAddr})
+        preprocess(c, bc, t, src.skipTyped, {WantAddr})
         preprocess(c, bc, t, dest, {WantAddr})
-        for ch in sonsFrom1(t, src): preprocess(c, bc, t, ch, {WantAddr})
+        for ch in sonsFromN(t, src, 2): preprocess(c, bc, t, ch, {WantAddr})
     elif t[src].kind in {CheckedCall, CheckedIndirectCall}:
-      build bc, info, CheckedCallM:
-        preprocess(c, bc, t, src.firstSon, {WantAddr})
+      let (_, gotoInstr, fn) = sons3(t, src)
+      build bc, info, CallM:
+        preprocess(c, bc, t, fn, {WantAddr})
         preprocess(c, bc, t, dest, {WantAddr})
-        for ch in sonsFrom1(t, src): preprocess(c, bc, t, ch, {WantAddr})
+        for ch in sonsFromN(t, src, 3): preprocess(c, bc, t, ch, {WantAddr})
+      preprocess c, bc, t, gotoInstr, {}
     elif t[dest].kind == Load:
       let (typ, a) = sons2(t, dest)
       let s = computeSize(bc, tid)[0]
@@ -628,8 +645,11 @@ proc preprocess(c: var Preprocessing; bc: var Bytecode; t: Tree; n: NodePos; fla
       for ch in sonsFrom1(t, n): preprocess(c, bc, t, ch, {WantAddr})
   of CheckedCall, CheckedIndirectCall:
     # avoid the Typed thing at position 0:
-    build bc, info, CheckedCallM:
-      for ch in sonsFrom1(t, n): preprocess(c, bc, t, ch, {WantAddr})
+    let (_, gotoInstr, fn) = sons3(t, n)
+    build bc, info, CallM:
+      preprocess(c, bc, t, fn, {WantAddr})
+      for ch in sonsFromN(t, n, 3): preprocess(c, bc, t, ch, {WantAddr})
+    preprocess c, bc, t, gotoInstr, {WantAddr}
   of CheckedAdd:
     recurse CheckedAddM
   of CheckedSub:
@@ -696,7 +716,7 @@ proc preprocess(c: var Preprocessing; bc: var Bytecode; t: Tree; n: NodePos; fla
       for ch in sons(t, n): preprocess(c2, bc, t, ch, {})
       bc.code[toPatch] = toIns(AllocLocals, c2.localsAddr)
     when false:
-      if here.int == 40192:
+      if here.int == 39850:
         debug bc, t, n
         debug bc, here
 
@@ -776,6 +796,10 @@ proc evalAddr(c: Bytecode; pc: CodePos; s: StackFrame): pointer =
     let (x, offset) = sons2(c.code, pc)
     result = evalAddr(c, x, s)
     result = result +! c.code[offset].operand
+  of DerefFieldAtM:
+    let (x, offset) = sons2(c.code, pc)
+    let p = evalAddr(c, x, s)
+    result = cast[ptr pointer](p)[] +! c.code[offset].operand
   of ArrayAtM:
     let (e, a, i) = sons3(c.code, pc)
     let elemSize = c.code[e].operand
@@ -783,10 +807,13 @@ proc evalAddr(c: Bytecode; pc: CodePos; s: StackFrame): pointer =
     var idx: int = 0
     eval(c, i, s, addr idx, sizeof(int))
     result = result +! (uint32(idx) * elemSize)
-  of LoadM:
-    let (_, arg) = sons2(c.code, pc)
-    let p = evalAddr(c, arg, s)
-    result = cast[ptr pointer](p)[]
+  of DerefArrayAtM:
+    let (e, a, i) = sons3(c.code, pc)
+    let elemSize = c.code[e].operand
+    var p = evalAddr(c, a, s)
+    var idx: int = 0
+    eval(c, i, s, addr idx, sizeof(int))
+    result = cast[ptr pointer](p)[] +! (uint32(idx) * elemSize)
   of LoadGlobalM:
     result = c.globalData +! c.code[pc].operand
   else:
@@ -897,23 +924,29 @@ proc evalSelect(c: Bytecode; pc: CodePos; s: StackFrame): CodePos =
     for pair in sonsFrom2(c, pc):
       assert c.code[pair].kind == SelectPairM
       let (values, action) = sons2(c.code, pair)
-      assert c.code[values].kind == SelectListM
-      for v in sons(c, values):
-        case c.code[v].kind
-        of SelectValueM:
-          var a = default(typ)
-          eval c, v.firstSon, s, addr a, sizeof(typ)
-          if selector == a:
-            return CodePos c.code[action].operand
-        of SelectRangeM:
-          let (va, vb) = sons2(c.code, v)
-          var a = default(typ)
-          eval c, va, s, addr a, sizeof(typ)
-          var b = default(typ)
-          eval c, vb, s, addr a, sizeof(typ)
-          if a <= selector and selector <= b:
-            return CodePos c.code[action].operand
-        else: raiseAssert "unreachable"
+      if c.code[values].kind == SelectValueM:
+        var a = default(typ)
+        eval c, values.firstSon, s, addr a, sizeof(typ)
+        if selector == a:
+          return CodePos c.code[action].operand
+      else:
+        assert c.code[values].kind == SelectListM, $c.code[values].kind
+        for v in sons(c, values):
+          case c.code[v].kind
+          of SelectValueM:
+            var a = default(typ)
+            eval c, v.firstSon, s, addr a, sizeof(typ)
+            if selector == a:
+              return CodePos c.code[action].operand
+          of SelectRangeM:
+            let (va, vb) = sons2(c.code, v)
+            var a = default(typ)
+            eval c, va, s, addr a, sizeof(typ)
+            var b = default(typ)
+            eval c, vb, s, addr a, sizeof(typ)
+            if a <= selector and selector <= b:
+              return CodePos c.code[action].operand
+          else: raiseAssert "unreachable"
     result = CodePos(-1)
 
   let (t, sel) = sons2(c.code, pc)
@@ -932,11 +965,18 @@ proc evalSelect(c: Bytecode; pc: CodePos; s: StackFrame): CodePos =
 proc eval(c: Bytecode; pc: CodePos; s: StackFrame; result: pointer; size: int) =
   case c.code[pc].kind
   of LoadLocalM:
-    let dest = s.locals +! c.code[pc].operand
-    copyMem dest, result, size
-  of FieldAtM, ArrayAtM, LoadM:
-    let dest = evalAddr(c, pc, s)
-    copyMem dest, result, size
+    let src = s.locals +! c.code[pc].operand
+    copyMem result, src, size
+  of FieldAtM, DerefFieldAtM, ArrayAtM, DerefArrayAtM, LoadGlobalM:
+    let src = evalAddr(c, pc, s)
+    copyMem result, src, size
+  of LoadProcM:
+    let procAddr = c.code[pc].operand
+    cast[ptr pointer](result)[] = cast[pointer](procAddr)
+  of LoadM:
+    let (_, arg) = sons2(c.code, pc)
+    let src = evalAddr(c, arg, s)
+    copyMem result, src, size
   of CheckedAddM: checkedBinop `+`
   of CheckedSubM: checkedBinop `-`
   of CheckedMulM: checkedBinop `*`
@@ -958,8 +998,7 @@ proc eval(c: Bytecode; pc: CodePos; s: StackFrame; result: pointer; size: int) =
 
   of StrValM:
     # binary compatible and no deep copy required:
-    copyMem(cast[ptr string](result), addr(c.m.lit.strings[c[pc].litId]), sizeof(string))
-    # XXX not correct!
+    copyMem(cast[ptr string](result), addr(c.strings[c[pc].litId]), sizeof(string))
   of ObjConstrM:
     for offset, size, val in triples(c, pc):
       eval c, val, s, result+!offset, size
@@ -1013,31 +1052,41 @@ proc evalProc(c: Bytecode; pc: CodePos; s: StackFrame): CodePos =
   assert procSym < ForwardedProc
   result = CodePos(procSym)
 
-proc echoImpl(c: Bytecode; pc: CodePos; s: StackFrame) =
-  type StringArray = object
-    len: int
-    data: ptr UncheckedArray[string]
-  var sa = default(StringArray)
+proc echoImpl(c: Bytecode; pc: CodePos; frame: StackFrame) =
+  var s = default(NimStringVM)
   for a in sonsFrom1(c, pc):
-    eval(c, a, s, addr(sa), sizeof(sa))
-  for i in 0..<sa.len:
-    stdout.write sa.data[i]
+    assert c[a].kind == ArrayConstrM
+    let elemSize = c.code[a.firstSon].operand.int
+    for ch in sonsFrom1(c, a):
+      eval c, ch, frame, addr s, elemSize
+      if s.len > 0:
+        discard stdout.writeBuffer(addr(s.p.data[0]), s.len)
   stdout.write "\n"
   stdout.flushFile()
 
-proc evalBuiltin(c: Bytecode; pc: CodePos; s: StackFrame; prc: CodePos; didEval: var bool): CodePos =
+type
+  EvalBuiltinState = enum
+    DidNothing, DidEval, DidError
+
+proc evalBuiltin(c: Bytecode; pc: CodePos; s: StackFrame; prc: CodePos; state: var EvalBuiltinState): CodePos =
   var prc = prc
   while true:
     case c[prc].kind
     of PragmaPairM:
       let (x, y) = sons2(c.code, prc)
-      if cast[PragmaKey](c[x]) == CoreName:
+      let key = cast[PragmaKey](c[x].operand)
+      case key
+      of CoreName:
         let lit = c[y].litId
         case c.m.lit.strings[lit]
         of "echoBinSafe": echoImpl(c, pc, s)
-        else: discard
-        echo "running compilerproc: ", c.m.lit.strings[lit]
-        didEval = true
+        else:
+          raiseAssert "cannot eval: " & c.m.lit.strings[lit]
+        state = DidEval
+      of HeaderImport, DllImport:
+        let lit = c[y].litId
+        raiseAssert "cannot eval: " & c.m.lit.strings[lit]
+      else: discard
     of PragmaIdM, AllocLocals: discard
     else: break
     next c, prc
@@ -1045,52 +1094,63 @@ proc evalBuiltin(c: Bytecode; pc: CodePos; s: StackFrame; prc: CodePos; didEval:
 
 proc exec(c: Bytecode; pc: CodePos; u: ref Universe) =
   var pc = pc
-  var s = StackFrame(u: u)
+  var frame = StackFrame(u: u)
   while pc.int < c.code.len:
+    when false: # c.interactive:
+      echo "running: ", pc.int
+      debug c, pc
+
     case c.code[pc].kind
     of GotoM:
       pc = CodePos(c.code[pc].operand)
     of AsgnM:
       let (sz, a, b) = sons3(c.code, pc)
-      let dest = evalAddr(c, a, s)
-      eval(c, b, s, dest, c.code[sz].operand.int)
+      let dest = evalAddr(c, a, frame)
+      eval(c, b, frame, dest, c.code[sz].operand.int)
       next c, pc
     of StoreM:
       let (sz, a, b) = sons3(c.code, pc)
-      let destPtr = evalAddr(c, a, s)
+      let destPtr = evalAddr(c, a, frame)
       let dest = cast[ptr pointer](destPtr)[]
-      eval(c, b, s, dest, c.code[sz].operand.int)
+      eval(c, b, frame, dest, c.code[sz].operand.int)
       next c, pc
     of CallM:
       # No support for return values, these are mapped to `var T` parameters!
-      var prc = evalProc(c, pc.firstSon, s)
+      var prc = evalProc(c, pc.firstSon, frame)
       assert c.code[prc.firstSon].kind == AllocLocals
       let frameSize = int c.code[prc.firstSon].operand
       # skip stupid stuff:
-      var didEval = false
-      prc = evalBuiltin(c, pc, s, prc.firstSon, didEval)
-      if didEval:
+      var evalState = DidNothing
+      prc = evalBuiltin(c, pc, frame, prc.firstSon, evalState)
+      if evalState != DidNothing:
         next c, pc
+        if pc.int < c.code.len and c.code[pc].kind == CheckedGotoM:
+          if evalState == DidEval:
+            next c, pc
+          else:
+            pc = CodePos(c.code[pc].operand)
       else:
         # setup storage for the proc already:
         let callInstr = pc
         next c, pc
-        let s2 = newStackFrame(frameSize, s, pc)
+        let s2 = newStackFrame(frameSize, frame, pc)
         for a in sonsFrom1(c, callInstr):
           assert c[prc].kind == SummonParamM
           let paramAddr = c[prc].operand
           next c, prc
           assert c[prc].kind == ImmediateValM
           let paramSize = c[prc].operand.int
-          eval(c, a, s2, s2.locals +! paramAddr, paramSize)
           next c, prc
-        s = s2
+          eval(c, a, s2, s2.locals +! paramAddr, paramSize)
+        frame = s2
         pc = prc
     of RetM:
-      pc = s.returnAddr
-      s = popStackFrame(s)
+      pc = frame.returnAddr
+      if c.code[pc].kind == CheckedGotoM:
+        pc = frame.jumpTo
+      frame = popStackFrame(frame)
     of SelectM:
-      let pc2 = evalSelect(c, pc, s)
+      let pc2 = evalSelect(c, pc, frame)
       if pc2.int >= 0:
         pc = pc2
       else:
@@ -1107,8 +1167,9 @@ proc execCode*(bc: var Bytecode; t: Tree; n: NodePos) =
   let start = CodePos(bc.code.len)
   var pc = n
   while pc.int < t.len:
-    #echo "RUnning: "
-    #debug bc, t, pc
+    #if bc.interactive:
+    #  echo "RUnning: "
+    #  debug bc, t, pc
     preprocess c, bc, t, pc, {}
     next t, pc
   exec bc, start, nil
diff --git a/compiler/pipelines.nim b/compiler/pipelines.nim
index e4c484e1f..8f40ac031 100644
--- a/compiler/pipelines.nim
+++ b/compiler/pipelines.nim
@@ -148,9 +148,10 @@ proc processPipelineModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator
     if s == nil:
       rawMessage(graph.config, errCannotOpenFile, filename.string)
       return false
+    graph.interactive = false
   else:
     s = stream
-
+    graph.interactive = stream.kind == llsStdIn
   while true:
     syntaxes.openParser(p, fileIdx, s, graph.cache, graph.config)