IC progress (#25283)

bugfix: produce the required nimcache subdir
This commit is contained in:
Andreas Rumpf
2025-11-25 12:49:23 +01:00
committed by GitHub
parent 6543040d40
commit 0486a2df51
16 changed files with 360 additions and 170 deletions

View File

@@ -57,6 +57,16 @@ proc ensureMutable*(t: PType) {.inline.} =
assert t.state != Sealed
if t.state == Partial: loadType(t)
proc backendEnsureMutable*(s: PSym) {.inline.} =
#assert s.state != Sealed
# ^ IC review this later
if s.state == Partial: loadSym(s)
proc backendEnsureMutable*(t: PType) {.inline.} =
#assert t.state != Sealed
# ^ IC review this later
if t.state == Partial: loadType(t)
proc owner*(s: PSym): PSym {.inline.} =
if s.state == Partial: loadSym(s)
result = s.ownerFieldImpl

View File

@@ -13,7 +13,7 @@ import std / [assertions, tables, sets]
from std / strutils import startsWith
import astdef, idents, msgs, options
import lineinfos as astli
import pathutils
import pathutils #, modulegraphs
import "../dist/nimony/src/lib" / [bitabs, nifstreams, nifcursors, lineinfos,
nifindexes, nifreader]
import "../dist/nimony/src/gear2" / modnames
@@ -258,6 +258,10 @@ proc writeLib(w: var Writer; dest: var TokenBuf; lib: PLib) =
proc writeSymDef(w: var Writer; dest: var TokenBuf; sym: PSym) =
dest.addParLe sdefTag, trLineInfo(w, sym.infoImpl)
dest.addSymDef pool.syms.getOrIncl(w.toNifSymName(sym)), NoLineInfo
if sfExported in sym.flagsImpl:
dest.addIdent "x"
else:
dest.addDotToken
if sym.magicImpl == mNone:
dest.addDotToken
else:
@@ -352,14 +356,14 @@ proc trInclude(w: var Writer; n: PNode) =
w.deps.addParRi
proc trImport(w: var Writer; n: PNode) =
w.deps.addParLe pool.tags.getOrIncl(toNifTag(n.kind)), trLineInfo(w, n.info)
for child in n:
assert child.kind == nkSym
let s = child.sym
assert s.kindImpl == skModule
let fp = toFullPath(w.infos.config, s.positionImpl.FileIndex)
w.deps.addStrLit fp
w.deps.addParRi
if child.kind == nkSym:
w.deps.addParLe pool.tags.getOrIncl(toNifTag(n.kind)), trLineInfo(w, n.info)
let s = child.sym
assert s.kindImpl == skModule
let fp = toFullPath(w.infos.config, s.positionImpl.FileIndex)
w.deps.addStrLit fp
w.deps.addParRi
proc writeNode(w: var Writer; dest: var TokenBuf; n: PNode) =
if n == nil:
@@ -421,6 +425,7 @@ proc writeNode(w: var Writer; dest: var TokenBuf; n: PNode) =
var ast = n
if n[namePos].kind == nkSym:
ast = n[namePos].sym.astImpl
if ast == nil: ast = n
w.withNode dest, ast:
# Process body and other parts
for i in 0 ..< ast.len:
@@ -463,7 +468,8 @@ proc writeNifModule*(config: ConfigRef; thisModule: int32; n: PNode) =
inner.addParRi()
let m = modname(w.moduleToNifSuffix, w.currentModule, w.infos.config)
let d = toGeneratedFile(config, AbsoluteFile(m), ".nif").string
let nifFilename = AbsoluteFile(m).changeFileExt(".nif")
let d = completeGeneratedFilePath(config, nifFilename).string
var dest = createTokenBuf(600)
dest.addParLe pool.tags.getOrIncl(toNifTag(nkStmtList)), rootInfo
@@ -472,7 +478,8 @@ proc writeNifModule*(config: ConfigRef; thisModule: int32; n: PNode) =
dest.add inner
dest.addParRi()
writeFileAndIndex d, dest
writeFile(dest, d)
createIndex(d, false, dest[0].info)
# --------------------------- Loader (lazy!) -----------------------------------------------
@@ -536,48 +543,37 @@ type
DecodeContext* = object
infos: LineInfoWriter
moduleIds: Table[string, int32]
#moduleIds: Table[string, int32]
types: Table[ItemId, (PType, NifIndexEntry)]
syms: Table[ItemId, (PSym, NifIndexEntry)]
mods: seq[NifModule]
cache: IdentCache
moduleToNifSuffix: Table[FileIndex, string]
#moduleToNifSuffix: Table[FileIndex, string]
proc createDecodeContext*(config: ConfigRef; cache: IdentCache): DecodeContext =
## Supposed to be a global variable
result = DecodeContext(infos: LineInfoWriter(config: config), cache: cache)
proc idToIdx(x: int32): int {.inline.} =
assert x <= -2'i32
result = -(x+2)
proc cursorFromIndexEntry(c: var DecodeContext; module: int32; entry: NifIndexEntry;
proc cursorFromIndexEntry(c: var DecodeContext; module: FileIndex; entry: NifIndexEntry;
buf: var TokenBuf): Cursor =
let m = idToIdx(module)
let s = addr c.mods[m].stream
let s = addr c.mods[module.int32].stream
s.r.jumpTo entry.offset
var buf = createTokenBuf(30)
nifcursors.parse(s[], buf, entry.info)
result = cursorAt(buf, 0)
proc moduleId(c: var DecodeContext; suffix: string): int32 =
# We don't know the "real" FileIndex due to our mapping to a short "Module suffix"
# This is not a problem, we use negative `ItemId.module` values here and then
# there is no interference with in-memory-modules. Modulegraphs.nim already uses -1
# so we start at -2 here.
result = c.moduleIds.getOrDefault(suffix)
if result == 0:
result = -int32(c.moduleIds.len + 2) # negative index!
proc moduleId(c: var DecodeContext; suffix: string): FileIndex =
var isKnownFile = false
result = c.infos.config.registerNifSuffix(suffix, isKnownFile)
if not isKnownFile:
let modFile = (getNimcacheDir(c.infos.config) / RelativeFile(suffix & ".nif")).string
let idxFile = (getNimcacheDir(c.infos.config) / RelativeFile(suffix & ".idx.nif")).string
c.moduleIds[suffix] = result
c.mods.add NifModule(stream: nifstreams.open(modFile), index: readIndex(idxFile))
assert c.mods.len-1 == idToIdx(result)
if result.int >= c.mods.len:
c.mods.setLen(result.int + 1)
c.mods[result.int] = NifModule(stream: nifstreams.open(modFile), index: readIndex(idxFile))
proc getOffset(c: var DecodeContext; module: int32; nifName: string): NifIndexEntry =
assert module < 0'i32
let index = idToIdx(module)
let ii = addr c.mods[index].index
proc getOffset(c: var DecodeContext; module: FileIndex; nifName: string): NifIndexEntry =
let ii = addr c.mods[module.int32].index
result = ii.public.getOrDefault(nifName)
if result.offset == 0:
result = ii.private.getOrDefault(nifName)
@@ -601,10 +597,10 @@ proc loadTypeStub(c: var DecodeContext; t: SymId): PType =
inc i
if i < name.len and name[i] == '.': inc i
let suffix = name.substr(i)
let id = ItemId(module: moduleId(c, suffix), item: itemId)
let id = ItemId(module: moduleId(c, suffix).int32, item: itemId)
result = c.types.getOrDefault(id)[0]
if result == nil:
let offs = c.getOffset(id.module, name)
let offs = c.getOffset(id.module.FileIndex, name)
result = PType(itemId: id, uniqueId: id, kind: TTypeKind(k), state: Partial)
c.types[id] = (result, offs)
@@ -627,10 +623,10 @@ proc loadSymStub(c: var DecodeContext; t: SymId): PSym =
let symAsStr = pool.syms[t]
let sn = parseSymName(symAsStr)
let module = moduleId(c, sn.module)
let val = addr c.mods[idToIdx(module)].symCounter
let val = addr c.mods[module.int32].symCounter
inc val[]
let id = ItemId(module: module, item: val[])
let id = ItemId(module: module.int32, item: val[])
result = c.syms.getOrDefault(id)[0]
if result == nil:
let offs = c.getOffset(module, symAsStr)
@@ -696,7 +692,7 @@ proc loadType*(c: var DecodeContext; t: PType) =
if t.state != Partial: return
t.state = Sealed
var buf = createTokenBuf(30)
var n = cursorFromIndexEntry(c, t.itemId.module, c.types[t.itemId][1], buf)
var n = cursorFromIndexEntry(c, t.itemId.module.FileIndex, c.types[t.itemId][1], buf)
expect n, ParLe
if n.tagId != tdefTag:
@@ -745,7 +741,7 @@ proc loadSym*(c: var DecodeContext; s: PSym) =
if s.state != Partial: return
s.state = Sealed
var buf = createTokenBuf(30)
var n = cursorFromIndexEntry(c, s.itemId.module, c.syms[s.itemId][1], buf)
var n = cursorFromIndexEntry(c, s.itemId.module.FileIndex, c.syms[s.itemId][1], buf)
expect n, ParLe
if n.tagId != sdefTag:
@@ -754,6 +750,17 @@ proc loadSym*(c: var DecodeContext; s: PSym) =
expect n, SymbolDef
# ignore the symbol's name, we have already used it to create this PSym instance!
inc n
if n.kind == Ident:
if pool.strings[n.litId] == "x":
s.flagsImpl.incl sfExported
inc n
else:
raiseAssert "expected `x` as the export marker"
elif n.kind == DotToken:
inc n
else:
raiseAssert "expected `x` or '.' but got " & $n.kind
loadField s.magicImpl
loadField s.flagsImpl
loadField s.optionsImpl
@@ -894,20 +901,20 @@ proc loadNode(c: var DecodeContext; n: var Cursor): PNode =
else:
raiseAssert "Not yet implemented " & $n.kind
when false:
proc loadNifModule*(c: var DecodeContext; f: FileIndex): PNode =
let moduleSuffix = moduleSuffix(c.infos.config, f)
let modFile = toGeneratedFile(c.infos.config, AbsoluteFile(moduleSuffix), ".nif").string
proc loadNifModule*(c: var DecodeContext; f: FileIndex): PNode =
let moduleSuffix = modname(c.moduleToNifSuffix, f.int, c.infos.config)
let modFile = toGeneratedFile(c.infos.config, AbsoluteFile(moduleSuffix), ".nif").string
var buf = createTokenBuf(300)
var s = nifstreams.open(modFile)
# XXX We can optimize this here and only load the top level entries!
try:
nifcursors.parse(s, buf, NoLineInfo)
finally:
nifstreams.close(s)
var n = cursorAt(buf, 0)
result = loadNode(c, n)
var buf = createTokenBuf(300)
var s = nifstreams.open(modFile)
# XXX We can optimize this here and only load the top level entries!
try:
nifcursors.parse(s, buf, NoLineInfo)
finally:
nifstreams.close(s)
var n = cursorAt(buf, 0)
result = loadNode(c, n)
when isMainModule:
import std / syncio

View File

@@ -170,7 +170,7 @@ proc canMove(p: BProc, n: PNode; dest: TLoc): bool =
template simpleAsgn(builder: var Builder, dest, src: TLoc) =
let rd = rdLoc(dest)
let rs = rdLoc(src)
builder.addAssignment(rd, rs)
builder.addAssignment(rd, rs)
proc genRefAssign(p: BProc, dest, src: TLoc) =
if (dest.storage == OnStack and p.config.selectedGC != gcGo) or not usesWriteBarrier(p.config):
@@ -675,7 +675,7 @@ proc binaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
if e[2].kind in {nkIntLit..nkInt64Lit}:
needsOverflowCheck = e[2].intVal == -1
if canBeZero:
# remove extra paren from `==` op here to avoid Wparentheses-equality:
# remove extra paren from `==` op here to avoid Wparentheses-equality:
p.s(cpsStmts).addSingleIfStmt(removeSinglePar(cOp(Equal, rdLoc(b), cIntValue(0)))):
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "raiseDivByZero"))
raiseInstr(p, p.s(cpsStmts))
@@ -696,7 +696,7 @@ proc unaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
let ra = rdLoc(a)
if optOverflowCheck in p.options:
let first = cIntLiteral(firstOrd(p.config, t))
# remove extra paren from `==` op here to avoid Wparentheses-equality:
# remove extra paren from `==` op here to avoid Wparentheses-equality:
p.s(cpsStmts).addSingleIfStmt(removeSinglePar(cOp(Equal, ra, first))):
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "raiseOverflow"))
raiseInstr(p, p.s(cpsStmts))
@@ -3435,7 +3435,7 @@ proc genConstDefinition(q: BModule; p: BProc; sym: PSym) =
proc genConstStmt(p: BProc, n: PNode) =
# This code is only used in the new DCE implementation.
assert useAliveDataFromDce in p.module.flags
assert delayedCodegen(p.module)
let m = p.module
for it in n:
if it[0].kind == nkSym:
@@ -3453,7 +3453,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
var sym = n.sym
case sym.kind
of skMethod:
if useAliveDataFromDce in p.module.flags or {sfDispatcher, sfForward} * sym.flags != {}:
if delayedCodegen(p.module) or {sfDispatcher, sfForward} * sym.flags != {}:
# we cannot produce code for the dispatcher yet:
fillProcLoc(p.module, n)
genProcPrototype(p.module, sym)
@@ -3466,7 +3466,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
if sfCompileTime in sym.flags:
localError(p.config, n.info, "request to generate code for .compileTime proc: " &
sym.name.s)
if useAliveDataFromDce in p.module.flags and sym.typ.callConv != ccInline:
if delayedCodegen(p.module) and sym.typ.callConv != ccInline:
fillProcLoc(p.module, n)
genProcPrototype(p.module, sym)
else:
@@ -3479,7 +3479,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
var lit = newBuilder("")
genLiteral(p, sym.astdef, sym.typ, lit)
putIntoDest(p, d, n, extract(lit), OnStatic)
elif useAliveDataFromDce in p.module.flags:
elif delayedCodegen(p.module):
genConstHeader(p.module, p.module, p, sym)
assert((sym.loc.snippet != "") and (sym.loc.t != nil))
putLocIntoDest(p, d, sym.loc)
@@ -3611,7 +3611,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
of nkWhileStmt: genWhileStmt(p, n)
of nkVarSection, nkLetSection: genVarStmt(p, n)
of nkConstSection:
if useAliveDataFromDce in p.module.flags:
if delayedCodegen(p.module):
genConstStmt(p, n)
else: # enforce addressable consts for exportc
let m = p.module
@@ -3677,7 +3677,10 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
of nkProcDef, nkFuncDef, nkMethodDef, nkConverterDef:
if n[genericParamsPos].kind == nkEmpty:
var prc = n[namePos].sym
if useAliveDataFromDce in p.module.flags:
if optCompress in p.config.globalOptions:
if prc.magic in generatedMagics:
genProc(p.module, prc)
elif delayedCodegen(p.module):
if p.module.alive.contains(prc.itemId.item) and
prc.magic in generatedMagics:
genProc(p.module, prc)

