IC: final implementation steps (#16801)

* removed dead code
* we need even more laziness for the generic caches
* make it bootstrap on older Nims
* wrote more deserialization code
* IC: replay required methods information
This commit is contained in:
Andreas Rumpf 2021-01-25 20:52:26 +01:00 • committed by GitHub
commit 25745ad195
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 259 additions and 105 deletions

View file

@ -2236,7 +2236,6 @@ proc genSlice(p: BProc; e: PNode; d: var TLoc) =
"'toOpenArray' is only valid within a call expression") "'toOpenArray' is only valid within a call expression")
proc genEnumToStr(p: BProc, e: PNode, d: var TLoc) = proc genEnumToStr(p: BProc, e: PNode, d: var TLoc) =
const ToStringProcSlot = -4
let t = e[1].typ.skipTypes(abstractInst+{tyRange}) let t = e[1].typ.skipTypes(abstractInst+{tyRange})
let toStrProc = getToStringProc(p.module.g.graph, t) let toStrProc = getToStringProc(p.module.g.graph, t)
# XXX need to modify this logic for IC. # XXX need to modify this logic for IC.

View file

@ -160,7 +160,7 @@ proc fixupDispatcher(meth, disp: PSym; conf: ConfigRef) =
if disp.typ.lockLevel < meth.typ.lockLevel: if disp.typ.lockLevel < meth.typ.lockLevel:
disp.typ.lockLevel = meth.typ.lockLevel disp.typ.lockLevel = meth.typ.lockLevel
proc methodDef*(g: ModuleGraph; idgen: IdGenerator; s: PSym, fromCache: bool) = proc methodDef*(g: ModuleGraph; idgen: IdGenerator; s: PSym) =
var witness: PSym var witness: PSym
for i in 0..<g.methods.len: for i in 0..<g.methods.len:
let disp = g.methods[i].dispatcher let disp = g.methods[i].dispatcher
@ -182,8 +182,6 @@ proc methodDef*(g: ModuleGraph; idgen: IdGenerator; s: PSym, fromCache: bool) =
# create a new dispatcher: # create a new dispatcher:
g.methods.add((methods: @[s], dispatcher: createDispatcher(s, g, idgen))) g.methods.add((methods: @[s], dispatcher: createDispatcher(s, g, idgen)))
#echo "adding ", s.info #echo "adding ", s.info
#if fromCache:
# internalError(s.info, "no method dispatcher found")
if witness != nil: if witness != nil:
localError(g.config, s.info, "invalid declaration order; cannot attach '" & s.name.s & localError(g.config, s.info, "invalid declaration order; cannot attach '" & s.name.s &
"' to method defined here: " & g.config$witness.info) "' to method defined here: " & g.config$witness.info)

View file

@ -74,11 +74,9 @@ type
flags*: TTypeFlags flags*: TTypeFlags
types*: seq[PackedItemId] types*: seq[PackedItemId]
n*: NodeId n*: NodeId
methods*: seq[(int, PackedItemId)]
#nodeflags*: TNodeFlags #nodeflags*: TNodeFlags
sym*: PackedItemId sym*: PackedItemId
owner*: PackedItemId owner*: PackedItemId
attachedOps*: array[TTypeAttachedOp, PackedItemId]
size*: BiggestInt size*: BiggestInt
align*: int16 align*: int16
paddingAtEnd*: int16 paddingAtEnd*: int16
@ -111,6 +109,10 @@ type
floats*: BiTable[BiggestFloat] floats*: BiTable[BiggestFloat]
#config*: ConfigRef #config*: ConfigRef
PackedInstantiation* = object
key*, sym*: PackedItemId
concreteTypes*: seq[PackedItemId]
proc `==`*(a, b: SymId): bool {.borrow.} proc `==`*(a, b: SymId): bool {.borrow.}
proc hash*(a: SymId): Hash {.borrow.} proc hash*(a: SymId): Hash {.borrow.}

View file

