mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-28 08:54:53 +00:00
VM: refactoring [backport] (#25280)
Note to @narimiran backport because IC requires it.
This commit is contained in:
@@ -480,9 +480,9 @@ proc opConv(c: PCtx; dest: var TFullReg, src: TFullReg, desttyp, srctyp: PType):
|
||||
else:
|
||||
asgnComplex(dest, src)
|
||||
|
||||
proc compile(c: PCtx, s: PSym): int =
|
||||
proc compile(c: PCtx, s: PSym): VmProcInfo =
|
||||
result = vmgen.genProc(c, s)
|
||||
when debugEchoCode: c.echoCode result
|
||||
when debugEchoCode: c.echoCode result.pc
|
||||
#c.echoCode
|
||||
|
||||
template handleJmpBack() {.dirty.} =
|
||||
@@ -1435,13 +1435,13 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
else:
|
||||
globalError(c.config, c.debug[pc], "VM not built with FFI support")
|
||||
elif prc.kind != skTemplate:
|
||||
let newPc = compile(c, prc)
|
||||
let procInfo = compile(c, prc)
|
||||
# tricky: a recursion is also a jump back, so we use the same
|
||||
# logic as for loops:
|
||||
if newPc < pc: handleJmpBack()
|
||||
if procInfo.pc < pc: handleJmpBack()
|
||||
#echo "new pc ", newPc, " calling: ", prc.name.s
|
||||
var newFrame = PStackFrame(prc: prc, comesFrom: pc, next: tos)
|
||||
newSeq(newFrame.slots, prc.offset+ord(isClosure))
|
||||
newSeq(newFrame.slots, procInfo.usedRegisters+ord(isClosure))
|
||||
# setup slot for proc result:
|
||||
let ret {.cursor.} = prc.typ.returnType
|
||||
# hot spot ahead!
|
||||
@@ -1467,7 +1467,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
tos = newFrame
|
||||
updateRegsAlias
|
||||
# -1 for the following 'inc pc'
|
||||
pc = newPc-1
|
||||
pc = procInfo.pc-1
|
||||
else:
|
||||
# for 'getAst' support we need to support template expansion here:
|
||||
let genSymOwner = if tos.next != nil and tos.next.prc != nil:
|
||||
@@ -2351,8 +2351,7 @@ proc execProc*(c: PCtx; sym: PSym; args: openArray[PNode]): PNode =
|
||||
let start = genProc(c, sym)
|
||||
|
||||
var tos = PStackFrame(prc: sym, comesFrom: 0, next: nil)
|
||||
let maxSlots = sym.offset
|
||||
newSeq(tos.slots, maxSlots)
|
||||
newSeq(tos.slots, start.usedRegisters)
|
||||
|
||||
# setup parameters:
|
||||
if not isEmptyType(sym.typ.returnType) or sym.kind == skMacro:
|
||||
@@ -2361,7 +2360,7 @@ proc execProc*(c: PCtx; sym: PSym; args: openArray[PNode]): PNode =
|
||||
for i in 0..<sym.typ.paramsLen:
|
||||
putIntoReg(tos.slots[i+1], args[i])
|
||||
|
||||
result = rawExecute(c, start, tos).regToNode
|
||||
result = rawExecute(c, start.pc, tos).regToNode
|
||||
else:
|
||||
result = nil
|
||||
localError(c.config, sym.info,
|
||||
@@ -2550,8 +2549,7 @@ proc evalMacroCall*(module: PSym; idgen: IdGenerator; g: ModuleGraph; templInstC
|
||||
return errorNode(idgen, module, n)
|
||||
|
||||
var tos = PStackFrame(prc: sym, comesFrom: 0, next: nil)
|
||||
let maxSlots = sym.offset
|
||||
newSeq(tos.slots, maxSlots)
|
||||
newSeq(tos.slots, start.usedRegisters)
|
||||
# setup arguments:
|
||||
var L = n.safeLen
|
||||
if L == 0: L = 1
|
||||
@@ -2578,7 +2576,7 @@ proc evalMacroCall*(module: PSym; idgen: IdGenerator; g: ModuleGraph; templInstC
|
||||
" generic parameter(s)")
|
||||
# temporary storage:
|
||||
#for i in L..<maxSlots: tos.slots[i] = newNode(nkEmpty)
|
||||
result = rawExecute(c, start, tos).regToNode
|
||||
result = rawExecute(c, start.pc, tos).regToNode
|
||||
if result.info.line < 0: result.info = n.info
|
||||
if cyclicTree(result): globalError(c.config, n.info, "macro produced a cyclic tree")
|
||||
dec(g.config.evalMacroCounter)
|
||||
|
||||
@@ -243,6 +243,11 @@ type
|
||||
VmCallback* = proc (args: VmArgs) {.closure.}
|
||||
|
||||
PCtx* = ref TCtx
|
||||
|
||||
VmProcInfo* = object
|
||||
pc*: int32
|
||||
usedRegisters*: int32
|
||||
|
||||
TCtx* = object of TPassContext # code gen context
|
||||
code*: seq[TInstr]
|
||||
debug*: seq[TLineInfo] # line info for every instruction; kept separate
|
||||
@@ -271,7 +276,7 @@ type
|
||||
profiler*: Profiler
|
||||
templInstCounter*: ref int # gives every template instantiation a unique ID, needed here for getAst
|
||||
vmstateDiff*: seq[(PSym, PNode)] # we remember the "diff" to global state here (feature for IC)
|
||||
procToCodePos*: Table[int, int]
|
||||
procToCodePos*: Table[int, VmProcInfo]
|
||||
cannotEval*: bool
|
||||
locals*: IntSet
|
||||
|
||||
@@ -293,6 +298,9 @@ type
|
||||
|
||||
PEvalContext* = PCtx
|
||||
|
||||
const
|
||||
NoVmProcInfo* = VmProcInfo(pc: 0'i32, usedRegisters: -1'i32)
|
||||
|
||||
proc newCtx*(module: PSym; cache: IdentCache; g: ModuleGraph; idgen: IdGenerator): PCtx =
|
||||
PCtx(code: @[], debug: @[],
|
||||
globals: newNode(nkStmtListExpr), constants: newNode(nkStmtList), types: @[],
|
||||
|
||||
@@ -2128,7 +2128,7 @@ proc genTupleConstr(c: PCtx, n: PNode, dest: var TDest) =
|
||||
c.preventFalseAlias(it, opcWrObj, dest, i.TRegister, tmp)
|
||||
c.freeTemp(tmp)
|
||||
|
||||
proc genProc*(c: PCtx; s: PSym): int
|
||||
proc genProc*(c: PCtx; s: PSym): VmProcInfo
|
||||
|
||||
proc toKey(s: PSym): string =
|
||||
result = ""
|
||||
@@ -2412,27 +2412,19 @@ proc optimizeJumps(c: PCtx; start: int) =
|
||||
c.finalJumpTarget(i, d - i)
|
||||
else: discard
|
||||
|
||||
proc genProc(c: PCtx; s: PSym): int =
|
||||
let
|
||||
pos = c.procToCodePos.getOrDefault(s.id)
|
||||
wasNotGenProcBefore = pos == 0
|
||||
noRegistersAllocated = s.offset == -1
|
||||
if wasNotGenProcBefore or noRegistersAllocated:
|
||||
# xxx: the noRegisterAllocated check is required in order to avoid issues
|
||||
# where nimsuggest can crash due as a macro with pos will be loaded
|
||||
# but it doesn't have offsets for register allocations see:
|
||||
# https://github.com/nim-lang/Nim/issues/18385
|
||||
# Improvements and further use of IC should remove the need for this.
|
||||
proc genProc(c: PCtx; s: PSym): VmProcInfo =
|
||||
result = c.procToCodePos.getOrDefault(s.id, NoVmProcInfo)
|
||||
if result.usedRegisters < 0:
|
||||
#if s.name.s == "outterMacro" or s.name.s == "innerProc":
|
||||
# echo "GENERATING CODE FOR ", s.name.s
|
||||
let last = c.code.len-1
|
||||
var eofInstr: TInstr = default(TInstr)
|
||||
var eofInstr = default(TInstr)
|
||||
if last >= 0 and c.code[last].opcode == opcEof:
|
||||
eofInstr = c.code[last]
|
||||
c.code.setLen(last)
|
||||
c.debug.setLen(last)
|
||||
#c.removeLastEof
|
||||
result = c.code.len+1 # skip the jump instruction
|
||||
result.pc = (c.code.len+1).int32 # skip the jump instruction
|
||||
c.procToCodePos[s.id] = result
|
||||
# thanks to the jmp we can add top level statements easily and also nest
|
||||
# procs easily:
|
||||
@@ -2457,12 +2449,12 @@ proc genProc(c: PCtx; s: PSym): int =
|
||||
c.gABC(body, opcRet)
|
||||
c.patch(procStart)
|
||||
c.gABC(body, opcEof, eofInstr.regA)
|
||||
c.optimizeJumps(result)
|
||||
s.offset = c.prc.regInfo.len.int32
|
||||
c.optimizeJumps(result.pc)
|
||||
result.usedRegisters = c.prc.regInfo.len.int32
|
||||
c.procToCodePos[s.id] = result
|
||||
#if s.name.s == "main" or s.name.s == "[]":
|
||||
# echo renderTree(body)
|
||||
# c.echoCode(result)
|
||||
c.prc = oldPrc
|
||||
else:
|
||||
c.prc.regInfo.setLen s.offset
|
||||
result = pos
|
||||
c.prc.regInfo.setLen result.usedRegisters
|
||||
|
||||
Reference in New Issue
Block a user