summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2013-08-07 01:40:08 +0200
committerAraq <rumpf_a@web.de>2013-08-07 01:40:08 +0200
commitaefa0da8a612df3bb363435dd78ed641b239c0c8 (patch)
treef51f7e8a3c4711b75280eb8e290ac2906c3032f6
parentee9aee6c0082e990d6b7355730704bdf6c70288c (diff)
downloadNim-aefa0da8a612df3bb363435dd78ed641b239c0c8.tar.gz
new VM: implemented constructors and jump optimizer
-rw-r--r--compiler/semfold.nim2
-rw-r--r--compiler/vm.nim41
-rw-r--r--compiler/vmdef.nim6
-rw-r--r--compiler/vmdeps.nim31
-rw-r--r--compiler/vmgen.nim125
-rw-r--r--lib/impure/zipfiles.nim2
-rw-r--r--todo.txt4
7 files changed, 187 insertions, 24 deletions
diff --git a/compiler/semfold.nim b/compiler/semfold.nim
index c9d2575cb..77ecf2e97 100644
--- a/compiler/semfold.nim
+++ b/compiler/semfold.nim
@@ -51,7 +51,7 @@ proc newStrNodeT(strVal: string, n: PNode): PNode =
   result.typ = n.typ
   result.info = n.info
 
-proc ordinalValToString(a: PNode): string = 
+proc ordinalValToString*(a: PNode): string = 
   # because $ has the param ordinal[T], `a` is not necessarily an enum, but an
   # ordinal
   var x = getInt(a)
diff --git a/compiler/vm.nim b/compiler/vm.nim
index 7929774ee..86d1fbe07 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -12,7 +12,7 @@
 
 import
   strutils, ast, astalgo, msgs, vmdef, vmgen, nimsets, types, passes, unsigned,
-  parser, vmdeps
+  parser, vmdeps, idents
 
 from semfold import leValueConv
 
@@ -87,12 +87,6 @@ template decodeBx(k: expr) {.immediate, dirty.} =
   let rbx = instr.regBx - wordExcess
   ensureKind(k)
 
-proc myreset(n: PNode) =
-  when defined(system.reset): 
-    var oldInfo = n.info
-    reset(n[])
-    n.info = oldInfo
-
 template move(a, b: expr) = system.shallowCopy(a, b)
 # XXX fix minor 'shallowCopy' overloading bug in compiler
 
@@ -666,7 +660,38 @@ proc execute(c: PCtx, start: int) =
     of opcNLineInfo:
       let rb = instr.regB
       let n = regs[rb]
-      regs[ra] = newStrNodeT(n.info.toFileLineCol, n)
+      regs[ra] = newStrNode(nkStrLit, n.info.toFileLineCol)
+      regs[ra].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)
+      else:
+        regs[ra].intVal = 0
+    of opcStrToIdent:
+      let rb = instr.regB
+      if regs[rb].kind notin {nkStrLit..nkTripleStrLit}:
+        stackTrace(c, tos, pc, errFieldXNotFound, "strVal")
+      else:
+        regs[ra] = newNodeI(nkIdent, c.debug[pc])
+        regs[ra].ident = getIdent(regs[rb].strVal)
+    of opcIdentToStr:
+      let rb = instr.regB
+      let a = regs[rb]
+      regs[ra] = newNodeI(nkStrLit, c.debug[pc])
+      if a.kind == nkSym:
+        regs[ra].strVal = a.sym.name.s
+      elif a.kind == nkIdent:
+        regs[ra].strVal = a.ident.s
+      else:
+        stackTrace(c, tos, pc, errFieldXNotFound, "ident")
+    of opcSetType:
+      regs[ra].typ = c.types[instr.regBx - wordExcess]
+    of opcConv:
+      let rb = instr.regB
+      inc pc
+      let typ = c.types[c.code[pc].regBx - wordExcess]
+      opConv(regs[ra], regs[rb], typ)
     else:
       InternalError(c.debug[pc], "unknown opcode " & $instr.opcode)
     inc pc
diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim
index 1a19efe5a..90d23e642 100644
--- a/compiler/vmdef.nim
+++ b/compiler/vmdef.nim
@@ -86,6 +86,9 @@ type
     opcNWarning,
     opcNHint,
     opcNLineInfo,
+    opcEqIdent,
+    opcStrToIdent,
+    opcIdentToStr,
     
     opcEcho,
     opcIndCall, # dest = call regStart, n; where regStart = fn, arg1, ...
@@ -114,7 +117,8 @@ type
     opcLdGlobal,  # dest = globals[Bx]
     opcLdImmInt,  # dest = immediate value
     opcWrGlobal,
-    opcWrGlobalRef
+    opcWrGlobalRef,
+    opcSetType    # dest.typ = types[Bx]
 
   TBlock* = object
     label*: PSym
diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim
index 2a9929de0..7a645aca9 100644
--- a/compiler/vmdeps.nim
+++ b/compiler/vmdeps.nim
@@ -7,7 +7,7 @@
 #    distribution, for details about the copyright.
 #
 
-import ast, msgs, osproc, streams, options
+import ast, types, msgs, osproc, streams, options, semfold
 
 proc readOutput(p: PProcess): string =
   result = ""
@@ -35,6 +35,35 @@ proc opSlurp*(file: string, info: TLineInfo, module: PSym): string =
     result = ""
     LocalError(info, errCannotOpenFile, file)
 
+proc myreset*(n: PNode) =
+  when defined(system.reset): 
+    var oldInfo = n.info
+    reset(n[])
+    n.info = oldInfo
+
+proc opConv*(dest, src: PNode, typ: PType) =
+  if typ.kind == tyString:
+    if dest.kind != nkStrLit:
+      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
+    of tyBool:
+      dest.strVal = if src.intVal == 0: "false" else: "true"
+    of tyFloat..tyFloat128:
+      dest.strVal = $src.floatVal
+    of tyString, tyCString:
+      dest.strVal = src.strVal
+    of tyChar:
+      dest.strVal = $chr(src.intVal)
+    else:
+      internalError("cannot convert to string " & typ.typeToString)
+  else:
+    discard
+
 when false:
   proc opExpandToAst*(c: PEvalContext, original: PNode): PNode =
     var
diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim
index c5bfa3095..2033fb23c 100644
--- a/compiler/vmgen.nim
+++ b/compiler/vmgen.nim
@@ -11,7 +11,7 @@
 
 import
   unsigned, strutils, ast, astalgo, types, msgs, renderer, vmdef, 
-  trees, intsets, rodread
+  trees, intsets, rodread, magicsys
 
 proc codeListing(c: PCtx, result: var string) =
   # first iteration: compute all necessary labels:
@@ -456,12 +456,12 @@ proc genAddSubInt(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
 proc unused(n: PNode; x: TDest) {.inline.} =
   if x >= 0: InternalError(n.info, "not unused")
 
-proc genConv(c: PCtx; n, arg: PNode; dest: var TDest; opc=opcConv) =
+proc genConv(c: PCtx; n, arg: PNode; dest: var TDest; opc=opcConv) =  
   let tmp = c.genx(arg)
-  let t = genType(c, n.typ)
+  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, t)
+  c.gABx(n, opc, 0, genType(c, n.typ))
   c.freeTemp(tmp)
 
 proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
@@ -685,11 +685,11 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
   of mNCopyNimNode: InternalError(n.info, "cannot generate code for: " & $m)
   of mNCopyNimTree: InternalError(n.info, "cannot generate code for: " & $m)
   of mNBindSym: genUnaryABC(c, n, dest, opcNBindSym)
