new vm: lots of fixes

This commit is contained in:
Araq 2013-07-27 01:28:31 +02:00
commit 27b7ecbbff
3 changed files with 146 additions and 53 deletions

View file

@ -10,7 +10,10 @@
## This file implements the new evaluation engine for Nimrod code. ## 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-2 int32s in memory, it is a register based VM.
import ast, astalgo, msgs, vmdef, vmgen, nimsets, types, passes, unsigned import
strutils, ast, astalgo, msgs, vmdef, vmgen, nimsets, types, passes, unsigned
from semfold import leValueConv
type type
PStackFrame* = ref TStackFrame PStackFrame* = ref TStackFrame
@ -79,10 +82,6 @@ template decodeBx(k: expr) {.immediate, dirty.} =
let rbx = instr.regBx - wordExcess let rbx = instr.regBx - wordExcess
ensureKind(k) ensureKind(k)
proc compile(c: PCtx, s: PSym): int =
result = vmgen.genProc(c, s)
#c.echoCode
proc myreset(n: PNode) = proc myreset(n: PNode) =
when defined(system.reset): when defined(system.reset):
var oldInfo = n.info var oldInfo = n.info
@ -130,18 +129,14 @@ proc pushSafePoint(f: PStackFrame; pc: int) =
proc popSafePoint(f: PStackFrame) = discard f.safePoints.pop() proc popSafePoint(f: PStackFrame) = discard f.safePoints.pop()
proc nextSafePoint(f: PStackFrame): int =
var f = f
while f.safePoints.isNil or f.safePoints.len == 0:
f = f.next
if f.isNil: return -1
result = f.safePoints.pop
proc cleanUpOnException(c: PCtx; tos: PStackFrame; regs: TNodeSeq): int = proc cleanUpOnException(c: PCtx; tos: PStackFrame; regs: TNodeSeq): int =
let raisedType = c.currentExceptionA.typ.skipTypes(abstractPtrs) let raisedType = c.currentExceptionA.typ.skipTypes(abstractPtrs)
var f = tos
while true: while true:
var pc2 = tos.nextSafePoint while f.safePoints.isNil or f.safePoints.len == 0:
if pc2 == -1: return -1 f = f.next
if f.isNil: return -1
var pc2 = f.safePoints[f.safePoints.high]
var nextExceptOrFinally = -1 var nextExceptOrFinally = -1
if c.code[pc2].opcode == opcExcept: if c.code[pc2].opcode == opcExcept:
@ -163,6 +158,8 @@ proc cleanUpOnException(c: PCtx; tos: PStackFrame; regs: TNodeSeq): int =
if c.code[pc2].opcode == opcFinally: if c.code[pc2].opcode == opcFinally:
# execute the corresponding handler, but don't quit walking the stack: # execute the corresponding handler, but don't quit walking the stack:
return pc2 return pc2
# not the right one:
discard f.safePoints.pop
proc cleanUpOnReturn(c: PCtx; f: PStackFrame): int = proc cleanUpOnReturn(c: PCtx; f: PStackFrame): int =
if f.safePoints.isNil: return -1 if f.safePoints.isNil: return -1
@ -174,6 +171,10 @@ proc cleanUpOnReturn(c: PCtx; f: PStackFrame): int =
return pc return pc
return -1 return -1
proc compile(c: PCtx, s: PSym): int =
result = vmgen.genProc(c, s)
#c.echoCode
proc execute(c: PCtx, start: int) = proc execute(c: PCtx, start: int) =
var pc = start var pc = start
var regs: TNodeSeq # alias to tos.slots for performance var regs: TNodeSeq # alias to tos.slots for performance
@ -188,11 +189,12 @@ proc execute(c: PCtx, start: int) =
of opcEof: break of opcEof: break
of opcRet: of opcRet:
# XXX perform any cleanup actions # XXX perform any cleanup actions
pc = tos.comesFrom
tos = tos.next tos = tos.next
if tos.isNil: return if tos.isNil: return
let retVal = regs[0] let retVal = regs[0]
move(regs, tos.slots) move(regs, tos.slots)
pc = tos.comesFrom
assert c.code[pc].opcode in {opcIndCall, opcIndCallAsgn} assert c.code[pc].opcode in {opcIndCall, opcIndCallAsgn}
if c.code[pc].opcode == opcIndCallAsgn: if c.code[pc].opcode == opcIndCallAsgn:
regs[c.code[pc].regA] = retVal regs[c.code[pc].regA] = retVal
@ -222,6 +224,10 @@ proc execute(c: PCtx, start: int) =
let idx = regs[rc].intVal let idx = regs[rc].intVal
# XXX what if the array is not 0-based? -> codegen should insert a sub # XXX what if the array is not 0-based? -> codegen should insert a sub
regs[ra] = regs[rb].sons[idx.int] regs[ra] = regs[rb].sons[idx.int]
of opcLdStrIdx:
decodeBC(nkIntLit)
let idx = regs[rc].intVal
regs[ra].intVal = regs[rb].strVal[idx.int].ord
of opcWrArr: of opcWrArr:
# a[b] = c # a[b] = c
let rb = instr.regB let rb = instr.regB
@ -432,6 +438,15 @@ proc execute(c: PCtx, start: int) =
regs[ra].strVal = getstr(regs[rb]) regs[ra].strVal = getstr(regs[rb])
for i in rb+1..rb+rc-1: for i in rb+1..rb+rc-1:
regs[ra].strVal.add getstr(regs[i]) regs[ra].strVal.add getstr(regs[i])
of opcAddStrCh:
decodeB(nkStrLit)
regs[ra].strVal.add(regs[rb].intVal.chr)
of opcAddStrStr:
decodeB(nkStrLit)
regs[ra].strVal.add(regs[rb].strVal)
of opcAddSeqElem:
decodeB(nkBracket)
regs[ra].add(copyTree(regs[rb]))
of opcEcho: of opcEcho:
echo regs[ra].strVal echo regs[ra].strVal
of opcContainsSet: of opcContainsSet:
@ -444,6 +459,14 @@ proc execute(c: PCtx, start: int) =
let rd = c.code[pc].regA let rd = c.code[pc].regA
regs[ra].strVal = substr(regs[rb].strVal, regs[rc].intVal.int, regs[ra].strVal = substr(regs[rb].strVal, regs[rc].intVal.int,
regs[rd].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])):
stackTrace(c, tos, pc, errGenerated,
msgKindToString(errIllegalConvFromXtoY) % [
"unknown type" , "unknown type"])
of opcIndCall, opcIndCallAsgn: of opcIndCall, opcIndCallAsgn:
# dest = call regStart, n; where regStart = fn, arg1, ... # dest = call regStart, n; where regStart = fn, arg1, ...
let rb = instr.regB let rb = instr.regB
@ -545,6 +568,12 @@ proc execute(c: PCtx, start: int) =
regs[ra] = getNullValue(typ, c.debug[pc]) regs[ra] = getNullValue(typ, c.debug[pc])
of opcLdConst: of opcLdConst:
regs[ra] = c.constants.sons[instr.regBx - wordExcess] regs[ra] = c.constants.sons[instr.regBx - wordExcess]
of opcAsgnConst:
let rb = instr.regBx - wordExcess
if regs[ra].isNil:
regs[ra] = copyTree(c.constants.sons[rb])
else:
asgnComplex(regs[ra], c.constants.sons[rb])
of opcNBindSym: of opcNBindSym:
# trivial implementation: # trivial implementation:
let rb = instr.regB let rb = instr.regB

