mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-30 09:54:49 +00:00
new vm: lots of fixes
This commit is contained in:
@@ -10,7 +10,10 @@
|
||||
## This file implements the new evaluation engine for Nimrod code.
|
||||
## 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
|
||||
PStackFrame* = ref TStackFrame
|
||||
@@ -79,10 +82,6 @@ template decodeBx(k: expr) {.immediate, dirty.} =
|
||||
let rbx = instr.regBx - wordExcess
|
||||
ensureKind(k)
|
||||
|
||||
proc compile(c: PCtx, s: PSym): int =
|
||||
result = vmgen.genProc(c, s)
|
||||
#c.echoCode
|
||||
|
||||
proc myreset(n: PNode) =
|
||||
when defined(system.reset):
|
||||
var oldInfo = n.info
|
||||
@@ -130,18 +129,14 @@ proc pushSafePoint(f: PStackFrame; pc: int) =
|
||||
|
||||
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 =
|
||||
let raisedType = c.currentExceptionA.typ.skipTypes(abstractPtrs)
|
||||
var f = tos
|
||||
while true:
|
||||
var pc2 = tos.nextSafePoint
|
||||
if pc2 == -1: return -1
|
||||
while f.safePoints.isNil or f.safePoints.len == 0:
|
||||
f = f.next
|
||||
if f.isNil: return -1
|
||||
var pc2 = f.safePoints[f.safePoints.high]
|
||||
|
||||
var nextExceptOrFinally = -1
|
||||
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:
|
||||
# execute the corresponding handler, but don't quit walking the stack:
|
||||
return pc2
|
||||
# not the right one:
|
||||
discard f.safePoints.pop
|
||||
|
||||
proc cleanUpOnReturn(c: PCtx; f: PStackFrame): int =
|
||||
if f.safePoints.isNil: return -1
|
||||
@@ -174,6 +171,10 @@ proc cleanUpOnReturn(c: PCtx; f: PStackFrame): int =
|
||||
return pc
|
||||
return -1
|
||||
|
||||
proc compile(c: PCtx, s: PSym): int =
|
||||
result = vmgen.genProc(c, s)
|
||||
#c.echoCode
|
||||
|
||||
proc execute(c: PCtx, start: int) =
|
||||
var pc = start
|
||||
var regs: TNodeSeq # alias to tos.slots for performance
|
||||
@@ -188,11 +189,12 @@ proc execute(c: PCtx, start: int) =
|
||||
of opcEof: break
|
||||
of opcRet:
|
||||
# XXX perform any cleanup actions
|
||||
pc = tos.comesFrom
|
||||
tos = tos.next
|
||||
if tos.isNil: return
|
||||
|
||||
let retVal = regs[0]
|
||||
move(regs, tos.slots)
|
||||
pc = tos.comesFrom
|
||||
assert c.code[pc].opcode in {opcIndCall, opcIndCallAsgn}
|
||||
if c.code[pc].opcode == opcIndCallAsgn:
|
||||
regs[c.code[pc].regA] = retVal
|
||||
@@ -222,6 +224,10 @@ proc execute(c: PCtx, start: int) =
|
||||
let idx = regs[rc].intVal
|
||||
# XXX what if the array is not 0-based? -> codegen should insert a sub
|
||||
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:
|
||||
# a[b] = c
|
||||
let rb = instr.regB
|
||||
@@ -432,6 +438,15 @@ proc execute(c: PCtx, start: int) =
|
||||
regs[ra].strVal = getstr(regs[rb])
|
||||
for i in rb+1..rb+rc-1:
|
||||
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:
|
||||
echo regs[ra].strVal
|
||||
of opcContainsSet:
|
||||
@@ -444,6 +459,14 @@ proc execute(c: PCtx, start: int) =
|
||||
let rd = c.code[pc].regA
|
||||
regs[ra].strVal = substr(regs[rb].strVal, regs[rc].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:
|
||||
# dest = call regStart, n; where regStart = fn, arg1, ...
|
||||
let rb = instr.regB
|
||||
@@ -545,6 +568,12 @@ proc execute(c: PCtx, start: int) =
|
||||
regs[ra] = getNullValue(typ, c.debug[pc])
|
||||
of opcLdConst:
|
||||
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:
|
||||
# trivial implementation:
|
||||
let rb = instr.regB
|
||||
|
||||
@@ -21,10 +21,6 @@ type
|
||||
TDest* = range[-1 .. 255]
|
||||
TInstr* = distinct uint32
|
||||
|
||||
TInstrFormat = enum
|
||||
ifABC, # three registers
|
||||
ifABx, # A + extended B
|
||||
|
||||
TOpcode* = enum
|
||||
opcEof, # end of code
|
||||
opcRet, # return
|
||||
@@ -46,6 +42,7 @@ type
|
||||
opcAddr,
|
||||
opcDeref,
|
||||
opcWrStrIdx,
|
||||
opcLdStrIdx, # a = b[c]
|
||||
|
||||
opcAddInt,
|
||||
opcAddImmInt,
|
||||
@@ -66,12 +63,18 @@ type
|
||||
opcSwap, opcIsNil, opcOf,
|
||||
opcSubStr, opcConv, opcCast, opcQuit, opcReset,
|
||||
|
||||
opcAddStrCh,
|
||||
opcAddStrStr,
|
||||
opcAddSeqElem,
|
||||
opcRangeChck,
|
||||
|
||||
opcEcho,
|
||||
opcIndCall, # dest = call regStart, n; where regStart = fn, arg1, ...
|
||||
opcIndCallAsgn, # dest = call regStart, n; where regStart = fn, arg1, ...
|
||||
|
||||
opcRaise,
|
||||
opcNBindSym, # opcodes for the AST manipulation following
|
||||
opcNewStr,
|
||||
|
||||
opcTJmp, # jump Bx if A != 0
|
||||
opcFJmp, # jump Bx if A == 0
|
||||
@@ -83,9 +86,9 @@ type
|
||||
opcFinallyEnd,
|
||||
opcNew,
|
||||
opcNewSeq,
|
||||
opcNewStr,
|
||||
opcLdNull, # dest = nullvalue(types[Bx])
|
||||
opcLdConst, # dest = constants[Bx]
|
||||
opcAsgnConst, # dest = copy(constants[Bx])
|
||||
opcLdGlobal, # dest = globals[Bx]
|
||||
opcLdImmInt, # dest = immediate value
|
||||
opcWrGlobal,
|
||||
@@ -100,7 +103,8 @@ type
|
||||
# temporary slot usage. This is required for the parameter
|
||||
# passing implementation.
|
||||
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)
|
||||
slotTempInt, # some temporary int
|
||||
slotTempFloat, # some temporary float
|
||||
@@ -117,11 +121,6 @@ type
|
||||
code*: seq[TInstr]
|
||||
debug*: seq[TLineInfo] # line info for every instruction; kept separate
|
||||
# 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 #
|
||||
constants*: PNode # constant data
|
||||
types*: seq[PType] # some instructions reference types (e.g. 'except')
|
||||
@@ -132,7 +131,7 @@ type
|
||||
TPosition* = distinct int
|
||||
|
||||
proc newCtx*(): PCtx =
|
||||
PCtx(code: @[], debug: @[], jumpTargets: initIntSet(),
|
||||
PCtx(code: @[], debug: @[],
|
||||
globals: newNode(nkStmtList), constants: newNode(nkStmtList), types: @[],
|
||||
prc: PProc(blocks: @[]))
|
||||
|
||||
@@ -141,6 +140,7 @@ const
|
||||
largeInstrs* = { # instructions which use 2 int32s instead of 1:
|
||||
opcSubstr, opcConv, opcCast, opcNewSeq, opcOf}
|
||||
slotSomeTemp* = slotTempUnknown
|
||||
relativeJumps* = {opcTJmp, opcFJmp, opcJmp}
|
||||
|
||||
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)
|
||||
|
||||
@@ -14,16 +14,30 @@ import
|
||||
trees, intsets, rodread
|
||||
|
||||
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
|
||||
var i = 0
|
||||
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 opc = opcode(x)
|
||||
if opc < firstABxInstr:
|
||||
result.addf("\t$#\tr$#, r$#, r$#", ($opc).substr(3), x.regA,
|
||||
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:
|
||||
result.addf("\t$#\tr$#, $#", ($opc).substr(3), x.regA, x.regBx-wordExcess)
|
||||
result.add("\t#")
|
||||
@@ -64,7 +78,7 @@ proc xjmp(c: PCtx; n: PNode; opc: TOpcode; a: TRegister = 0): TPosition =
|
||||
|
||||
proc genLabel(c: PCtx): TPosition =
|
||||
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)) =
|
||||
let dist = p.int - c.code.len
|
||||
@@ -75,7 +89,7 @@ proc patch(c: PCtx, p: TPosition) =
|
||||
# patch with current index
|
||||
let p = p.int
|
||||
let diff = c.code.len - p
|
||||
c.jumpTargets.incl(c.code.len)
|
||||
#c.jumpTargets.incl(c.code.len)
|
||||
InternalAssert(-0x7fff < diff and diff < 0x7fff)
|
||||
let oldInstr = c.code[p]
|
||||
# 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) =
|
||||
let L1 = c.xjmp(n, opcJmp)
|
||||
if n.sons[0].kind == nkSym:
|
||||
echo cast[int](n.sons[0].sym)
|
||||
for i in countdown(c.prc.blocks.len-1, 0):
|
||||
if c.prc.blocks[i].label == n.sons[0].sym:
|
||||
c.prc.blocks[i].fixups.add L1
|
||||
break
|
||||
return
|
||||
InternalError(n.info, "cannot find 'break' target")
|
||||
else:
|
||||
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) =
|
||||
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)
|
||||
|
||||
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.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) =
|
||||
let
|
||||
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(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) =
|
||||
if dest < 0: dest = getTemp(c, n.typ)
|
||||
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.freeTemp(tmp)
|
||||
of mLengthOpenArray, mLengthArray, mLengthSeq:
|
||||
genUnaryABC(c, n, dest, opcLenSeq)
|
||||
genUnaryABI(c, n, dest, opcLenSeq)
|
||||
of mLengthStr:
|
||||
genUnaryABC(c, n, dest, opcLenStr)
|
||||
genUnaryABI(c, n, dest, opcLenStr)
|
||||
of mIncl, mExcl:
|
||||
unused(n, dest)
|
||||
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])
|
||||
c.gABC(n, opcEcho, d)
|
||||
c.freeTemp(d)
|
||||
of mAppendStrCh: InternalError(n.info, "cannot generate code for: " & $m)
|
||||
of mAppendStrStr: InternalError(n.info, "cannot generate code for: " & $m)
|
||||
of mAppendSeqElem: InternalError(n.info, "cannot generate code for: " & $m)
|
||||
of mAppendStrCh:
|
||||
unused(n, dest)
|
||||
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 mParseStmtToAst: 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:
|
||||
result = true
|
||||
|
||||
proc unnecessaryIndirection(n: PNode): bool =
|
||||
proc unneededIndirection(n: PNode): bool =
|
||||
n.typ.skipTypes(abstractInst).kind == tyRef
|
||||
|
||||
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]
|
||||
else:
|
||||
result = n
|
||||
|
||||
proc genAddrDeref(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
|
||||
# a nop for certain types
|
||||
if unnecessaryIndirection(n):
|
||||
if unneededIndirection(n.sons[0]):
|
||||
gen(c, n.sons[0], dest)
|
||||
else:
|
||||
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)
|
||||
|
||||
proc genLit(c: PCtx; n: PNode; dest: var TDest) =
|
||||
var opc = opcLdConst
|
||||
if dest < 0: dest = c.getTemp(n.typ)
|
||||
elif c.prc.slots[dest].kind == slotFixedVar: opc = opcAsgnConst
|
||||
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) =
|
||||
let s = n.sym
|
||||
@@ -775,7 +814,10 @@ proc genObjAccess(c: PCtx; n: PNode; dest: var TDest) =
|
||||
genAccess(c, n, dest, opcLdObj)
|
||||
|
||||
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 getNullValueAux(obj: PNode, result: PNode) =
|
||||
@@ -827,7 +869,8 @@ proc setSlot(c: PCtx; v: PSym) =
|
||||
# XXX generate type initialization here?
|
||||
if v.position == 0:
|
||||
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
|
||||
|
||||
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
|
||||
discard genProc(c, s)
|
||||
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,
|
||||
nkTemplateDef, nkIncludeStmt, nkImportStmt:
|
||||
unused(n, dest)
|
||||
of nkStringToCString, nkCStringToString:
|
||||
gen(c, n.sons[0], dest)
|
||||
else:
|
||||
#of nkCurly, nkBracket, nkPar:
|
||||
InternalError n.info, "too implement " & $n.kind
|
||||
|
||||
proc genStmt*(c: PCtx; n: PNode): int =
|
||||
result = c.code.len
|
||||
var d: TDest = -1
|
||||
gen(c, n, d)
|
||||
proc removeLastEof(c: PCtx) =
|
||||
let last = c.code.len-1
|
||||
if last >= 0 and c.code[last].opcode == opcEof:
|
||||
# since we can re-use the EOF nothing happened:
|
||||
result = last
|
||||
else:
|
||||
gABC(c, n, opcEof)
|
||||
# overwrite last EOF:
|
||||
assert c.code.len == c.debug.len
|
||||
c.code.setLen(last)
|
||||
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
|
||||
|
||||
proc genParams(c: PCtx; params: PNode) =
|
||||
# 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:
|
||||
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)
|
||||
|
||||
proc genProc(c: PCtx; s: PSym): int =
|
||||
let x = s.ast.sons[optimizedCodePos]
|
||||
if x.kind == nkEmpty:
|
||||
c.removeLastEof
|
||||
result = c.code.len+1 # skip the jump instruction
|
||||
s.ast.sons[optimizedCodePos] = newIntNode(nkIntLit, result)
|
||||
# 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:
|
||||
c.gABC(body, opcRet)
|
||||
c.patch(procStart)
|
||||
c.gABC(body, opcEof)
|
||||
s.position = c.prc.maxSlots
|
||||
c.prc = oldPrc
|
||||
else:
|
||||
|
||||
Reference in New Issue
Block a user