-  of mStrToIdent: InternalError(n.info, "cannot generate code for: " & $m)
-  of mIdentToStr: InternalError(n.info, "cannot generate code for: " & $m)
-  of mEqIdent: InternalError(n.info, "cannot generate code for: " & $m)
-  of mEqNimrodNode: InternalError(n.info, "cannot generate code for: " & $m)
-  of mNLineInfo: InternalError(n.info, "cannot generate code for: " & $m)
+  of mStrToIdent: genUnaryABC(c, n, dest, opcStrToIdent)
+  of mIdentToStr: genUnaryABC(c, n, dest, opcIdentToStr)
+  of mEqIdent: genBinaryABC(c, n, dest, opcEqIdent)
+  of mEqNimrodNode: genBinaryABC(c, n, dest, opcEqRef)
+  of mNLineInfo: genUnaryABC(c, n, dest, opcNLineInfo)
   of mNHint: 
     unused(n, dest)
     genUnaryStmt(c, n, opcNHint)
@@ -946,6 +946,63 @@ proc genVarSection(c: PCtx; n: PNode) =
       else:
         genAsgn(c, a.sons[0], a.sons[2], true)
 
+proc genArrayConstr(c: PCtx, n: PNode, dest: var TDest) =
+  if dest < 0: dest = c.getTemp(n.typ)
+  c.gABx(n, opcLdNull, dest, c.genType(n.typ))
+  let intType = getSysType(tyInt)
+  var tmp = getTemp(c, intType)
+  c.gABx(n, opcLdNull, tmp, c.genType(intType))
+  for x in n:
+    let a = c.genx(x)
+    c.gABC(n, opcWrArr, dest, a, tmp)
+    c.gABI(n, opcAddImmInt, tmp, tmp, 1)
+    c.freeTemp(a)
+  c.freeTemp(tmp)
+
+proc genSetConstr(c: PCtx, n: PNode, dest: var TDest) =
+  if dest < 0: dest = c.getTemp(n.typ)
+  c.gABx(n, opcLdNull, dest, c.genType(n.typ))
+  for x in n:
+    let a = c.genx(x)
+    c.gABC(n, opcIncl, dest, a)
+    c.freeTemp(a)
+
+proc genObjConstr(c: PCtx, n: PNode, dest: var TDest) =
+  if dest < 0: dest = c.getTemp(n.typ)
+  let t = n.typ.skipTypes(abstractRange)
+  if t.kind == tyRef:
+    c.gABx(n, opcNew, dest, c.genType(t.sons[0]))
+  else:
+    c.gABx(n, opcLdNull, dest, c.genType(n.typ))
+  for i in 1.. <n.len:
+    let it = n.sons[i]
+    if it.kind == nkExprColonExpr and it.sons[0].kind == nkSym:
+      let idx = c.genx(it.sons[0])
+      let tmp = c.genx(it.sons[1])
+      c.gABC(it, whichAsgnOpc(it.sons[1], opcWrObj), dest, idx, tmp)
+      c.freeTemp(tmp)
+      c.freeTemp(idx)
+    else:
+      internalError(n.info, "invalid object constructor")
+
+proc genTupleConstr(c: PCtx, n: PNode, dest: var TDest) =
+  if dest < 0: dest = c.getTemp(n.typ)
+  var idx = getTemp(c, getSysType(tyInt))
+  for i in 0.. <n.len:
+    let it = n.sons[i]
+    if it.kind == nkExprColonExpr:
+      let idx = c.genx(it.sons[0])
+      let tmp = c.genx(it.sons[1])
+      c.gABC(it, whichAsgnOpc(it.sons[1], opcWrObj), dest, idx, tmp)
+      c.freeTemp(tmp)
+      c.freeTemp(idx)
+    else:
+      let tmp = c.genx(it)
+      c.gABx(it, opcLdImmInt, idx, i)
+      c.gABC(it, whichAsgnOpc(it, opcWrObj), dest, idx, tmp)
+      c.freeTemp(tmp)
+  c.freeTemp(idx)
+
 proc genProc*(c: PCtx; s: PSym): int
 
 proc gen(c: PCtx; n: PNode; dest: var TDest) =
@@ -1048,8 +1105,11 @@ proc gen(c: PCtx; n: PNode; dest: var TDest) =
     unused(n, dest)
   of nkStringToCString, nkCStringToString:
     gen(c, n.sons[0], dest)