View file

@ -21,10 +21,6 @@ type
TDest* = range[-1 .. 255] TDest* = range[-1 .. 255]
TInstr* = distinct uint32 TInstr* = distinct uint32
TInstrFormat = enum
ifABC, # three registers
ifABx, # A + extended B
TOpcode* = enum TOpcode* = enum
opcEof, # end of code opcEof, # end of code
opcRet, # return opcRet, # return
@ -46,6 +42,7 @@ type
opcAddr, opcAddr,
opcDeref, opcDeref,
opcWrStrIdx, opcWrStrIdx,
opcLdStrIdx, # a = b[c]
opcAddInt, opcAddInt,
opcAddImmInt, opcAddImmInt,
@ -66,12 +63,18 @@ type
opcSwap, opcIsNil, opcOf, opcSwap, opcIsNil, opcOf,
opcSubStr, opcConv, opcCast, opcQuit, opcReset, opcSubStr, opcConv, opcCast, opcQuit, opcReset,
opcAddStrCh,
opcAddStrStr,
opcAddSeqElem,
opcRangeChck,
opcEcho, opcEcho,
opcIndCall, # dest = call regStart, n; where regStart = fn, arg1, ... opcIndCall, # dest = call regStart, n; where regStart = fn, arg1, ...
opcIndCallAsgn, # dest = call regStart, n; where regStart = fn, arg1, ... opcIndCallAsgn, # dest = call regStart, n; where regStart = fn, arg1, ...
opcRaise, opcRaise,
opcNBindSym, # opcodes for the AST manipulation following opcNBindSym, # opcodes for the AST manipulation following
opcNewStr,
opcTJmp, # jump Bx if A != 0 opcTJmp, # jump Bx if A != 0
opcFJmp, # jump Bx if A == 0 opcFJmp, # jump Bx if A == 0
@ -83,9 +86,9 @@ type
opcFinallyEnd, opcFinallyEnd,
opcNew, opcNew,
opcNewSeq, opcNewSeq,
opcNewStr,
opcLdNull, # dest = nullvalue(types[Bx]) opcLdNull, # dest = nullvalue(types[Bx])
opcLdConst, # dest = constants[Bx] opcLdConst, # dest = constants[Bx]
opcAsgnConst, # dest = copy(constants[Bx])
opcLdGlobal, # dest = globals[Bx] opcLdGlobal, # dest = globals[Bx]
opcLdImmInt, # dest = immediate value opcLdImmInt, # dest = immediate value
opcWrGlobal, opcWrGlobal,
@ -100,7 +103,8 @@ type
# temporary slot usage. This is required for the parameter # temporary slot usage. This is required for the parameter
# passing implementation. # passing implementation.
slotEmpty, # slot is unused slotEmpty, # slot is unused
slotFixed, # slot is used for a fixed var/param/result slotFixedVar, # slot is used for a fixed var/result (requires copy then)
slotFixedLet, # slot is used for a fixed param/let
slotTempUnknown, # slot but type unknown (argument of proc call) slotTempUnknown, # slot but type unknown (argument of proc call)
slotTempInt, # some temporary int slotTempInt, # some temporary int
slotTempFloat, # some temporary float slotTempFloat, # some temporary float
@ -117,11 +121,6 @@ type
code*: seq[TInstr] code*: seq[TInstr]
debug*: seq[TLineInfo] # line info for every instruction; kept separate debug*: seq[TLineInfo] # line info for every instruction; kept separate
# to not slow down interpretation # to not slow down interpretation
jumpTargets*: TIntSet # we need to mark instructions that are
# jump targets;
# we must not optimize over a jump target and we
# need to generate a label for a jump target when
# producing a VM listing
globals*: PNode # globals*: PNode #
constants*: PNode # constant data constants*: PNode # constant data
types*: seq[PType] # some instructions reference types (e.g. 'except') types*: seq[PType] # some instructions reference types (e.g. 'except')
@ -132,7 +131,7 @@ type
TPosition* = distinct int TPosition* = distinct int
proc newCtx*(): PCtx = proc newCtx*(): PCtx =
PCtx(code: @[], debug: @[], jumpTargets: initIntSet(), PCtx(code: @[], debug: @[],
globals: newNode(nkStmtList), constants: newNode(nkStmtList), types: @[], globals: newNode(nkStmtList), constants: newNode(nkStmtList), types: @[],
prc: PProc(blocks: @[])) prc: PProc(blocks: @[]))
@ -141,6 +140,7 @@ const
largeInstrs* = { # instructions which use 2 int32s instead of 1: largeInstrs* = { # instructions which use 2 int32s instead of 1:
opcSubstr, opcConv, opcCast, opcNewSeq, opcOf} opcSubstr, opcConv, opcCast, opcNewSeq, opcOf}
slotSomeTemp* = slotTempUnknown slotSomeTemp* = slotTempUnknown
relativeJumps* = {opcTJmp, opcFJmp, opcJmp}
template opcode*(x: TInstr): TOpcode {.immediate.} = TOpcode(x.uint32 and 0xff'u32) template opcode*(x: TInstr): TOpcode {.immediate.} = TOpcode(x.uint32 and 0xff'u32)
template regA*(x: TInstr): TRegister {.immediate.} = TRegister(x.uint32 shr 8'u32 and 0xff'u32) template regA*(x: TInstr): TRegister {.immediate.} = TRegister(x.uint32 shr 8'u32 and 0xff'u32)