View File

@@ -366,6 +366,7 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
if v.flags * {sfImportc, sfExportc} == {sfImportc} and
value.kind == nkEmpty and
v.loc.flags * {lfHeader, lfNoDecl} != {}:
# IC XXX: this is bad, we should set v.loc regardless here
return
if sfPure in v.flags:
# v.owner.kind != skModule:
@@ -461,7 +462,7 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
if value.kind != nkEmpty and valueAsRope.len == 0:
genLineDir(targetProc, vn)
if not isCppCtorCall:
ensureMutable v
backendEnsureMutable v
loadInto(targetProc, vn, value, v.locImpl)
if forHcr:
endBlockWith(targetProc):

View File

@@ -108,7 +108,7 @@ proc fillParamName(m: BModule; s: PSym) =
# and a function called in main or proxy uses `socket` as a parameter name.
# That would lead to either needing to reload `proxy` or to overwrite the
# executable file for the main module, which is running (or both!) -> error.
ensureMutable s
backendEnsureMutable s
s.locImpl.snippet = res.rope
proc fillLocalName(p: BProc; s: PSym) =
@@ -158,8 +158,8 @@ proc getTypeName(m: BModule; typ: PType; sig: SigHash): Rope =
else:
break
let typ = if typ.kind in {tyAlias, tySink, tyOwned}: typ.elementType else: typ
ensureMutable typ
if typ.loc.snippet == "":
backendEnsureMutable typ
typ.typeName(typ.locImpl.snippet)
typ.locImpl.snippet.add $sig
else:
@@ -608,7 +608,7 @@ proc genProcParams(m: BModule; t: PType, rettype: var Rope, params: var Builder,
else:
descKind = dkRefParam
if isCompileTimeOnly(param.typ): continue
ensureMutable param
backendEnsureMutable param
fillParamName(m, param)
fillLoc(param.locImpl, locParam, t.n[i],
param.paramStorageLoc)
@@ -715,7 +715,7 @@ proc genRecordFieldsAux(m: BModule; n: PNode,
if field.typ.kind == tyVoid: return
#assert(field.ast == nil)
let sname = mangleRecFieldName(m, field)
ensureMutable field
backendEnsureMutable field
fillLoc(field.locImpl, locField, n, unionPrefix & sname, OnUnknown)
# for importcpp'ed objects, we only need to set field.loc, but don't
# have to recurse via 'getTypeDescAux'. And not doing so prevents problems
@@ -1212,7 +1212,7 @@ proc genProcHeader(m: BModule; prc: PSym; result: var Builder; visibility: var D
# using static is needed for inline procs
var check = initIntSet()
fillBackendName(m, prc)
ensureMutable prc
backendEnsureMutable prc
fillLoc(prc.locImpl, locProc, prc.ast[namePos], OnUnknown)
var rettype: Snippet = ""
var desc = newBuilder("")
@@ -2054,17 +2054,21 @@ proc genTypeInfo*(config: ConfigRef, m: BModule; t: PType; info: TLineInfo): Rop
else:
result = genTypeInfoV1(m, t, info)
proc retrieveSym(n: PNode): PSym =
case n.kind
of nkPostfix: result = retrieveSym(n[1])
of nkPragmaExpr, nkTypeDef: result = retrieveSym(n[0])
of nkSym: result = n.sym
else: result = nil
proc genTypeSection(m: BModule, n: PNode) =
var intSet = initIntSet()
for i in 0..<n.len:
if len(n[i]) == 0: continue
if n[i][0].kind != nkPragmaExpr: continue
for p in 0..<n[i][0].len:
if (n[i][0][p].kind notin {nkSym, nkPostfix}): continue
var s = n[i][0][p]
if s.kind == nkPostfix:
s = n[i][0][p][1]
if {sfExportc, sfCompilerProc} * s.sym.flags == {sfExportc}:
discard getTypeDescAux(m, s.typ, intSet, descKindFromSymKind(s.sym.kind))
if m.g.generatedHeader != nil:
discard getTypeDescAux(m.g.generatedHeader, s.typ, intSet, descKindFromSymKind(s.sym.kind))
let compress = optCompress in m.config.globalOptions
for typedef in n:
let s = retrieveSym(typedef)
if s != nil and ({sfExportc, sfCompilerProc} * s.flags == {sfExportc} or compress) and s.typ != nil and
not containsGenericType(s.typ) and
s.typ.kind notin {tyVoid, tyNot, tyAnything, tyOr, tyAnd, tyUntyped, tyTyped, tyNone, tyNil, tySink}:
discard getTypeDescAux(m, s.typ, intSet, descKindFromSymKind(s.kind))
if m.g.generatedHeader != nil:
discard getTypeDescAux(m.g.generatedHeader, s.typ, intSet, descKindFromSymKind(s.kind))

View File

@@ -63,7 +63,7 @@ proc addForwardedProc(m: BModule, prc: PSym) =
proc findPendingModule(m: BModule, s: PSym): BModule =
# TODO fixme
if m.config.symbolFiles == v2Sf:
if m.config.symbolFiles == v2Sf or optCompress in m.config.globalOptions:
let ms = s.itemId.module #getModule(s)
result = m.g.modules[ms]
else:
@@ -506,7 +506,7 @@ include ccgreset
proc resetLoc(p: BProc, loc: var TLoc) =
let containsGcRef = optSeqDestructors notin p.config.globalOptions and containsGarbageCollectedRef(loc.t)
let typ = skipTypes(loc.t, abstractVarRange)
if isImportedCppType(typ):
if isImportedCppType(typ):
var didGenTemp = false
let rl = rdLoc(loc)
let init = genCppInitializer(p.module, p, typ, didGenTemp)
@@ -600,7 +600,7 @@ proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
# ``var v = X()`` gets transformed into ``X(&v)``.
# Nowadays the logic in ccgcalls deals with this case however.
if not immediateAsgn:
ensureMutable v
backendEnsureMutable v
constructLoc(p, v.locImpl)
proc getTemp(p: BProc, t: PType, needsInit=false): TLoc =
@@ -785,7 +785,7 @@ proc fillProcLoc(m: BModule; n: PNode) =
let sym = n.sym
if sym.loc.k == locNone:
fillBackendName(m, sym)
ensureMutable sym
backendEnsureMutable sym
fillLoc(sym.locImpl, locProc, n, OnStack)
proc getLabel(p: BProc): TLabel =
@@ -1362,7 +1362,8 @@ proc genProcAux*(m: BModule, prc: PSym) =
closureSetup(p, prc)
genProcBody(p, procBody)
prc.info = tmpInfo
# IC: spurious write, seems fine for now:
prc.infoImpl = tmpInfo
var generatedProc = newBuilder("")
generatedProc.genCLineDir prc.info, m.config
@@ -1445,6 +1446,8 @@ proc genProcPrototype(m: BModule, sym: PSym) =
getModuleDllPath(m, sym),
'"' & name & '"')
elif not containsOrIncl(m.declaredProtos, sym.id):
if optCompress in m.config.globalOptions:
m.queue.add(sym)
let asPtr = isReloadable(m, sym)
var header = newBuilder("")
var visibility: DeclVisibility = None
@@ -1464,6 +1467,8 @@ proc genProcPrototype(m: BModule, sym: PSym) =
m.s[cfsProcHeaders].add(extract(header))
m.s[cfsProcHeaders].finishProcHeaderAsProto()
include inliner
# TODO: figure out how to rename this - it DOES generate a forward declaration
proc genProcNoForward(m: BModule, prc: PSym) =
if lfImportCompilerProc in prc.loc.flags:
@@ -1502,16 +1507,22 @@ proc genProcNoForward(m: BModule, prc: PSym) =
#if prc.loc.k == locNone:
# mangle the inline proc based on the module where it is defined -
# not on the first module that uses it
let m2 = if m.config.symbolFiles != disabledSf: m
else: findPendingModule(m, prc)
fillProcLoc(m2, prc.ast[namePos])
#elif {sfExportc, sfImportc} * prc.flags == {}:
# # reset name to restore consistency in case of hashing collisions:
# echo "resetting ", prc.id, " by ", m.module.name.s
# prc.loc.snippet = nil
# prc.loc.snippet = mangleName(m, prc)
genProcPrototype(m, prc)
genProcAux(m, prc)
if m.module.itemId.module != prc.itemId.module and optCompress in m.config.globalOptions:
let prcCopy = copyInlineProc(prc, m.idgen)
fillProcLoc(m, prcCopy.ast[namePos])
genProcPrototype(m, prcCopy)
genProcAux(m, prcCopy)
else:
let m2 = if m.config.symbolFiles != disabledSf: m
else: findPendingModule(m, prc)
fillProcLoc(m2, prc.ast[namePos])
#elif {sfExportc, sfImportc} * prc.flags == {}:
# # reset name to restore consistency in case of hashing collisions:
# echo "resetting ", prc.id, " by ", m.module.name.s
# prc.loc.snippet = nil
# prc.loc.snippet = mangleName(m, prc)
genProcPrototype(m, prc)
genProcAux(m, prc)
elif sfImportc notin prc.flags:
var q = findPendingModule(m, prc)
fillProcLoc(q, prc.ast[namePos])
@@ -1571,7 +1582,7 @@ proc genVarPrototype(m: BModule, n: PNode) =
let sym = n.sym
useHeader(m, sym)
fillBackendName(m, sym)
ensureMutable sym
backendEnsureMutable sym
fillLoc(sym.locImpl, locGlobalVar, n, OnHeap)
if treatGlobalDifferentlyForHCR(m, sym): incl(sym, lfIndirect)
@@ -2509,6 +2520,11 @@ proc writeModule(m: BModule, pending: bool) =
let cfile = getCFile(m)
if moduleHasChanged(m.g.graph, m.module):
genInitCode(m)
while m.queue.len > 0:
let sym = m.queue.pop()
genProcAux(m, sym)
finishTypeDescriptions(m)
if sfMainModule in m.module.flags:
# generate main file:

View File

@@ -119,7 +119,7 @@ type
mapping*: Rope # the generated mapping file (if requested)
modules*: seq[BModule] # list of all compiled modules
modulesClosed*: seq[BModule] # list of the same compiled modules, but in the order they were closed
forwardedProcs*: seq[PSym] # proc:s that did not yet have a body
forwardedProcs*: seq[PSym] # procs that did not yet have a body
generatedHeader*: BModule
typeInfoMarker*: TypeCacheWithOwner
typeInfoMarkerV2*: TypeCacheWithOwner
@@ -155,6 +155,7 @@ type
forwTypeCache*: TypeCache # cache for forward declarations of types
declaredThings*: IntSet # things we have declared in this .c file
declaredProtos*: IntSet # prototypes we have declared in this .c file
queue*: seq[PSym] # queue of procs to generate
alive*: IntSet # symbol IDs of alive data as computed by `dce.nim`
headerFiles*: seq[string] # needed headers to include
typeInfoMarker*: TypeCache # needed for generating type information
@@ -178,6 +179,9 @@ template config*(m: BModule): ConfigRef = m.g.config
template config*(p: BProc): ConfigRef = p.module.g.config
template vccAndC*(p: BProc): bool = p.module.config.cCompiler == ccVcc and p.module.config.backend == backendC
proc delayedCodegen*(m: BModule): bool {.inline.} =
useAliveDataFromDce in m.flags or m.config.globalOptions.contains(optCompress)
proc includeHeader*(this: BModule; header: string) =
if not this.headerFiles.contains header:
this.headerFiles.add header

122
compiler/inliner.nim Normal file
View File

@@ -0,0 +1,122 @@
proc copySymdef(n: PNode; locals: var Table[int, PSym]; idgen: IdGenerator; owner: PSym): PNode =
case n.kind
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit:
result = n
of nkSym:
let oldSym = n.sym
let newSym = copySym(oldSym, idgen)
setOwner(newSym, owner)
locals[oldSym.id] = newSym
result = newSymNode(newSym, oldSym.info)
else:
result = shallowCopy(n)
for i in 0..<n.len:
result[i] = copySymdef(n[i], locals, idgen, owner)
proc copyInlineProcBody(n: PNode; locals: var Table[int, PSym]; idgen: IdGenerator; owner: PSym): PNode =
case n.kind
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit:
result = n
of nkSym:
let sym = locals.getOrDefault(n.sym.id)
if sym != nil:
result = newSymNode(sym, n.info)
else:
result = n
of nkLetSection, nkVarSection:
result = shallowCopy(n)
for i in 0..<n.len:
let it = n[i]
if it.kind == nkCommentStmt:
result[i] = it
elif it.kind in {nkIdentDefs, nkConstDef}:
result[i] = shallowCopy(it)
for j in 0..<it.len-2:
result[i][j] = copySymdef(it[j], locals, idgen, owner)
for j in it.len-2..<it.len:
result[i][j] = copyInlineProcBody(it[j], locals, idgen, owner)
else:
assert it.kind == nkVarTuple
result[i] = shallowCopy(it)
for j in 0..<it.len-2:
assert it[j].kind == nkSym
let oldSym = it[j].sym
let newSym = copySym(oldSym, idgen)
setOwner(newSym, owner)
locals[oldSym.id] = newSym
result[i][j] = newSymNode(newSym, oldSym.info)
for j in it.len-2..<it.len:
result[i][j] = copyInlineProcBody(it[j], locals, idgen, owner)
of nkForStmt, nkParForStmt:
result = shallowCopy(n)
for i in 0..<n.len-2:
assert n[i].kind == nkSym
let oldSym = n[i].sym
let newSym = copySym(oldSym, idgen)
setOwner(newSym, owner)
locals[oldSym.id] = newSym
result[i] = newSymNode(newSym, oldSym.info)
result[n.len-2] = copyInlineProcBody(n[n.len-2], locals, idgen, owner)
result[n.len-1] = copyInlineProcBody(n[n.len-1], locals, idgen, owner)
of routineDefs, nkTypeSection, nkTypeOfExpr, nkMixinStmt, nkBindStmt, nkConstSection:
result = n
else:
result = shallowCopy(n)
for i in 0..<n.len:
result[i] = copyInlineProcBody(n[i], locals, idgen, owner)
proc copyParams(n: PNode; locals: var Table[int, PSym]; idgen: IdGenerator; owner: PSym): PNode =
result = shallowCopy(n)
result[0] = n[0] # return type
for i in 1..<n.len:
let it = n[i]
assert it.kind == nkIdentDefs
result[i] = shallowCopy(it)
for j in 0..<it.len-2:
assert it[j].kind == nkSym
let oldSym = it[j].sym
let newSym = copySym(oldSym, idgen)
setOwner(newSym, owner)
locals[oldSym.id] = newSym
result[i][j] = newSymNode(newSym, oldSym.info)
owner.typ.addParam newSym
for j in it.len-2..<it.len:
result[i][j] = copyInlineProcBody(it[j], locals, idgen, owner)
proc copyInlineProc(prc: PSym; idgen: IdGenerator): PSym =
result = copySym(prc, idgen)
var locals = initTable[int, PSym]()
var a = shallowCopy(prc.ast)
if resultPos < prc.ast.len and prc.ast[resultPos].kind == nkSym:
let oldRes = prc.ast[resultPos].sym
let newRes = copySym(oldRes, idgen)
setOwner(newRes, result)
locals[oldRes.id] = newRes
a[resultPos] = newSymNode(newRes, oldRes.info)
result.typ = copyType(prc.typ, idgen, result)
result.typ.n = newNodeI(prc.typ.n.kind, prc.typ.n.info)
if prc.typ.n.len > 0:
result.typ.n.add copyNode(prc.typ.n[0])
for i in 1..<prc.typ.n.len:
let it = prc.typ.n[i]
assert it.kind == nkSym
let oldSym = it.sym
let newSym = copySym(oldSym, idgen)
setOwner(newSym, result)
locals[oldSym.id] = newSym
result.typ.addParam newSym
for i in 0..<prc.ast.len:
if i == paramsPos:
a[i] = copyTree(prc.ast[i])
elif i == resultPos and prc.ast[i].kind == nkSym:
discard "handled above"
else:
a[i] = copyInlineProcBody(prc.ast[i], locals, idgen, result)
result.ast = a
#echo "Produced: ", renderTree(result.ast, {renderIds})

View File

@@ -133,6 +133,16 @@ proc fileInfoIdx*(conf: ConfigRef; filename: RelativeFile): FileIndex =
var dummy: bool = false
fileInfoIdx(conf, AbsoluteFile expandFilename(filename.string), dummy)
proc registerNifSuffix*(conf: ConfigRef; suffix: string; isKnownFile: var bool): FileIndex =
result = conf.m.filenameToIndexTbl.getOrDefault(suffix, InvalidFileIdx)
if result == InvalidFileIdx:
isKnownFile = false
result = conf.m.fileInfos.len.FileIndex
conf.m.fileInfos.add(newFileInfo(AbsoluteFile suffix, RelativeFile suffix))
conf.m.filenameToIndexTbl[suffix] = result
else:
isKnownFile = true
proc newLineInfo*(fileInfoIdx: FileIndex, line, col: int): TLineInfo =
result = TLineInfo(fileIndex: fileInfoIdx)
if line < int high(uint16):

View File

@@ -372,9 +372,9 @@ proc useVarNoInitCheck(a: PEffects; n: PNode; s: PSym) =
proc useVar(a: PEffects, n: PNode) =
let s = n.sym
if a.inExceptOrFinallyStmt > 0:
incl s, sfUsedInFinallyOrExcept
if isLocalSym(a, s):
if a.inExceptOrFinallyStmt > 0:
incl s, sfUsedInFinallyOrExcept
if sfNoInit in s.flags:
# If the variable is explicitly marked as .noinit. do not emit any error
a.init.add s.id

View File

@@ -143,15 +143,15 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]; conf: Confi
if t.sym != nil and {sfImportc, sfExportc} * t.sym.flags != {}:
c.hashSym(t.sym)
of tyObject, tyEnum:
if t.typeInst != nil:
if t.typeInstImpl != nil:
# prevent against infinite recursions here, see bug #8883:
let inst = t.typeInst
t.typeInst = nil
let inst = t.typeInstImpl
t.typeInstImpl = nil # IC: spurious writes are ok since we set it back immediately
assert inst.kind == tyGenericInst
c.hashType inst.genericHead, flags, conf
for _, a in inst.genericInstParams:
c.hashType a, flags, conf
t.typeInst = inst
t.typeInstImpl = inst
return
c &= char(t.kind)
# Every cyclic type in Nim need to be constructed via some 't.sym', so this

View File

@@ -117,3 +117,5 @@ proc addInt*(result: var string; x: int64) {.enforceNoRaises.} =
proc addInt*(result: var string; x: int) {.inline, enforceNoRaises.} =
addInt(result, int64(x))
{.pop.}

View File

@@ -555,9 +555,6 @@ type
when defined(nimIcIntegrityChecks):
include "system/exceptions"
else:
import system/exceptions
export exceptions
when defined(js) or defined(nimdoc):
type
@@ -1651,6 +1648,25 @@ when not defined(js) and defined(nimV2):
vTable: UncheckedArray[pointer] # vtable for types
PNimTypeV2 = ptr TNimTypeV2
when notJSnotNims and defined(nimSeqsV2):
const nimStrVersion {.core.} = 2
type
NimStrPayloadBase = object
cap: int
NimStrPayload {.core.} = object
cap: int
data: UncheckedArray[char]
NimStringV2 {.core.} = object
len: int
p: ptr NimStrPayload ## can be nil if len == 0.
when not defined(nimIcIntegrityChecks):
import system/exceptions
export exceptions
when notJSnotNims and defined(nimSeqsV2):
include "system/strs_v2"
include "system/seqs_v2"
@@ -2248,6 +2264,37 @@ when not defined(js) and declared(alloc0) and declared(dealloc):
inc(i)
dealloc(a)
when notJSnotNims and hostOS != "standalone":
proc getCurrentException*(): ref Exception {.compilerRtl, inl, benign.} =
## Retrieves the current exception; if there is none, `nil` is returned.
result = currException
proc nimBorrowCurrentException(): ref Exception {.compilerRtl, inl, benign, nodestroy.} =
# .nodestroy here so that we do not produce a write barrier as the
# C codegen only uses it in a borrowed way:
result = currException
proc getCurrentExceptionMsg*(): string {.inline, benign.} =
## Retrieves the error message that was attached to the current
## exception; if there is none, `""` is returned.
return if currException == nil: "" else: currException.msg
proc setCurrentException*(exc: ref Exception) {.inline, benign.} =
## Sets the current exception.
##
## .. warning:: Only use this if you know what you are doing.
currException = exc
proc raiseDefect() {.compilerRtl.} =
let e = getCurrentException()
if e of Defect:
reportUnhandledError(e)
rawQuit(1)
elif defined(nimscript):
proc getCurrentException*(): ref Exception {.compilerRtl.} = discard
proc raiseDefect*() {.compilerRtl.} = discard
when not defined(js):
when hasThreadSupport:
when hostOS != "standalone":
@@ -2333,37 +2380,6 @@ when notJSnotNims and hasThreadSupport and hostOS != "standalone":
include "system/channels_builtin"
when notJSnotNims and hostOS != "standalone":
proc getCurrentException*(): ref Exception {.compilerRtl, inl, benign.} =
## Retrieves the current exception; if there is none, `nil` is returned.
result = currException
proc nimBorrowCurrentException(): ref Exception {.compilerRtl, inl, benign, nodestroy.} =
# .nodestroy here so that we do not produce a write barrier as the
# C codegen only uses it in a borrowed way:
result = currException
proc getCurrentExceptionMsg*(): string {.inline, benign.} =
## Retrieves the error message that was attached to the current
## exception; if there is none, `""` is returned.
return if currException == nil: "" else: currException.msg
proc setCurrentException*(exc: ref Exception) {.inline, benign.} =
## Sets the current exception.
##
## .. warning:: Only use this if you know what you are doing.
currException = exc
proc raiseDefect() {.compilerRtl.} =
let e = getCurrentException()
if e of Defect:
reportUnhandledError(e)
rawQuit(1)
elif defined(nimscript):
proc getCurrentException*(): ref Exception {.compilerRtl.} = discard
proc raiseDefect*() {.compilerRtl.} = discard
when notJSnotNims:
{.push stackTrace: off, profiler: off.}
when (defined(profiler) or defined(memProfiler)):

View File

@@ -14,7 +14,7 @@ at offset 0 then. The ``ref`` object header is independent from the
runtime type and only contains a reference count.
]#
{.push raises: [].}
{.push raises: [], rangeChecks: off.}
when defined(gcOrc):
const

View File

@@ -9,8 +9,6 @@
# Implementation of some runtime checks.
include system/indexerrors
when defined(nimPreviewSlimSystem):
import std/formatfloat
proc raiseRangeError(val: BiggestInt) {.compilerproc, noinline.} =
when hostOS == "standalone":
@@ -53,12 +51,6 @@ proc raiseRangeErrorI(i, a, b: BiggestInt) {.compilerproc, noinline.} =
else:
sysFatal(RangeDefect, "value out of range: " & $i & " notin " & $a & " .. " & $b)
proc raiseRangeErrorF(i, a, b: float) {.compilerproc, noinline.} =
when defined(standalone):
sysFatal(RangeDefect, "value out of range")
else:
sysFatal(RangeDefect, "value out of range: " & $i & " notin " & $a & " .. " & $b)
proc raiseRangeErrorU(i, a, b: uint64) {.compilerproc, noinline.} =
# todo: better error reporting
sysFatal(RangeDefect, "value out of range")
@@ -97,16 +89,6 @@ proc chckRangeU(i, a, b: uint64): uint64 {.compilerproc.} =
result = 0
sysFatal(RangeDefect, "value out of range")
proc chckRangeF(x, a, b: float): float =
if x >= a and x <= b:
return x
else:
result = 0.0
when hostOS == "standalone":
sysFatal(RangeDefect, "value out of range")
else:
sysFatal(RangeDefect, "value out of range: ", $x)
proc chckNil(p: pointer) =
if p == nil:
sysFatal(NilAccessDefect, "attempt to write to a nil address")
@@ -164,3 +146,30 @@ when not defined(nimV2):
when defined(nimV2):
proc raiseObjectCaseTransition() {.compilerproc.} =
sysFatal(FieldDefect, "assignment to discriminant changes object branch")
import std/formatfloat
when not defined(nimPreviewSlimSystem):
export addFloat
func f2s(x: float | float32): string =
## Outplace version of `addFloat`.
result = ""
result.addFloat(x)
proc raiseRangeErrorF(i, a, b: float) {.compilerproc, noinline.} =
when defined(standalone):
sysFatal(RangeDefect, "value out of range")
else:
sysFatal(RangeDefect, "value out of range: " & f2s(i) & " notin " & f2s(a) & " .. " & f2s(b))
proc chckRangeF(x, a, b: float): float =
if x >= a and x <= b:
return x
else:
result = 0.0
when hostOS == "standalone":
sysFatal(RangeDefect, "value out of range")
else:
sysFatal(RangeDefect, "value out of range: ", f2s(x))

View File

@@ -9,20 +9,6 @@
## Default new string implementation used by Nim's core.
type
NimStrPayloadBase = object
cap: int
NimStrPayload {.core.} = object
cap: int
data: UncheckedArray[char]
NimStringV2 {.core.} = object
len: int
p: ptr NimStrPayload ## can be nil if len == 0.
const nimStrVersion {.core.} = 2
{.push overflowChecks: off, rangeChecks: off.}
template isLiteral(s): bool = (s.p == nil) or (s.p.cap and strlitFlag) == strlitFlag