+  of nkBracket: genArrayConstr(c, n, dest)
+  of nkCurly: genSetConstr(c, n, dest)
+  of nkObjConstr: genObjConstr(c, n, dest)
+  of nkPar, nkClosure: genTupleConstr(c, n, dest)
   else:
-    #of nkCurly, nkBracket, nkPar:
     InternalError n.info, "too implement " & $n.kind
 
 proc removeLastEof(c: PCtx) =
@@ -1076,6 +1136,51 @@ proc genParams(c: PCtx; params: PNode) =
     c.prc.slots[i] = (inUse: true, kind: slotFixedLet)
   c.prc.maxSlots = max(params.len, 1)
 
+proc finalJumpTarget(c: PCtx; pc, diff: int) =
+  InternalAssert(-0x7fff < diff and diff < 0x7fff)
+  let oldInstr = c.code[pc]
+  # opcode and regA stay the same:
+  c.code[pc] = ((oldInstr.uint32 and 0xffff'u32).uint32 or
+                uint32(diff+wordExcess) shl 16'u32).TInstr
+
+proc optimizeJumps(c: PCtx; start: int) =
+  const maxIterations = 10
+  for i in start .. <c.code.len:
+    let opc = c.code[i].opcode
+    case opc
+    of opcTJmp, opcFJmp:
+      var reg = c.code[i].regA
+      var d = i + c.code[i].regBx
+      var iters = maxIterations
+      while iters > 0:
+        case c.code[d].opcode
+        of opcJmp:
+          d = d + c.code[d].regBx
+        of opcTJmp, opcFJmp:
+          if c.code[d].regA != reg: break
+          # tjmp x, 23
+          # ...
+          # tjmp x, 12
+          # -- we know 'x' is true, and so can jump to 12+13:
+          if c.code[d].opcode == opc:
+            d = d + c.code[d].regBx
+          else:
+            # tjmp x, 23
+            # fjmp x, 22
+            # We know 'x' is true so skip to the next instruction:
+            d = d + 1
+        else: break
+        dec iters
+      c.finalJumpTarget(i, d - i)
+    of opcJmp:
+      var d = i + c.code[i].regBx
+      var iters = maxIterations
+      while c.code[d].opcode == opcJmp and iters > 0:
+        d = d + c.code[d].regBx
+        dec iters
+      c.finalJumpTarget(i, d - i)
+    else: discard
+
 proc genProc(c: PCtx; s: PSym): int =
   let x = s.ast.sons[optimizedCodePos]
   if x.kind == nkEmpty:
diff --git a/lib/impure/zipfiles.nim b/lib/impure/zipfiles.nim
index 029d8527d..de73b500d 100644
--- a/lib/impure/zipfiles.nim
+++ b/lib/impure/zipfiles.nim
@@ -30,7 +30,7 @@ proc open*(z: var TZipArchive, filename: string, mode: TFileMode = fmRead): bool
   var err, flags: int32
   case mode
   of fmRead, fmReadWriteExisting, fmAppend: flags = 0
-  of fmWrite:                               
+  of fmWrite:
     if existsFile(filename): removeFile(filename)
     flags = ZIP_CREATE or ZIP_EXCL
   of fmReadWrite: flags = ZIP_CREATE
diff --git a/todo.txt b/todo.txt
index 5b6cca2bb..dff9b5770 100644
--- a/todo.txt
+++ b/todo.txt
@@ -4,10 +4,9 @@ version 0.9.4
 - new VM:
   - implement opcConv
   - implement missing magics
-  - implement constructors
+  - implement overflow checking
   - implement the glue to replace evals.nim
   - implement on the fly CSE
-  - implement a jump optimizer
 
 - make 'bind' default for templates and introduce 'mixin'
 - special rule for ``[]=``
@@ -17,6 +16,7 @@ version 0.9.4
   - overloading of ``.``? Special case ``.=``?
 - built-in 'getImpl'
 - optimize 'genericReset'; 'newException' leads to code bloat
+- stack-less GC
 
 
 Bugs