@ -12,10 +12,12 @@
## support. ## support.
import ".." / [ast, modulegraphs, trees, extccomp, btrees, import ".." / [ast, modulegraphs, trees, extccomp, btrees,
msgs, lineinfos, pathutils, options] msgs, lineinfos, pathutils, options, cgmeth]
import tables import tables
import packed_ast, to_packed_ast, bitabs
proc replayStateChanges*(module: PSym; g: ModuleGraph) = proc replayStateChanges*(module: PSym; g: ModuleGraph) =
let list = module.ast let list = module.ast
assert list != nil assert list != nil
@ -84,6 +86,44 @@ proc replayStateChanges*(module: PSym; g: ModuleGraph) =
else: else:
internalAssert g.config, false internalAssert g.config, false
# of nkMethodDef: proc replayGenericCacheInformation*(g: ModuleGraph; module: int) =
# methodDef(g, n[namePos].sym, fromCache=true) ## We remember the generic instantiations a module performed
## in order to to avoid the code bloat that generic code tends
## to imply. This is cheaper than deduplication of identical
## generic instantiations. However, deduplication is more
## powerful and general and I hope to implement it soon too
## (famous last words).
assert g.packed[module].status == loaded
for it in g.packed[module].fromDisk.typeInstCache:
let key = translateId(it[0], g.packed, module, g.config)
g.typeInstCache.mgetOrPut(key, @[]).add LazyType(id: FullId(module: module, packed: it[1]), typ: nil)
for it in mitems(g.packed[module].fromDisk.procInstCache):
let key = translateId(it.key, g.packed, module, g.config)
let sym = translateId(it.sym, g.packed, module, g.config)
var concreteTypes = newSeq[FullId](it.concreteTypes.len)
for i in 0..high(it.concreteTypes):
let tmp = translateId(it.concreteTypes[i], g.packed, module, g.config)
concreteTypes[i] = FullId(module: tmp.module, packed: it.concreteTypes[i])
g.procInstCache.mgetOrPut(key, @[]).add LazyInstantiation(
module: module, sym: FullId(module: sym.module, packed: it.sym),
concreteTypes: concreteTypes, inst: nil)
for it in mitems(g.packed[module].fromDisk.methodsPerType):
let key = translateId(it[0], g.packed, module, g.config)
let col = it[1]
let tmp = translateId(it[2], g.packed, module, g.config)
let symId = FullId(module: tmp.module, packed: it[2])
g.methodsPerType.mgetOrPut(key, @[]).add (col, LazySym(id: symId, sym: nil))
for it in mitems(g.packed[module].fromDisk.enumToStringProcs):
let key = translateId(it[0], g.packed, module, g.config)
let tmp = translateId(it[1], g.packed, module, g.config)
let symId = FullId(module: tmp.module, packed: it[1])
g.enumToStringProcs[key] = LazySym(id: symId, sym: nil)
for it in mitems(g.packed[module].fromDisk.methods):
let sym = loadSymFromId(g.config, g.cache, g.packed, module,
PackedItemId(module: LitId(0), item: it))
methodDef(g, g.idgen, sym)

View file

@ -31,6 +31,11 @@ type
bodiesSection bodiesSection
symsSection symsSection
typesSection typesSection
typeInstCacheSection
procInstCacheSection
attachedOpsSection
methodsPerTypeSection
enumToStringProcsSection
aliveSymsSection # beware, this is stored in a `.alivesyms` file. aliveSymsSection # beware, this is stored in a `.alivesyms` file.
RodFileError* = enum RodFileError* = enum
@ -73,6 +78,12 @@ proc storePrim*[T](f: var RodFile; x: T) =
elif T is tuple: elif T is tuple:
for y in fields(x): for y in fields(x):
storePrim(f, y) storePrim(f, y)
elif T is object:
for y in fields(x):
when y is seq:
storeSeq(f, y)
else:
storePrim(f, y)
else: else:
{.error: "unsupported type for 'storePrim'".} {.error: "unsupported type for 'storePrim'".}
@ -107,6 +118,12 @@ proc loadPrim*[T](f: var RodFile; x: var T) =
elif T is tuple: elif T is tuple:
for y in fields(x): for y in fields(x):
loadPrim(f, y) loadPrim(f, y)
elif T is object:
for y in fields(x):
when y is seq:
loadSeq(f, y)
else:
loadPrim(f, y)
else: else:
{.error: "unsupported type for 'loadPrim'".} {.error: "unsupported type for 'loadPrim'".}

View file