View file

@ -14,16 +14,30 @@ import
trees, intsets, rodread trees, intsets, rodread
proc codeListing(c: PCtx, result: var string) = proc codeListing(c: PCtx, result: var string) =
# first iteration: compute all necessary labels:
var jumpTargets = initIntSet()
for i in 0.. < c.code.len:
let x = c.code[i]
if x.opcode in relativeJumps:
jumpTargets.incl(i+x.regBx-wordExcess)
# for debugging purposes # for debugging purposes
var i = 0 var i = 0
while i < c.code.len: while i < c.code.len:
if i in c.jumpTargets: result.addf("L$1:\n", i) if i in jumpTargets: result.addf("L$1:\n", i)
let x = c.code[i] let x = c.code[i]
let opc = opcode(x) let opc = opcode(x)
if opc < firstABxInstr: if opc < firstABxInstr:
result.addf("\t$#\tr$#, r$#, r$#", ($opc).substr(3), x.regA, result.addf("\t$#\tr$#, r$#, r$#", ($opc).substr(3), x.regA,
x.regB, x.regC) x.regB, x.regC)
elif opc in relativeJumps:
result.addf("\t$#\tr$#, L$#", ($opc).substr(3), x.regA,
i+x.regBx-wordExcess)
elif opc in {opcLdConst, opcAsgnConst}:
result.addf("\t$#\tr$#, $#", ($opc).substr(3), x.regA,
c.constants[x.regBx-wordExcess].renderTree)
else: else:
result.addf("\t$#\tr$#, $#", ($opc).substr(3), x.regA, x.regBx-wordExcess) result.addf("\t$#\tr$#, $#", ($opc).substr(3), x.regA, x.regBx-wordExcess)
result.add("\t#") result.add("\t#")
@ -64,7 +78,7 @@ proc xjmp(c: PCtx; n: PNode; opc: TOpcode; a: TRegister = 0): TPosition =
proc genLabel(c: PCtx): TPosition = proc genLabel(c: PCtx): TPosition =
result = TPosition(c.code.len) result = TPosition(c.code.len)
c.jumpTargets.incl(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, opc: TOpcode, p = TPosition(0)) =
let dist = p.int - c.code.len let dist = p.int - c.code.len
@ -75,7 +89,7 @@ proc patch(c: PCtx, p: TPosition) =
# patch with current index # patch with current index
let p = p.int let p = p.int
let diff = c.code.len - p let diff = c.code.len - p
c.jumpTargets.incl(c.code.len) #c.jumpTargets.incl(c.code.len)
InternalAssert(-0x7fff < diff and diff < 0x7fff) InternalAssert(-0x7fff < diff and diff < 0x7fff)
let oldInstr = c.code[p] let oldInstr = c.code[p]
# opcode and regA stay the same: # opcode and regA stay the same:
@ -195,10 +209,11 @@ proc genBlock(c: PCtx; n: PNode; dest: var TDest) =
proc genBreak(c: PCtx; n: PNode) = proc genBreak(c: PCtx; n: PNode) =
let L1 = c.xjmp(n, opcJmp) let L1 = c.xjmp(n, opcJmp)
if n.sons[0].kind == nkSym: if n.sons[0].kind == nkSym:
echo cast[int](n.sons[0].sym)
for i in countdown(c.prc.blocks.len-1, 0): for i in countdown(c.prc.blocks.len-1, 0):
if c.prc.blocks[i].label == n.sons[0].sym: if c.prc.blocks[i].label == n.sons[0].sym:
c.prc.blocks[i].fixups.add L1 c.prc.blocks[i].fixups.add L1
break return
InternalError(n.info, "cannot find 'break' target") InternalError(n.info, "cannot find 'break' target")
else: else:
c.prc.blocks[c.prc.blocks.high].fixups.add L1 c.prc.blocks[c.prc.blocks.high].fixups.add L1
@ -365,7 +380,10 @@ proc genCall(c: PCtx; n: PNode; dest: var TDest) =
proc genNew(c: PCtx; n: PNode) = proc genNew(c: PCtx; n: PNode) =
let dest = c.genx(n.sons[1]) let dest = c.genx(n.sons[1])
c.gABx(n, opcNew, dest, c.genType(n.sons[1].typ.skipTypes(abstractVar))) # we use the ref's base type here as the VM conflates 'ref object'
# and 'object' since internally we already have a pointer.
c.gABx(n, opcNew, dest,
c.genType(n.sons[1].typ.skipTypes(abstractVar).sons[0]))
c.freeTemp(dest) c.freeTemp(dest)
proc genNewSeq(c: PCtx; n: PNode) = proc genNewSeq(c: PCtx; n: PNode) =
@ -382,6 +400,12 @@ proc genUnaryABC(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
c.gABC(n, opc, dest, tmp) c.gABC(n, opc, dest, tmp)
c.freeTemp(tmp) c.freeTemp(tmp)
proc genUnaryABI(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
let tmp = c.genx(n.sons[1])
if dest < 0: dest = c.getTemp(n.typ)
c.gABI(n, opc, dest, tmp, 0)
c.freeTemp(tmp)
proc genBinaryABC(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) = proc genBinaryABC(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
let let
tmp = c.genx(n.sons[1]) tmp = c.genx(n.sons[1])
@ -391,6 +415,13 @@ proc genBinaryABC(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
c.freeTemp(tmp) c.freeTemp(tmp)
c.freeTemp(tmp2) c.freeTemp(tmp2)
proc genBinaryStmt(c: PCtx; n: PNode; opc: TOpcode) =
let
dest = c.genx(n.sons[1])
tmp = c.genx(n.sons[2])
c.gABC(n, opc, dest, tmp, 0)
c.freeTemp(tmp)
proc genVarargsABC(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) = proc genVarargsABC(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
if dest < 0: dest = getTemp(c, n.typ) if dest < 0: dest = getTemp(c, n.typ)
var x = c.getTempRange(n.len-1, slotTempStr) var x = c.getTempRange(n.len-1, slotTempStr)
@ -465,9 +496,9 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
c.gABC(n, opcNewStr, dest, tmp) c.gABC(n, opcNewStr, dest, tmp)
c.freeTemp(tmp) c.freeTemp(tmp)
of mLengthOpenArray, mLengthArray, mLengthSeq: of mLengthOpenArray, mLengthArray, mLengthSeq:
genUnaryABC(c, n, dest, opcLenSeq) genUnaryABI(c, n, dest, opcLenSeq)
of mLengthStr: of mLengthStr:
genUnaryABC(c, n, dest, opcLenStr) genUnaryABI(c, n, dest, opcLenStr)
of mIncl, mExcl: of mIncl, mExcl:
unused(n, dest) unused(n, dest)
var d = c.genx(n.sons[1]) var d = c.genx(n.sons[1])
@ -596,9 +627,15 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
var d = c.genx(n.sons[i]) var d = c.genx(n.sons[i])
c.gABC(n, opcEcho, d) c.gABC(n, opcEcho, d)
c.freeTemp(d) c.freeTemp(d)
of mAppendStrCh: InternalError(n.info, "cannot generate code for: " & $m) of mAppendStrCh:
of mAppendStrStr: InternalError(n.info, "cannot generate code for: " & $m) unused(n, dest)
of mAppendSeqElem: InternalError(n.info, "cannot generate code for: " & $m) genBinaryStmt(c, n, opcAddStrCh)
of mAppendStrStr:
unused(n, dest)
genBinaryStmt(c, n, opcAddStrStr)
of mAppendSeqElem:
unused(n, dest)
genBinaryStmt(c, n, opcAddSeqElem)
of mParseExprToAst: InternalError(n.info, "cannot generate code for: " & $m) of mParseExprToAst: InternalError(n.info, "cannot generate code for: " & $m)
of mParseStmtToAst: InternalError(n.info, "cannot generate code for: " & $m) of mParseStmtToAst: InternalError(n.info, "cannot generate code for: " & $m)
of mExpandToAst: InternalError(n.info, "cannot generate code for: " & $m) of mExpandToAst: InternalError(n.info, "cannot generate code for: " & $m)
@ -664,18 +701,18 @@ proc requiresCopy(n: PNode): bool =
else: else:
result = true result = true
proc unnecessaryIndirection(n: PNode): bool = proc unneededIndirection(n: PNode): bool =
n.typ.skipTypes(abstractInst).kind == tyRef n.typ.skipTypes(abstractInst).kind == tyRef
proc skipDeref(n: PNode): PNode = proc skipDeref(n: PNode): PNode =
if n.kind in {nkDerefExpr, nkHiddenDeref} and unnecessaryIndirection(n): if n.kind in {nkDerefExpr, nkHiddenDeref} and unneededIndirection(n.sons[0]):
result = n.sons[0] result = n.sons[0]
else: else:
result = n result = n
proc genAddrDeref(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) = proc genAddrDeref(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
# a nop for certain types # a nop for certain types
if unnecessaryIndirection(n): if unneededIndirection(n.sons[0]):
gen(c, n.sons[0], dest) gen(c, n.sons[0], dest)
else: else:
let tmp = c.genx(n.sons[0]) let tmp = c.genx(n.sons[0])
@ -740,9 +777,11 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
genAsgn(c, dest, ri, requiresCopy) genAsgn(c, dest, ri, requiresCopy)
proc genLit(c: PCtx; n: PNode; dest: var TDest) = proc genLit(c: PCtx; n: PNode; dest: var TDest) =
var opc = opcLdConst
if dest < 0: dest = c.getTemp(n.typ) if dest < 0: dest = c.getTemp(n.typ)
elif c.prc.slots[dest].kind == slotFixedVar: opc = opcAsgnConst
let lit = genLiteral(c, n) let lit = genLiteral(c, n)
c.gABx(n, opcLdConst, dest, lit) c.gABx(n, opc, dest, lit)
proc genRdVar(c: PCtx; n: PNode; dest: var TDest) = proc genRdVar(c: PCtx; n: PNode; dest: var TDest) =
let s = n.sym let s = n.sym
@ -775,7 +814,10 @@ proc genObjAccess(c: PCtx; n: PNode; dest: var TDest) =
genAccess(c, n, dest, opcLdObj) genAccess(c, n, dest, opcLdObj)
proc genArrAccess(c: PCtx; n: PNode; dest: var TDest) = proc genArrAccess(c: PCtx; n: PNode; dest: var TDest) =
genAccess(c, n, dest, opcLdArr) if n.sons[0].typ.skipTypes(abstractVarRange).kind in {tyString, tyCString}:
genAccess(c, n, dest, opcLdStrIdx)
else:
genAccess(c, n, dest, opcLdArr)
proc getNullValue*(typ: PType, info: TLineInfo): PNode proc getNullValue*(typ: PType, info: TLineInfo): PNode
proc getNullValueAux(obj: PNode, result: PNode) = proc getNullValueAux(obj: PNode, result: PNode) =
@ -827,7 +869,8 @@ proc setSlot(c: PCtx; v: PSym) =
# XXX generate type initialization here? # XXX generate type initialization here?
if v.position == 0: if v.position == 0:
v.position = c.prc.maxSlots v.position = c.prc.maxSlots
c.prc.slots[v.position] = (inUse: true, kind: slotFixed) c.prc.slots[v.position] = (inUse: true,
kind: if v.kind == skLet: slotFixedLet else: slotFixedVar)
inc c.prc.maxSlots inc c.prc.maxSlots
proc genVarSection(c: PCtx; n: PNode) = proc genVarSection(c: PCtx; n: PNode) =
@ -959,36 +1002,56 @@ proc gen(c: PCtx; n: PNode; dest: var TDest) =
let s = n.sons[namePos].sym let s = n.sons[namePos].sym
discard genProc(c, s) discard genProc(c, s)
genLit(c, n.sons[namePos], dest) genLit(c, n.sons[namePos], dest)
of nkChckRangeF, nkChckRange64, nkChckRange:
let
tmp0 = c.genx(n.sons[0])
tmp1 = c.genx(n.sons[1])
tmp2 = c.genx(n.sons[2])
c.gABC(n, opcRangeChck, tmp0, tmp1, tmp2)
c.freeTemp(tmp1)
c.freeTemp(tmp2)
if dest >= 0:
gABC(c, n, whichAsgnOpc(n), dest, tmp0)
c.freeTemp(tmp0)
else:
dest = tmp0
of nkEmpty, nkCommentStmt, nkTypeSection, nkConstSection, nkPragma, of nkEmpty, nkCommentStmt, nkTypeSection, nkConstSection, nkPragma,
nkTemplateDef, nkIncludeStmt, nkImportStmt: nkTemplateDef, nkIncludeStmt, nkImportStmt:
unused(n, dest) unused(n, dest)
of nkStringToCString, nkCStringToString:
gen(c, n.sons[0], dest)
else: else:
#of nkCurly, nkBracket, nkPar: #of nkCurly, nkBracket, nkPar:
InternalError n.info, "too implement " & $n.kind InternalError n.info, "too implement " & $n.kind
proc genStmt*(c: PCtx; n: PNode): int = proc removeLastEof(c: PCtx) =
result = c.code.len
var d: TDest = -1
gen(c, n, d)
let last = c.code.len-1 let last = c.code.len-1
if last >= 0 and c.code[last].opcode == opcEof: if last >= 0 and c.code[last].opcode == opcEof:
# since we can re-use the EOF nothing happened: # overwrite last EOF:
result = last assert c.code.len == c.debug.len
else: c.code.setLen(last)
gABC(c, n, opcEof) c.debug.setLen(last)
proc genStmt*(c: PCtx; n: PNode): int =
c.removeLastEof
result = c.code.len
var d: TDest = -1
c.gen(n, d)
c.gABC(n, opcEof)
InternalAssert d < 0 InternalAssert d < 0
proc genParams(c: PCtx; params: PNode) = proc genParams(c: PCtx; params: PNode) =
# res.sym.position is already 0 # res.sym.position is already 0
c.prc.slots[0] = (inUse: true, kind: slotFixed) c.prc.slots[0] = (inUse: true, kind: slotFixedVar)
for i in 1.. <params.len: for i in 1.. <params.len:
let param = params.sons[i].sym let param = params.sons[i].sym
c.prc.slots[i] = (inUse: true, kind: slotFixed) c.prc.slots[i] = (inUse: true, kind: slotFixedLet)
c.prc.maxSlots = max(params.len, 1) c.prc.maxSlots = max(params.len, 1)
proc genProc(c: PCtx; s: PSym): int = proc genProc(c: PCtx; s: PSym): int =
let x = s.ast.sons[optimizedCodePos] let x = s.ast.sons[optimizedCodePos]
if x.kind == nkEmpty: if x.kind == nkEmpty:
c.removeLastEof
result = c.code.len+1 # skip the jump instruction result = c.code.len+1 # skip the jump instruction
s.ast.sons[optimizedCodePos] = newIntNode(nkIntLit, result) s.ast.sons[optimizedCodePos] = newIntNode(nkIntLit, result)
# thanks to the jmp we can add top level statements easily and also nest # thanks to the jmp we can add top level statements easily and also nest
@ -1004,6 +1067,7 @@ proc genProc(c: PCtx; s: PSym): int =
# generate final 'return' statement: # generate final 'return' statement:
c.gABC(body, opcRet) c.gABC(body, opcRet)
c.patch(procStart) c.patch(procStart)
c.gABC(body, opcEof)
s.position = c.prc.maxSlots s.position = c.prc.maxSlots
c.prc = oldPrc c.prc = oldPrc
else: else: