diff options
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/vm.nim | 21 | ||||
-rw-r--r-- | compiler/vmdef.nim | 7 | ||||
-rw-r--r-- | compiler/vmgen.nim | 14 |
3 files changed, 33 insertions, 9 deletions
diff --git a/compiler/vm.nim b/compiler/vm.nim index 70eb6f828..f8b32bac1 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -68,7 +68,9 @@ proc stackTrace(c: PCtx, tos: PStackFrame, pc: int, msg: TMsgKind, arg = "") = msgWriteln("stack trace: (most recent call last)") stackTraceAux(c, tos, pc) - localError(c.debug[pc], msg, arg) + # XXX test if we want 'globalError' for every mode + if c.mode == emRepl: globalError(c.debug[pc], msg, arg) + else: localError(c.debug[pc], msg, arg) proc bailOut(c: PCtx; tos: PStackFrame) = stackTrace(c, tos, c.exceptionInstr, errUnhandledExceptionX, @@ -333,6 +335,16 @@ proc compile(c: PCtx, s: PSym): int = when debugEchoCode: c.echoCode result #c.echoCode +template handleJmpBack() {.dirty.} = + if c.loopIterations <= 0: + if allowInfiniteLoops in c.features: + c.loopIterations = MaxLoopIterations + else: + msgWriteln("stack trace: (most recent call last)") + stackTraceAux(c, tos, pc) + globalError(c.debug[pc], errTooManyIterations) + dec(c.loopIterations) + proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = var pc = start var tos = tos @@ -735,6 +747,9 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = globalError(c.debug[pc], errGenerated, "VM not built with FFI support") elif prc.kind != skTemplate: let newPc = compile(c, prc) + # tricky: a recursion is also a jump back, so we use the same + # logic as for loops: + if newPc < pc: handleJmpBack() #echo "new pc ", newPc, " calling: ", prc.name.s var newFrame = PStackFrame(prc: prc, comesFrom: pc, next: tos) newSeq(newFrame.slots, prc.offset) @@ -778,6 +793,10 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = # jump Bx let rbx = instr.regBx - wordExcess - 1 # -1 for the following 'inc pc' inc pc, rbx + of opcJmpBack: + let rbx = instr.regBx - wordExcess - 1 # -1 for the following 'inc pc' + inc pc, rbx + handleJmpBack() of opcBranch: # we know the next instruction is a 'fjmp': let branch = c.constants[instr.regBx-wordExcess] diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index 7725d79b8..90ff8e29f 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -16,6 +16,9 @@ const byteExcess* = 128 # we use excess-K for immediates wordExcess* = 32768 + MaxLoopIterations* = 500_000 # max iterations of all loops + + type TRegister* = range[0..255] TDest* = range[-1 .. 255] @@ -110,6 +113,7 @@ type opcTJmp, # jump Bx if A != 0 opcFJmp, # jump Bx if A == 0 opcJmp, # jump Bx + opcJmpBack, # jump Bx; resulting from a while loop opcBranch, # branch for 'case' opcTry, opcExcept, @@ -182,6 +186,7 @@ type mode*: TEvalMode features*: TSandboxFlags traceActive*: bool + loopIterations*: int TPosition* = distinct int @@ -190,7 +195,7 @@ type proc newCtx*(module: PSym): PCtx = PCtx(code: @[], debug: @[], globals: newNode(nkStmtListExpr), constants: newNode(nkStmtList), types: @[], - prc: PProc(blocks: @[]), module: module) + prc: PProc(blocks: @[]), module: module, loopIterations: MaxLoopIterations) proc refresh*(c: PCtx, module: PSym) = c.module = module diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 82d1e9ab8..a3af54145 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -92,10 +92,10 @@ proc genLabel(c: PCtx): TPosition = result = TPosition(c.code.len) #c.jumpTargets.incl(c.code.len) -proc jmpBack(c: PCtx, n: PNode, opc: TOpcode, p = TPosition(0)) = +proc jmpBack(c: PCtx, n: PNode, p = TPosition(0)) = let dist = p.int - c.code.len internalAssert(-0x7fff < dist and dist < 0x7fff) - gABx(c, n, opc, 0, dist) + gABx(c, n, opcJmpBack, 0, dist) proc patch(c: PCtx, p: TPosition) = # patch with current index @@ -229,20 +229,20 @@ proc genWhile(c: PCtx; n: PNode) = withBlock(nil): if isTrue(n.sons[0]): c.gen(n.sons[1]) - c.jmpBack(n, opcJmp, L1) + c.jmpBack(n, L1) elif isNotOpr(n.sons[0]): var tmp = c.genx(n.sons[0].sons[1]) let L2 = c.xjmp(n, opcTJmp, tmp) c.freeTemp(tmp) c.gen(n.sons[1]) - c.jmpBack(n, opcJmp, L1) + c.jmpBack(n, L1) c.patch(L2) else: var tmp = c.genx(n.sons[0]) let L2 = c.xjmp(n, opcFJmp, tmp) c.freeTemp(tmp) c.gen(n.sons[1]) - c.jmpBack(n, opcJmp, L1) + c.jmpBack(n, L1) c.patch(L2) proc genBlock(c: PCtx; n: PNode; dest: var TDest) = @@ -1518,7 +1518,7 @@ proc optimizeJumps(c: PCtx; start: int) = var d = i + c.code[i].jmpDiff for iters in countdown(maxIterations, 0): case c.code[d].opcode - of opcJmp: + of opcJmp, opcJmpBack: d = d + c.code[d].jmpDiff of opcTJmp, opcFJmp: if c.code[d].regA != reg: break @@ -1536,7 +1536,7 @@ proc optimizeJumps(c: PCtx; start: int) = else: break if d != i + c.code[i].jmpDiff: c.finalJumpTarget(i, d - i) - of opcJmp: + of opcJmp, opcJmpBack: var d = i + c.code[i].jmpDiff var iters = maxIterations while c.code[d].opcode == opcJmp and iters > 0: |