@ -33,8 +33,15 @@ type
exports*: seq[(LitId, int32)] exports*: seq[(LitId, int32)]
reexports*: seq[(LitId, PackedItemId)] reexports*: seq[(LitId, PackedItemId)]
compilerProcs*, trmacros*, converters*, pureEnums*: seq[(LitId, int32)] compilerProcs*, trmacros*, converters*, pureEnums*: seq[(LitId, int32)]
methods*: seq[(LitId, PackedItemId, int32)] methods*: seq[int32]
macroUsages*: seq[(PackedItemId, PackedLineInfo)] macroUsages*: seq[(PackedItemId, PackedLineInfo)]
typeInstCache*: seq[(PackedItemId, PackedItemId)]
procInstCache*: seq[PackedInstantiation]
attachedOps*: seq[(TTypeAttachedOp, PackedItemId, PackedItemId)]
methodsPerType*: seq[(PackedItemId, int, PackedItemId)]
enumToStringProcs*: seq[(PackedItemId, PackedItemId)]
sh*: Shared sh*: Shared
cfg: PackedConfig cfg: PackedConfig
@ -160,9 +167,7 @@ proc addPureEnum*(c: var PackedEncoder; m: var PackedModule; s: PSym) =
m.pureEnums.add((nameId, s.itemId.item)) m.pureEnums.add((nameId, s.itemId.item))
proc addMethod*(c: var PackedEncoder; m: var PackedModule; s: PSym) = proc addMethod*(c: var PackedEncoder; m: var PackedModule; s: PSym) =
let nameId = getOrIncl(m.sh.strings, s.name.s) m.methods.add s.itemId.item
discard "to do"
# c.m.methods.add((nameId, s.itemId.item))
proc addReexport*(c: var PackedEncoder; m: var PackedModule; s: PSym) = proc addReexport*(c: var PackedEncoder; m: var PackedModule; s: PSym) =
let nameId = getOrIncl(m.sh.strings, s.name.s) let nameId = getOrIncl(m.sh.strings, s.name.s)
@ -415,6 +420,17 @@ proc toPackedNode*(n: PNode; ir: var PackedTree; c: var PackedEncoder; m: var Pa
toPackedNode(n[i], ir, c, m) toPackedNode(n[i], ir, c, m)
ir.patch patchPos ir.patch patchPos
proc storeInstantiation*(c: var PackedEncoder; m: var PackedModule; s: PSym; i: PInstantiation) =
var t = newSeq[PackedItemId](i.concreteTypes.len)
for j in 0..high(i.concreteTypes):
t[j] = storeTypeLater(i.concreteTypes[j], c, m)
m.procInstCache.add PackedInstantiation(key: storeSymLater(s, c, m),
sym: storeSymLater(i.sym, c, m),
concreteTypes: t)
proc storeTypeInst*(c: var PackedEncoder; m: var PackedModule; s: PSym; inst: PType) =
m.typeInstCache.add (storeSymLater(s, c, m), storeTypeLater(inst, c, m))
proc addPragmaComputation*(c: var PackedEncoder; m: var PackedModule; n: PNode) = proc addPragmaComputation*(c: var PackedEncoder; m: var PackedModule; n: PNode) =
toPackedNode(n, m.toReplay, c, m) toPackedNode(n, m.toReplay, c, m)
@ -436,20 +452,6 @@ proc toPackedNodeTopLevel*(n: PNode, encoder: var PackedEncoder; m: var PackedMo
toPackedNodeIgnoreProcDefs(n, encoder, m) toPackedNodeIgnoreProcDefs(n, encoder, m)
flush encoder, m flush encoder, m
proc storePrim*(f: var RodFile; x: PackedType) =
for y in fields(x):
when y is seq:
storeSeq(f, y)
else:
storePrim(f, y)
proc loadPrim*(f: var RodFile; x: var PackedType) =
for y in fields(x):
when y is seq:
loadSeq(f, y)
else:
loadPrim(f, y)
proc loadError(err: RodFileError; filename: AbsoluteFile) = proc loadError(err: RodFileError; filename: AbsoluteFile) =
echo "Error: ", $err, "\nloading file: ", filename.string echo "Error: ", $err, "\nloading file: ", filename.string
@ -503,6 +505,12 @@ proc loadRodFile*(filename: AbsoluteFile; m: var PackedModule; config: ConfigRef
loadSeqSection symsSection, m.sh.syms loadSeqSection symsSection, m.sh.syms
loadSeqSection typesSection, m.sh.types loadSeqSection typesSection, m.sh.types
loadSeqSection typeInstCacheSection, m.typeInstCache
loadSeqSection procInstCacheSection, m.procInstCache
loadSeqSection attachedOpsSection, m.attachedOps
loadSeqSection methodsPerTypeSection, m.methodsPerType
loadSeqSection enumToStringProcsSection, m.enumToStringProcs
close(f) close(f)
result = f.err result = f.err
@ -557,6 +565,13 @@ proc saveRodFile*(filename: AbsoluteFile; encoder: var PackedEncoder; m: var Pac
storeSeqSection symsSection, m.sh.syms storeSeqSection symsSection, m.sh.syms
storeSeqSection typesSection, m.sh.types storeSeqSection typesSection, m.sh.types
storeSeqSection typeInstCacheSection, m.typeInstCache
storeSeqSection procInstCacheSection, m.procInstCache
storeSeqSection attachedOpsSection, m.attachedOps
storeSeqSection methodsPerTypeSection, m.methodsPerType
storeSeqSection enumToStringProcsSection, m.enumToStringProcs
close(f) close(f)
if f.err != ok: if f.err != ok:
storeError(f.err, filename) storeError(f.err, filename)
@ -902,6 +917,36 @@ proc loadProcBody*(config: ConfigRef, cache: IdentCache;
assert pos != emptyNodeId assert pos != emptyNodeId
result = loadProcBody(decoder, g, mId, g[mId].fromDisk.bodies, NodePos pos) result = loadProcBody(decoder, g, mId, g[mId].fromDisk.bodies, NodePos pos)
proc loadTypeFromId*(config: ConfigRef, cache: IdentCache;
g: var PackedModuleGraph; module: int; id: PackedItemId): PType =
result = g[module].types[id.item]
if result == nil:
var decoder = PackedDecoder(
lastModule: int32(-1),
lastLit: LitId(0),
lastFile: FileIndex(-1),
config: config,
cache: cache)
result = loadType(decoder, g, module, id)
proc loadSymFromId*(config: ConfigRef, cache: IdentCache;
g: var PackedModuleGraph; module: int; id: PackedItemId): PSym =
result = g[module].syms[id.item]
if result == nil:
var decoder = PackedDecoder(
lastModule: int32(-1),
lastLit: LitId(0),
lastFile: FileIndex(-1),
config: config,
cache: cache)
result = loadSym(decoder, g, module, id)
proc translateId*(id: PackedItemId; g: PackedModuleGraph; thisModule: int; config: ConfigRef): ItemId =
if id.module == LitId(0):
ItemId(module: thisModule.int32, item: id.item)
else:
ItemId(module: toFileIndex(id.module, g[thisModule].fromDisk, config).int32, item: id.item)
proc checkForHoles(m: PackedModule; config: ConfigRef; moduleId: int) = proc checkForHoles(m: PackedModule; config: ConfigRef; moduleId: int) =
var bugs = 0 var bugs = 0
for i in 1 .. high(m.sh.syms): for i in 1 .. high(m.sh.syms):

View file

@ -14,7 +14,7 @@
import ast, astalgo, intsets, tables, options, lineinfos, hashes, idents, import ast, astalgo, intsets, tables, options, lineinfos, hashes, idents,
btrees, md5 btrees, md5
import ic / to_packed_ast import ic / [packed_ast, to_packed_ast]
type type
SigHash* = distinct MD5Digest SigHash* = distinct MD5Digest
@ -31,15 +31,33 @@ type
opNot*, opContains*, opLe*, opLt*, opAnd*, opOr*, opIsNil*, opEq*: PSym opNot*, opContains*, opLe*, opLt*, opAnd*, opOr*, opIsNil*, opEq*: PSym
opAdd*, opSub*, opMul*, opDiv*, opLen*: PSym opAdd*, opSub*, opMul*, opDiv*, opLen*: PSym
FullId* = object
module*: int
packed*: PackedItemId
LazySym* = object
id*: FullId
sym*: PSym
LazyType* = object
id*: FullId
typ*: PType
LazyInstantiation* = object
module*: int
sym*: FullId
concreteTypes*: seq[FullId]
inst*: PInstantiation
ModuleGraph* = ref object ModuleGraph* = ref object
ifaces*: seq[Iface] ## indexed by int32 fileIdx ifaces*: seq[Iface] ## indexed by int32 fileIdx
packed*: PackedModuleGraph packed*: PackedModuleGraph
typeInstCache*: Table[ItemId, seq[PType]] # A symbol's ItemId. typeInstCache*: Table[ItemId, seq[LazyType]] # A symbol's ItemId.
procInstCache*: Table[ItemId, seq[PInstantiation]] # A symbol's ItemId. procInstCache*: Table[ItemId, seq[LazyInstantiation]] # A symbol's ItemId.
attachedOps*: array[TTypeAttachedOp, Table[ItemId, PSym]] # Type ID, destructors, etc. attachedOps*: array[TTypeAttachedOp, Table[ItemId, PSym]] # Type ID, destructors, etc.
methodsPerType*: Table[ItemId, seq[(int, PSym)]] # Type ID, attached methods methodsPerType*: Table[ItemId, seq[(int, LazySym)]] # Type ID, attached methods
enumToStringProcs*: Table[ItemId, PSym] enumToStringProcs*: Table[ItemId, LazySym]
startupPackedConfig*: PackedConfig startupPackedConfig*: PackedConfig
packageSyms*: TStrTable packageSyms*: TStrTable
@ -97,68 +115,6 @@ type
close: TPassClose, close: TPassClose,
isFrontend: bool] isFrontend: bool]
iterator typeInstCacheItems*(g: ModuleGraph; s: PSym): PType =
if g.typeInstCache.contains(s.itemId):
let x = addr(g.typeInstCache[s.itemId])
for t in x[]:
yield t
proc addToGenericCache*(g: ModuleGraph; module: int; s: PSym; inst: PType) =
g.typeInstCache.mgetOrPut(s.itemId, @[]).add inst
# XXX Also add to the packed module!
iterator procInstCacheItems*(g: ModuleGraph; s: PSym): PInstantiation =
if g.procInstCache.contains(s.itemId):
let x = addr(g.procInstCache[s.itemId])
for t in x[]:
yield t
proc addToGenericProcCache*(g: ModuleGraph; module: int; s: PSym; inst: PInstantiation) =
g.procInstCache.mgetOrPut(s.itemId, @[]).add inst
# XXX Also add to the packed module!
proc getAttachedOp*(g: ModuleGraph; t: PType; op: TTypeAttachedOp): PSym =
## returns the requested attached operation for type `t`. Can return nil
## if no such operation exists.
result = g.attachedOps[op].getOrDefault(t.itemId)
proc setAttachedOp*(g: ModuleGraph; module: int; t: PType; op: TTypeAttachedOp; value: PSym) =
## we also need to record this to the packed module.
g.attachedOps[op][t.itemId] = value
# XXX Also add to the packed module!
proc setAttachedOpPartial*(g: ModuleGraph; module: int; t: PType; op: TTypeAttachedOp; value: PSym) =
## we also need to record this to the packed module.
g.attachedOps[op][t.itemId] = value
# XXX Also add to the packed module!
proc completePartialOp*(g: ModuleGraph; module: int; t: PType; op: TTypeAttachedOp; value: PSym) =
discard "To implement"
proc getToStringProc*(g: ModuleGraph; t: PType): PSym =
result = g.enumToStringProcs.getOrDefault(t.itemId)
assert result != nil
proc setToStringProc*(g: ModuleGraph; t: PType; value: PSym) =
g.enumToStringProcs[t.itemId] = value
iterator methodsForGeneric*(g: ModuleGraph; t: PType): (int, PSym) =
for a, b in items g.methodsPerType.getOrDefault(t.itemId):
yield (a, b)
proc addMethodToGeneric*(g: ModuleGraph; module: int; t: PType; col: int; m: PSym) =
g.methodsPerType.mgetOrPut(t.itemId, @[]).add (col, m)
proc hasDisabledAsgn*(g: ModuleGraph; t: PType): bool =
let op = getAttachedOp(g, t, attachedAsgn)
result = op != nil and sfError in op.flags
proc copyTypeProps*(g: ModuleGraph; module: int; dest, src: PType) =
for k in low(TTypeAttachedOp)..high(TTypeAttachedOp):
let op = getAttachedOp(g, src, k)
if op != nil:
setAttachedOp(g, module, dest, k, op)
const const
cb64 = [ cb64 = [
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N",
@ -196,8 +152,11 @@ proc toBase64a(s: cstring, len: int): string =
template semtab*(m: PSym; g: ModuleGraph): TStrTable = template semtab*(m: PSym; g: ModuleGraph): TStrTable =
g.ifaces[m.position].interf g.ifaces[m.position].interf
proc cachedModule(g: ModuleGraph; m: PSym): bool {.inline.} = proc isCachedModule(g: ModuleGraph; module: int): bool {.inline.} =
m.position < g.packed.len and g.packed[m.position].status == loaded module < g.packed.len and g.packed[module].status == loaded
proc isCachedModule(g: ModuleGraph; m: PSym): bool {.inline.} =
isCachedModule(g, m.position)
proc simulateCachedModule*(g: ModuleGraph; moduleSym: PSym; m: PackedModule) = proc simulateCachedModule*(g: ModuleGraph; moduleSym: PSym; m: PackedModule) =
when false: when false:
@ -227,7 +186,7 @@ proc nextModuleIter*(mi: var ModuleIter; g: ModuleGraph): PSym =
result = nextIdentIter(mi.ti, g.ifaces[mi.modIndex].interf) result = nextIdentIter(mi.ti, g.ifaces[mi.modIndex].interf)
iterator allSyms*(g: ModuleGraph; m: PSym): PSym = iterator allSyms*(g: ModuleGraph; m: PSym): PSym =
if cachedModule(g, m): if isCachedModule(g, m):
var rodIt: RodIter var rodIt: RodIter
var r = initRodIterAllSyms(rodIt, g.config, g.cache, g.packed, FileIndex m.position) var r = initRodIterAllSyms(rodIt, g.config, g.cache, g.packed, FileIndex m.position)
while r != nil: while r != nil:
@ -239,7 +198,7 @@ iterator allSyms*(g: ModuleGraph; m: PSym): PSym =
yield s yield s
proc someSym*(g: ModuleGraph; m: PSym; name: PIdent): PSym = proc someSym*(g: ModuleGraph; m: PSym; name: PIdent): PSym =
if cachedModule(g, m): if isCachedModule(g, m):
result = interfaceSymbol(g.config, g.cache, g.packed, FileIndex(m.position), name) result = interfaceSymbol(g.config, g.cache, g.packed, FileIndex(m.position), name)
else: else:
result = strTableGet(g.ifaces[m.position].interf, name) result = strTableGet(g.ifaces[m.position].interf, name)
@ -254,6 +213,87 @@ iterator systemModuleSyms*(g: ModuleGraph; name: PIdent): PSym =
yield r yield r
r = nextModuleIter(mi, g) r = nextModuleIter(mi, g)
proc resolveType(g: ModuleGraph; t: var LazyType): PType =
result = t.typ
if result == nil and isCachedModule(g, t.id.module):
result = loadTypeFromId(g.config, g.cache, g.packed, t.id.module, t.id.packed)
t.typ = result
assert result != nil
proc resolveSym(g: ModuleGraph; t: var LazySym): PSym =
result = t.sym
if result == nil and isCachedModule(g, t.id.module):
result = loadSymFromId(g.config, g.cache, g.packed, t.id.module, t.id.packed)
t.sym = result
assert result != nil
proc resolveInst(g: ModuleGraph; t: var LazyInstantiation): PInstantiation =
result = t.inst
if result == nil and isCachedModule(g, t.module):
result = PInstantiation(sym: loadSymFromId(g.config, g.cache, g.packed, t.sym.module, t.sym.packed))
result.concreteTypes = newSeq[PType](t.concreteTypes.len)
for i in 0..high(result.concreteTypes):
result.concreteTypes[i] = loadTypeFromId(g.config, g.cache, g.packed,
t.concreteTypes[i].module, t.concreteTypes[i].packed)
t.inst = result
assert result != nil
iterator typeInstCacheItems*(g: ModuleGraph; s: PSym): PType =
if g.typeInstCache.contains(s.itemId):
let x = addr(g.typeInstCache[s.itemId])
for t in mitems(x[]):
yield resolveType(g, t)
iterator procInstCacheItems*(g: ModuleGraph; s: PSym): PInstantiation =
if g.procInstCache.contains(s.itemId):
let x = addr(g.procInstCache[s.itemId])
for t in mitems(x[]):
yield resolveInst(g, t)
proc getAttachedOp*(g: ModuleGraph; t: PType; op: TTypeAttachedOp): PSym =
## returns the requested attached operation for type `t`. Can return nil
## if no such operation exists.
result = g.attachedOps[op].getOrDefault(t.itemId)
proc setAttachedOp*(g: ModuleGraph; module: int; t: PType; op: TTypeAttachedOp; value: PSym) =
## we also need to record this to the packed module.
g.attachedOps[op][t.itemId] = value
# XXX Also add to the packed module!
proc setAttachedOpPartial*(g: ModuleGraph; module: int; t: PType; op: TTypeAttachedOp; value: PSym) =
## we also need to record this to the packed module.
g.attachedOps[op][t.itemId] = value
# XXX Also add to the packed module!
proc completePartialOp*(g: ModuleGraph; module: int; t: PType; op: TTypeAttachedOp; value: PSym) =
discard "To implement"
proc getToStringProc*(g: ModuleGraph; t: PType): PSym =
result = resolveSym(g, g.enumToStringProcs[t.itemId])
assert result != nil
proc setToStringProc*(g: ModuleGraph; t: PType; value: PSym) =
g.enumToStringProcs[t.itemId] = LazySym(sym: value)
iterator methodsForGeneric*(g: ModuleGraph; t: PType): (int, PSym) =
if g.methodsPerType.contains(t.itemId):
for it in mitems g.methodsPerType[t.itemId]:
yield (it[0], resolveSym(g, it[1]))
proc addMethodToGeneric*(g: ModuleGraph; module: int; t: PType; col: int; m: PSym) =
g.methodsPerType.mgetOrPut(t.itemId, @[]).add (col, LazySym(sym: m))
proc hasDisabledAsgn*(g: ModuleGraph; t: PType): bool =
let op = getAttachedOp(g, t, attachedAsgn)
result = op != nil and sfError in op.flags
proc copyTypeProps*(g: ModuleGraph; module: int; dest, src: PType) =
for k in low(TTypeAttachedOp)..high(TTypeAttachedOp):
let op = getAttachedOp(g, src, k)
if op != nil:
setAttachedOp(g, module, dest, k, op)
proc `$`*(u: SigHash): string = proc `$`*(u: SigHash): string =
toBase64a(cast[cstring](unsafeAddr u), sizeof(u)) toBase64a(cast[cstring](unsafeAddr u), sizeof(u))

View file

@ -111,6 +111,7 @@ proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags): P
else: else:
partialInitModule(result, graph, fileIdx, filename) partialInitModule(result, graph, fileIdx, filename)
replayStateChanges(result, graph) replayStateChanges(result, graph)
replayGenericCacheInformation(graph, fileIdx.int)
elif graph.isDirty(result): elif graph.isDirty(result):
result.flags.excl sfDirty result.flags.excl sfDirty
# reset module fields: # reset module fields:

View file

@ -9,6 +9,8 @@
## This module contains the data structures for the semantic checking phase. ## This module contains the data structures for the semantic checking phase.
import std / tables
import import
intsets, options, ast, astalgo, msgs, idents, renderer, intsets, options, ast, astalgo, msgs, idents, renderer,
magicsys, vmdef, modulegraphs, lineinfos, sets, pathutils magicsys, vmdef, modulegraphs, lineinfos, sets, pathutils
@ -551,6 +553,16 @@ proc storeRodNode*(c: PContext, n: PNode) =
if c.config.symbolFiles != disabledSf: if c.config.symbolFiles != disabledSf:
toPackedNodeTopLevel(n, c.encoder, c.packedRepr) toPackedNodeTopLevel(n, c.encoder, c.packedRepr)
proc addToGenericProcCache*(c: PContext; s: PSym; inst: PInstantiation) =
c.graph.procInstCache.mgetOrPut(s.itemId, @[]).add LazyInstantiation(module: c.module.position, inst: inst)
if c.config.symbolFiles != disabledSf:
storeInstantiation(c.encoder, c.packedRepr, s, inst)
proc addToGenericCache*(c: PContext; s: PSym; inst: PType) =
c.graph.typeInstCache.mgetOrPut(s.itemId, @[]).add LazyType(typ: inst)
if c.config.symbolFiles != disabledSf:
storeTypeInst(c.encoder, c.packedRepr, s, inst)
proc saveRodFile*(c: PContext) = proc saveRodFile*(c: PContext) =
if c.config.symbolFiles != disabledSf: if c.config.symbolFiles != disabledSf:
for (m, n) in PCtx(c.graph.vm).vmstateDiff: for (m, n) in PCtx(c.graph.vm).vmstateDiff:

View file

@ -378,7 +378,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
#if c.compilesContextId == 0: #if c.compilesContextId == 0:
rawHandleSelf(c, result) rawHandleSelf(c, result)
entry.compilesId = c.compilesContextId entry.compilesId = c.compilesContextId
addToGenericProcCache(c.graph, c.module.position, fn, entry) addToGenericProcCache(c, fn, entry)
c.generics.add(makeInstPair(fn, entry)) c.generics.add(makeInstPair(fn, entry))
if n[pragmasPos].kind != nkEmpty: if n[pragmasPos].kind != nkEmpty:
pragma(c, result, n[pragmasPos], allRoutinePragmas) pragma(c, result, n[pragmasPos], allRoutinePragmas)

View file

@ -1814,7 +1814,7 @@ proc hasObjParam(s: PSym): bool =
proc finishMethod(c: PContext, s: PSym) = proc finishMethod(c: PContext, s: PSym) =
if hasObjParam(s): if hasObjParam(s):
methodDef(c.graph, c.idgen, s, false) methodDef(c.graph, c.idgen, s)
proc semMethodPrototype(c: PContext; s: PSym; n: PNode) = proc semMethodPrototype(c: PContext; s: PSym; n: PNode) =
if isGenericRoutine(s): if isGenericRoutine(s):
@ -1839,7 +1839,7 @@ proc semMethodPrototype(c: PContext; s: PSym; n: PNode) =
# no sense either. # no sense either.
# and result[bodyPos].kind != nkEmpty: # and result[bodyPos].kind != nkEmpty:
if hasObjParam(s): if hasObjParam(s):
methodDef(c.graph, c.idgen, s, fromCache=false) methodDef(c.graph, c.idgen, s)
else: else:
localError(c.config, n.info, "'method' needs a parameter that has an object type") localError(c.config, n.info, "'method' needs a parameter that has an object type")

View file

@ -54,12 +54,12 @@ proc searchInstTypes*(g: ModuleGraph; key: PType): PType =
return inst return inst
proc cacheTypeInst(g: ModuleGraph; moduleId: int; inst: PType) = proc cacheTypeInst(c: PContext; inst: PType) =
let gt = inst[0] let gt = inst[0]
let t = if gt.kind == tyGenericBody: gt.lastSon else: gt let t = if gt.kind == tyGenericBody: gt.lastSon else: gt
if t.kind in {tyStatic, tyError, tyGenericParam} + tyTypeClasses: if t.kind in {tyStatic, tyError, tyGenericParam} + tyTypeClasses:
return return
addToGenericCache(g, moduleId, gt.sym, inst) addToGenericCache(c, gt.sym, inst)
type type
LayeredIdTable* = ref object LayeredIdTable* = ref object
@ -323,7 +323,7 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
var body = t[0] var body = t[0]
if body.kind != tyGenericBody: if body.kind != tyGenericBody:
internalError(cl.c.config, cl.info, "no generic body") internalError(cl.c.config, cl.info, "no generic body")
var header: PType = t var header = t
# search for some instantiation here: # search for some instantiation here:
if cl.allowMetaTypes: if cl.allowMetaTypes:
result = PType(idTableGet(cl.localCache, t)) result = PType(idTableGet(cl.localCache, t))
@ -364,7 +364,7 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
# we need to add the candidate here, before it's fully instantiated for # we need to add the candidate here, before it's fully instantiated for
# recursive instantions: # recursive instantions:
if not cl.allowMetaTypes: if not cl.allowMetaTypes:
cacheTypeInst(cl.c.graph, cl.c.module.position, result) cacheTypeInst(cl.c, result)
else: else:
idTablePut(cl.localCache, t, result) idTablePut(cl.localCache, t, result)