summary refs log tree commit diff stats
path: root/compiler/vm.nim
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/vm.nim')
-rw-r--r--compiler/vm.nim92
1 files changed, 76 insertions, 16 deletions
diff --git a/compiler/vm.nim b/compiler/vm.nim
index 0d5386502..fb8749250 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -48,9 +48,17 @@ type
                               # XXX 'break' should perform cleanup actions
                               # What does the C backend do for it?
 
-proc stackTraceAux(c: PCtx; x: PStackFrame; pc: int) =
+proc stackTraceAux(c: PCtx; x: PStackFrame; pc: int; recursionLimit=100) =
   if x != nil:
-    stackTraceAux(c, x.next, x.comesFrom)
+    if recursionLimit == 0:
+      var calls = 0
+      var x = x
+      while x != nil:
+        inc calls
+        x = x.next
+      msgWriteln($calls & " calls omitted\n")
+      return
+    stackTraceAux(c, x.next, x.comesFrom, recursionLimit-1)
     var info = c.debug[pc]
     # we now use the same format as in system/except.nim
     var s = toFilename(info)
@@ -222,13 +230,14 @@ proc pushSafePoint(f: PStackFrame; pc: int) =
 
 proc popSafePoint(f: PStackFrame) = discard f.safePoints.pop()
 
-proc cleanUpOnException(c: PCtx; tos: PStackFrame; regs: seq[TFullReg]): int =
+proc cleanUpOnException(c: PCtx; tos: PStackFrame): 
+                                              tuple[pc: int, f: PStackFrame] =
   let raisedType = c.currentExceptionA.typ.skipTypes(abstractPtrs)
   var f = tos
   while true:
     while f.safePoints.isNil or f.safePoints.len == 0:
       f = f.next
-      if f.isNil: return -1
+      if f.isNil: return (-1, nil)
     var pc2 = f.safePoints[f.safePoints.high]
 
     var nextExceptOrFinally = -1
@@ -244,13 +253,13 @@ proc cleanUpOnException(c: PCtx; tos: PStackFrame; regs: seq[TFullReg]): int =
         c.currentExceptionB = c.currentExceptionA
         c.currentExceptionA = nil
         # execute the corresponding handler:
-        return pc2
+        return (pc2, f)
       inc pc2
     if nextExceptOrFinally >= 0:
       pc2 = nextExceptOrFinally
     if c.code[pc2].opcode == opcFinally:
       # execute the corresponding handler, but don't quit walking the stack:
-      return pc2
+      return (pc2, f)
     # not the right one:
     discard f.safePoints.pop
 
@@ -495,18 +504,46 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       else: stackTrace(c, tos, pc, errNilAccess)
     of opcAddInt:
       decodeBC(rkInt)
-      regs[ra].intVal = regs[rb].intVal + regs[rc].intVal
+      let
+        bVal = regs[rb].intVal
+        cVal = regs[rc].intVal
+        sum = bVal +% cVal
+      if (sum xor bVal) >= 0 or (sum xor cVal) >= 0:
+        regs[ra].intVal = sum
+      else:
+        stackTrace(c, tos, pc, errOverOrUnderflow)
     of opcAddImmInt:
       decodeBImm(rkInt)
       #message(c.debug[pc], warnUser, "came here")
       #debug regs[rb].node
-      regs[ra].intVal = regs[rb].intVal + imm
+      let
+        bVal = regs[rb].intVal
+        cVal = imm
+        sum = bVal +% cVal
+      if (sum xor bVal) >= 0 or (sum xor cVal) >= 0:
+        regs[ra].intVal = sum
+      else:
+        stackTrace(c, tos, pc, errOverOrUnderflow)
     of opcSubInt:
       decodeBC(rkInt)
-      regs[ra].intVal = regs[rb].intVal - regs[rc].intVal
+      let
+        bVal = regs[rb].intVal
+        cVal = regs[rc].intVal
+        diff = bVal -% cVal
+      if (diff xor bVal) >= 0 or (diff xor not cVal) >= 0:
+        regs[ra].intVal = diff
+      else:
+        stackTrace(c, tos, pc, errOverOrUnderflow)
     of opcSubImmInt:
       decodeBImm(rkInt)
-      regs[ra].intVal = regs[rb].intVal - imm
+      let
+        bVal = regs[rb].intVal
+        cVal = imm
+        diff = bVal -% cVal
+      if (diff xor bVal) >= 0 or (diff xor not cVal) >= 0:
+        regs[ra].intVal = diff
+      else:
+        stackTrace(c, tos, pc, errOverOrUnderflow)
     of opcLenSeq:
       decodeBImm(rkInt)
       #assert regs[rb].kind == nkBracket
@@ -539,7 +576,18 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       regs[ra].intVal = nimsets.cardSet(regs[rb].node)
     of opcMulInt:
       decodeBC(rkInt)
-      regs[ra].intVal = regs[rb].intVal * regs[rc].intVal
+      let
+        bVal = regs[rb].intVal
+        cVal = regs[rc].intVal
+        product = bVal *% cVal
+        floatProd = toBiggestFloat(bVal) * toBiggestFloat(cVal)
+        resAsFloat = toBiggestFloat(product)
+      if resAsFloat == floatProd:
+        regs[ra].intVal = product
+      elif 32.0 * abs(resAsFloat - floatProd) <= abs(floatProd):
+        regs[ra].intVal = product
+      else:
+        stackTrace(c, tos, pc, errOverOrUnderflow)
     of opcDivInt:
       decodeBC(rkInt)
       if regs[rc].intVal == 0: stackTrace(c, tos, pc, errConstantDivisionByZero)
@@ -632,7 +680,11 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
     of opcUnaryMinusInt:
       decodeB(rkInt)
       assert regs[rb].kind == rkInt
-      regs[ra].intVal = -regs[rb].intVal
+      let val = regs[rb].intVal
+      if val != int64.low:
+        regs[ra].intVal = -val
+      else:
+        stackTrace(c, tos, pc, errOverOrUnderflow)
     of opcUnaryMinusFloat:
       decodeB(rkFloat)
       assert regs[rb].kind == rkFloat
@@ -826,19 +878,27 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
     of opcFinallyEnd:
       if c.currentExceptionA != nil:
         # we are in a cleanup run:
-        pc = cleanUpOnException(c, tos, regs)-1
-        if pc < 0: 
+        let (newPc, newTos) = cleanUpOnException(c, tos)
+        if newPc-1 < 0:
           bailOut(c, tos)
           return
+        pc = newPc-1
+        if tos != newTos:
+          tos = newTos
+          move(regs, tos.slots)
     of opcRaise:
       let raised = regs[ra].node
       c.currentExceptionA = raised
       c.exceptionInstr = pc
+      let (newPc, newTos) = cleanUpOnException(c, tos)
       # -1 because of the following 'inc'
-      pc = cleanUpOnException(c, tos, regs) - 1
-      if pc < 0:
+      if pc-1 < 0:
         bailOut(c, tos)
         return
+      pc = newPc -1
+      if tos != newTos:
+        tos = newTos
+        move(regs, tos.slots)
     of opcNew:
       ensureKind(rkNode)
       let typ = c.types[instr.regBx - wordExcess]