Skip to content

Commit a773178

Browse files
authored
IC: progress (#25314)
1 parent 6656084 commit a773178

File tree

13 files changed

+321
-191
lines changed

13 files changed

+321
-191
lines changed

compiler/ast.nim

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ template typ*(n: PNode): PType =
3333
n.typField
3434

3535
when not defined(nimKochBootstrap):
36-
var program {.threadvar.}: DecodeContext
36+
var program* {.threadvar.}: DecodeContext
3737

3838
proc setupProgram*(config: ConfigRef; cache: IdentCache) =
3939
when not defined(nimKochBootstrap):
@@ -736,10 +736,6 @@ proc appendToModule*(m: PSym, n: PNode) =
736736
assert m.astImpl.kind == nkStmtList
737737
m.astImpl.add(n)
738738

739-
const # for all kind of hash tables:
740-
GrowthFactor* = 2 # must be power of 2, > 0
741-
StartSize* = 8 # must be power of 2, > 0
742-
743739
proc copyStrTable*(dest: var TStrTable, src: TStrTable) =
744740
dest.counter = src.counter
745741
setLen(dest.data, src.data.len)

compiler/ast2nif.nim

Lines changed: 122 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,8 @@ type
126126
moduleToNifSuffix: Table[FileIndex, string]
127127
locals: HashSet[ItemId] # track proc-local symbols
128128
inProc: int
129+
writtenTypes: seq[PType] # types written in this module, to be unloaded later
130+
writtenSyms: seq[PSym] # symbols written in this module, to be unloaded later
129131

130132
proc toNifSymName(w: var Writer; sym: PSym): string =
131133
## Generate NIF name for a symbol: local names are `ident.disamb`,
@@ -238,6 +240,8 @@ proc writeType(w: var Writer; dest: var TokenBuf; typ: PType) =
238240
elif typ.itemId.module == w.currentModule and typ.state == Complete:
239241
typ.state = Sealed
240242
writeTypeDef(w, dest, typ)
243+
# Collect for later unloading after entire module is written
244+
w.writtenTypes.add typ
241245
else:
242246
dest.addSymUse pool.syms.getOrIncl(w.typeToNifSym(typ)), NoLineInfo
243247

@@ -291,6 +295,11 @@ proc writeSymDef(w: var Writer; dest: var TokenBuf; sym: PSym) =
291295
writeSym(w, dest, sym.instantiatedFromImpl)
292296
dest.addParRi
293297

298+
# Collect for later unloading after entire module is written
299+
if sym.kindImpl notin {skModule, skPackage}:
300+
# do not unload modules
301+
w.writtenSyms.add sym
302+
294303
proc writeSym(w: var Writer; dest: var TokenBuf; sym: PSym) =
295304
if sym == nil:
296305
dest.addDotToken()
@@ -453,14 +462,19 @@ proc writeToplevelNode(w: var Writer; outer, inner: var TokenBuf; n: PNode) =
453462
else:
454463
writeNode w, outer, n
455464

465+
proc createStmtList(buf: var TokenBuf; info: PackedLineInfo) {.inline.} =
466+
buf.addParLe pool.tags.getOrIncl(toNifTag(nkStmtList)), info
467+
buf.addDotToken # flags
468+
buf.addDotToken # type
469+
456470
proc writeNifModule*(config: ConfigRef; thisModule: int32; n: PNode) =
457471
var w = Writer(infos: LineInfoWriter(config: config), currentModule: thisModule)
458472
var outer = createTokenBuf(300)
459473
var inner = createTokenBuf(300)
460474

461475
let rootInfo = trLineInfo(w, n.info)
462-
outer.addParLe pool.tags.getOrIncl(toNifTag(nkStmtList)), rootInfo
463-
inner.addParLe pool.tags.getOrIncl(toNifTag(nkStmtList)), rootInfo
476+
createStmtList(outer, rootInfo)
477+
createStmtList(inner, rootInfo)
464478

465479
w.writeToplevelNode outer, inner, n
466480

@@ -472,7 +486,7 @@ proc writeNifModule*(config: ConfigRef; thisModule: int32; n: PNode) =
472486
let d = completeGeneratedFilePath(config, nifFilename).string
473487

474488
var dest = createTokenBuf(600)
475-
dest.addParLe pool.tags.getOrIncl(toNifTag(nkStmtList)), rootInfo
489+
createStmtList(dest, rootInfo)
476490
dest.add w.deps
477491
dest.add outer
478492
dest.add inner
@@ -481,6 +495,13 @@ proc writeNifModule*(config: ConfigRef; thisModule: int32; n: PNode) =
481495
writeFile(dest, d)
482496
createIndex(d, false, dest[0].info)
483497

498+
# Unload all written types and symbols from memory after the entire module is written
499+
# This handles cyclic references correctly since everything is written before unloading
500+
for typ in w.writtenTypes:
501+
forcePartial(typ)
502+
for sym in w.writtenSyms:
503+
forcePartial(sym)
504+
484505

485506
# --------------------------- Loader (lazy!) -----------------------------------------------
486507

@@ -548,7 +569,7 @@ type
548569
syms: Table[ItemId, (PSym, NifIndexEntry)]
549570
mods: seq[NifModule]
550571
cache: IdentCache
551-
#moduleToNifSuffix: Table[FileIndex, string]
572+
moduleToNifSuffix: Table[FileIndex, string]
552573

553574
proc createDecodeContext*(config: ConfigRef; cache: IdentCache): DecodeContext =
554575
## Supposed to be a global variable
@@ -567,7 +588,7 @@ proc moduleId(c: var DecodeContext; suffix: string): FileIndex =
567588
result = c.infos.config.registerNifSuffix(suffix, isKnownFile)
568589
if not isKnownFile:
569590
let modFile = (getNimcacheDir(c.infos.config) / RelativeFile(suffix & ".nif")).string
570-
let idxFile = (getNimcacheDir(c.infos.config) / RelativeFile(suffix & ".idx.nif")).string
591+
let idxFile = (getNimcacheDir(c.infos.config) / RelativeFile(suffix & ".s.idx.nif")).string
571592
if result.int >= c.mods.len:
572593
c.mods.setLen(result.int + 1)
573594
c.mods[result.int] = NifModule(stream: nifstreams.open(modFile), index: readIndex(idxFile))
@@ -580,7 +601,7 @@ proc getOffset(c: var DecodeContext; module: FileIndex; nifName: string): NifInd
580601
if result.offset == 0:
581602
raiseAssert "symbol has no offset: " & nifName
582603

583-
proc loadNode(c: var DecodeContext; n: var Cursor): PNode
604+
proc loadNode(c: var DecodeContext; n: var Cursor; thisModule: string): PNode
584605

585606
proc loadTypeStub(c: var DecodeContext; t: SymId): PType =
586607
let name = pool.syms[t]
@@ -619,10 +640,10 @@ proc loadTypeStub(c: var DecodeContext; n: var Cursor): PType =
619640
else:
620641
raiseAssert "type expected but got " & $n.kind
621642

622-
proc loadSymStub(c: var DecodeContext; t: SymId): PSym =
643+
proc loadSymStub(c: var DecodeContext; t: SymId; thisModule: string): PSym =
623644
let symAsStr = pool.syms[t]
624645
let sn = parseSymName(symAsStr)
625-
let module = moduleId(c, sn.module)
646+
let module = moduleId(c, if sn.module.len > 0: sn.module else: thisModule)
626647
let val = addr c.mods[module.int32].symCounter
627648
inc val[]
628649

@@ -632,19 +653,20 @@ proc loadSymStub(c: var DecodeContext; t: SymId): PSym =
632653
let offs = c.getOffset(module, symAsStr)
633654
result = PSym(itemId: id, kindImpl: skStub, name: c.cache.getIdent(sn.name), disamb: sn.count.int32, state: Partial)
634655
c.syms[id] = (result, offs)
656+
c.moduleToNifSuffix[module] = (if sn.module.len > 0: sn.module else: thisModule)
635657

636-
proc loadSymStub(c: var DecodeContext; n: var Cursor): PSym =
658+
proc loadSymStub(c: var DecodeContext; n: var Cursor; thisModule: string): PSym =
637659
if n.kind == DotToken:
638660
result = nil
639661
inc n
640662
elif n.kind == Symbol:
641663
let s = n.symId
642-
result = loadSymStub(c, s)
664+
result = loadSymStub(c, s, thisModule)
643665
inc n
644666
elif n.kind == ParLe and n.tagId == sdefTag:
645667
let s = n.firstSon.symId
646668
skip n
647-
result = loadSymStub(c, s)
669+
result = loadSymStub(c, s, thisModule)
648670
else:
649671
raiseAssert "sym expected but got " & $n.kind
650672

@@ -700,6 +722,7 @@ proc loadType*(c: var DecodeContext; t: PType) =
700722
inc n
701723
expect n, SymbolDef
702724
# ignore the type's name, we have already used it to create this PType's itemId!
725+
let typesModule = parseSymName(pool.syms[n.symId]).module
703726
inc n
704727
#loadField t.kind
705728
loadField t.flagsImpl
@@ -710,17 +733,17 @@ proc loadType*(c: var DecodeContext; t: PType) =
710733
loadField t.itemId.item # nonUniqueId
711734

712735
t.typeInstImpl = loadTypeStub(c, n)
713-
t.nImpl = loadNode(c, n)
714-
t.ownerFieldImpl = loadSymStub(c, n)
715-
t.symImpl = loadSymStub(c, n)
736+
t.nImpl = loadNode(c, n, typesModule)
737+
t.ownerFieldImpl = loadSymStub(c, n, typesModule)
738+
t.symImpl = loadSymStub(c, n, typesModule)
716739
loadLoc c, n, t.locImpl
717740

718741
while n.kind != ParRi:
719742
t.sonsImpl.add loadTypeStub(c, n)
720743

721744
skipParRi n
722745

723-
proc loadAnnex(c: var DecodeContext; n: var Cursor): PLib =
746+
proc loadAnnex(c: var DecodeContext; n: var Cursor; thisModule: string): PLib =
724747
if n.kind == DotToken:
725748
result = nil
726749
inc n
@@ -732,7 +755,7 @@ proc loadAnnex(c: var DecodeContext; n: var Cursor): PLib =
732755
expect n, StringLit
733756
result.name = pool.strings[n.litId]
734757
inc n
735-
result.path = loadNode(c, n)
758+
result.path = loadNode(c, n, thisModule)
736759
skipParRi n
737760
else:
738761
raiseAssert "`lib/annex` information expected"
@@ -741,7 +764,8 @@ proc loadSym*(c: var DecodeContext; s: PSym) =
741764
if s.state != Partial: return
742765
s.state = Sealed
743766
var buf = createTokenBuf(30)
744-
var n = cursorFromIndexEntry(c, s.itemId.module.FileIndex, c.syms[s.itemId][1], buf)
767+
let symsModule = s.itemId.module.FileIndex
768+
var n = cursorFromIndexEntry(c, symsModule, c.syms[s.itemId][1], buf)
745769

746770
expect n, ParLe
747771
if n.tagId != sdefTag:
@@ -772,7 +796,7 @@ proc loadSym*(c: var DecodeContext; s: PSym) =
772796

773797
case s.kindImpl
774798
of skLet, skVar, skField, skForVar:
775-
s.guardImpl = loadSymStub(c, n)
799+
s.guardImpl = loadSymStub(c, n, c.moduleToNifSuffix[symsModule])
776800
loadField s.bitsizeImpl
777801
loadField s.alignmentImpl
778802
else:
@@ -785,62 +809,68 @@ proc loadSym*(c: var DecodeContext; s: PSym) =
785809
else:
786810
loadField s.positionImpl
787811
s.typImpl = loadTypeStub(c, n)
788-
s.ownerFieldImpl = loadSymStub(c, n)
812+
s.ownerFieldImpl = loadSymStub(c, n, c.moduleToNifSuffix[symsModule])
789813
# We do not store `sym.ast` here but instead set it in the deserializer
790814
#writeNode(w, sym.ast)
791815
loadLoc c, n, s.locImpl
792-
s.constraintImpl = loadNode(c, n)
793-
s.instantiatedFromImpl = loadSymStub(c, n)
816+
s.constraintImpl = loadNode(c, n, c.moduleToNifSuffix[symsModule])
817+
s.instantiatedFromImpl = loadSymStub(c, n, c.moduleToNifSuffix[symsModule])
794818
skipParRi n
795819

796820

797821
template withNode(c: var DecodeContext; n: var Cursor; result: PNode; kind: TNodeKind; body: untyped) =
798822
let info = c.infos.oldLineInfo(n.info)
823+
inc n
799824
let flags = loadAtom(TNodeFlags, n)
800825
result = newNodeI(kind, info)
801826
result.flags = flags
802827
result.typField = c.loadTypeStub n
803828
body
804829
skipParRi n
805830

806-
proc loadNode(c: var DecodeContext; n: var Cursor): PNode =
831+
proc loadNode(c: var DecodeContext; n: var Cursor; thisModule: string): PNode =
807832
result = nil
808-
case n.kind:
833+
case n.kind
834+
of Symbol:
835+
let info = c.infos.oldLineInfo(n.info)
836+
result = newSymNode(c.loadSymStub(n, thisModule), info)
809837
of DotToken:
810838
result = nil
811839
inc n
812840
of ParLe:
813841
let kind = n.nodeKind
814-
case kind:
842+
case kind
815843
of nkNone:
816844
# special NIF introduced tag?
817845
case pool.tags[n.tagId]
818846
of hiddenTypeTagName:
819847
inc n
820848
let typ = c.loadTypeStub n
821849
let info = c.infos.oldLineInfo(n.info)
822-
result = newSymNode(c.loadSymStub n, info)
850+
result = newSymNode(c.loadSymStub(n, thisModule), info)
823851
result.typField = typ
824852
skipParRi n
825853
of symDefTagName:
826854
let name = n.firstSon
827855
assert name.kind == SymbolDef
828-
result = newSymNode(c.loadSymStub name.symId, c.infos.oldLineInfo(n.info))
856+
result = newSymNode(c.loadSymStub(name.symId, thisModule), c.infos.oldLineInfo(n.info))
829857
skip n
830858
of typeDefTagName:
831859
raiseAssert "`td` tag in invalid context"
832860
of "none":
833861
result = newNodeI(nkNone, c.infos.oldLineInfo(n.info))
862+
inc n
834863
result.flags = loadAtom(TNodeFlags, n)
835864
skipParRi n
836865
else:
837866
raiseAssert "Unknown NIF tag " & pool.tags[n.tagId]
838867
of nkEmpty:
839868
result = newNodeI(nkEmpty, c.infos.oldLineInfo(n.info))
840-
result.flags = loadAtom(TNodeFlags, n)
869+
inc n
841870
skipParRi n
842871
of nkIdent:
843872
let info = c.infos.oldLineInfo(n.info)
873+
inc n
844874
let flags = loadAtom(TNodeFlags, n)
845875
let typ = c.loadTypeStub n
846876
expect n, Ident
@@ -850,8 +880,9 @@ proc loadNode(c: var DecodeContext; n: var Cursor): PNode =
850880
result.typField = typ
851881
skipParRi n
852882
of nkSym:
853-
let info = c.infos.oldLineInfo(n.info)
854-
result = newSymNode(c.loadSymStub n, info)
883+
#let info = c.infos.oldLineInfo(n.info)
884+
#result = newSymNode(c.loadSymStub n, info)
885+
raiseAssert "nkSym should be mapped to a NIF symbol, not a tag"
855886
of nkCharLit:
856887
c.withNode n, result, kind:
857888
expect n, CharLit
@@ -897,24 +928,71 @@ proc loadNode(c: var DecodeContext; n: var Cursor): PNode =
897928
else:
898929
c.withNode n, result, kind:
899930
while n.kind != ParRi:
900-
result.sons.add c.loadNode(n)
931+
result.sons.add c.loadNode(n, thisModule)
901932
else:
902933
raiseAssert "Not yet implemented " & $n.kind
903934

904-
when false:
905-
proc loadNifModule*(c: var DecodeContext; f: FileIndex): PNode =
906-
let moduleSuffix = moduleSuffix(c.infos.config, f)
907-
let modFile = toGeneratedFile(c.infos.config, AbsoluteFile(moduleSuffix), ".nif").string
908-
909-
var buf = createTokenBuf(300)
910-
var s = nifstreams.open(modFile)
911-
# XXX We can optimize this here and only load the top level entries!
912-
try:
913-
nifcursors.parse(s, buf, NoLineInfo)
914-
finally:
915-
nifstreams.close(s)
916-
var n = cursorAt(buf, 0)
917-
result = loadNode(c, n)
935+
proc moduleSuffix(conf: ConfigRef; f: FileIndex): string =
936+
moduleSuffix(toFullPath(conf, f), cast[seq[string]](conf.searchPaths))
937+
938+
proc loadSymFromIndexEntry(c: var DecodeContext; module: FileIndex;
939+
nifName: string; entry: NifIndexEntry; thisModule: string): PSym =
940+
## Loads a symbol from the NIF index entry.
941+
## Creates a symbol stub and loads its full definition.
942+
result = loadSymStub(c, pool.syms.getOrIncl nifName, thisModule)
943+
944+
proc populateInterfaceTablesFromIndex(c: var DecodeContext; module: FileIndex;
945+
interf, interfHidden: var TStrTable; thisModule: string) =
946+
## Populates interface tables from the NIF index structure.
947+
## Uses the index's public/private tables instead of traversing AST.
948+
let idx = addr c.mods[module.int32].index
949+
950+
# Add all public symbols to interf (exported interface) and interfHidden
951+
for nifName, entry in idx.public:
952+
if not nifName.startsWith("`t"):
953+
# do not load types, they are not part of an interface but an implementation detail!
954+
#echo "LOADING SYM ", nifName, " ", entry.offset
955+
let sym = loadSymFromIndexEntry(c, module, nifName, entry, thisModule)
956+
if sym != nil:
957+
strTableAdd(interf, sym)
958+
strTableAdd(interfHidden, sym)
959+
960+
when false:
961+
# Add private symbols to interfHidden only
962+
for nifName, entry in idx.private:
963+
let sym = loadSymFromIndexEntry(c, module, nifName, entry, thisModule)
964+
if sym != nil:
965+
strTableAdd(interfHidden, sym)
966+
967+
proc toNifFilename*(conf: ConfigRef; f: FileIndex): string =
968+
let suffix = moduleSuffix(conf, f)
969+
result = toGeneratedFile(conf, AbsoluteFile(suffix), ".nif").string
970+
971+
proc toNifIndexFilename*(conf: ConfigRef; f: FileIndex): string =
972+
let suffix = moduleSuffix(conf, f)
973+
result = toGeneratedFile(conf, AbsoluteFile(suffix), ".s.idx.nif").string
974+
975+
proc loadNifModule*(c: var DecodeContext; f: FileIndex; interf, interfHidden: var TStrTable): PNode =
976+
let suffix = moduleSuffix(c.infos.config, f)
977+
let modFile = toGeneratedFile(c.infos.config, AbsoluteFile(suffix), ".nif").string
978+
979+
# Ensure module index is loaded - moduleId returns the FileIndex for this suffix
980+
let module = moduleId(c, suffix)
981+
982+
# Populate interface tables from the NIF index structure
983+
# Use the FileIndex returned by moduleId to ensure we access the correct index
984+
populateInterfaceTablesFromIndex(c, module, interf, interfHidden, suffix)
985+
986+
var buf = createTokenBuf(300)
987+
var s = nifstreams.open(modFile)
988+
discard processDirectives(s.r)
989+
# XXX We can optimize this here and only load the top level entries!
990+
try:
991+
nifcursors.parse(s, buf, NoLineInfo)
992+
finally:
993+
nifstreams.close(s)
994+
var n = cursorAt(buf, 0)
995+
result = loadNode(c, n, suffix)
918996

919997
when isMainModule:
920998
import std / syncio

0 commit comments

Comments
 (0)