ic refactoring (#17778)

* minor IC documentation update

* IC: refactoring: removed the 'shared' type and fields, these were a leftover from an earlier design
This commit is contained in:
Andreas Rumpf 2021-04-19 11:48:06 +02:00 • committed by GitHub
commit 4b0b536419
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 146 additions and 159 deletions

View file

@ -27,7 +27,7 @@ type
proc isExportedToC(c: var AliveContext; g: PackedModuleGraph; symId: int32): bool = proc isExportedToC(c: var AliveContext; g: PackedModuleGraph; symId: int32): bool =
## "Exported to C" procs are special (these are marked with '.exportc') because these ## "Exported to C" procs are special (these are marked with '.exportc') because these
## must not be optimized away! ## must not be optimized away!
let symPtr = addr g[c.thisModule].fromDisk.sh.syms[symId] let symPtr = unsafeAddr g[c.thisModule].fromDisk.syms[symId]
let flags = symPtr.flags let flags = symPtr.flags
# due to a bug/limitation in the lambda lifting, unused inner procs # due to a bug/limitation in the lambda lifting, unused inner procs
# are not transformed correctly; issue (#411). However, the whole purpose here # are not transformed correctly; issue (#411). However, the whole purpose here
@ -39,7 +39,7 @@ proc isExportedToC(c: var AliveContext; g: PackedModuleGraph; symId: int32): boo
# XXX: This used to be a condition to: # XXX: This used to be a condition to:
# (sfExportc in prc.flags and lfExportLib in prc.loc.flags) or # (sfExportc in prc.flags and lfExportLib in prc.loc.flags) or
if sfCompilerProc in flags: if sfCompilerProc in flags:
c.compilerProcs[g[c.thisModule].fromDisk.sh.strings[symPtr.name]] = (c.thisModule, symId) c.compilerProcs[g[c.thisModule].fromDisk.strings[symPtr.name]] = (c.thisModule, symId)
template isNotGeneric(n: NodePos): bool = ithSon(tree, n, genericParamsPos).kind == nkEmpty template isNotGeneric(n: NodePos): bool = ithSon(tree, n, genericParamsPos).kind == nkEmpty
@ -47,17 +47,17 @@ proc followLater(c: var AliveContext; g: PackedModuleGraph; module: int; item: i
## Marks a symbol 'item' as used and later in 'followNow' the symbol's body will ## Marks a symbol 'item' as used and later in 'followNow' the symbol's body will
## be analysed. ## be analysed.
if not c.alive[module].containsOrIncl(item): if not c.alive[module].containsOrIncl(item):
var body = g[module].fromDisk.sh.syms[item].ast var body = g[module].fromDisk.syms[item].ast
if body != emptyNodeId: if body != emptyNodeId:
let opt = g[module].fromDisk.sh.syms[item].options let opt = g[module].fromDisk.syms[item].options
if g[module].fromDisk.sh.syms[item].kind in routineKinds: if g[module].fromDisk.syms[item].kind in routineKinds:
body = NodeId ithSon(g[module].fromDisk.bodies, NodePos body, bodyPos) body = NodeId ithSon(g[module].fromDisk.bodies, NodePos body, bodyPos)
c.stack.add((module, opt, NodePos(body))) c.stack.add((module, opt, NodePos(body)))
when false: when false:
let nid = g[module].fromDisk.sh.syms[item].name let nid = g[module].fromDisk.syms[item].name
if nid != LitId(0): if nid != LitId(0):
let name = g[module].fromDisk.sh.strings[nid] let name = g[module].fromDisk.strings[nid]
if name in ["nimFrame", "callDepthLimitReached"]: if name in ["nimFrame", "callDepthLimitReached"]:
echo "I was called! ", name, " body exists: ", body != emptyNodeId, " ", module, " ", item echo "I was called! ", name, " body exists: ", body != emptyNodeId, " ", module, " ", item
@ -66,12 +66,12 @@ proc requestCompilerProc(c: var AliveContext; g: PackedModuleGraph; name: string
followLater(c, g, module, item) followLater(c, g, module, item)
proc loadTypeKind(t: PackedItemId; c: AliveContext; g: PackedModuleGraph; toSkip: set[TTypeKind]): TTypeKind = proc loadTypeKind(t: PackedItemId; c: AliveContext; g: PackedModuleGraph; toSkip: set[TTypeKind]): TTypeKind =
template kind(t: ItemId): TTypeKind = g[t.module].fromDisk.sh.types[t.item].kind template kind(t: ItemId): TTypeKind = g[t.module].fromDisk.types[t.item].kind
var t2 = translateId(t, g, c.thisModule, c.decoder.config) var t2 = translateId(t, g, c.thisModule, c.decoder.config)
result = t2.kind result = t2.kind
while result in toSkip: while result in toSkip:
t2 = translateId(g[t2.module].fromDisk.sh.types[t2.item].types[^1], g, t2.module, c.decoder.config) t2 = translateId(g[t2.module].fromDisk.types[t2.item].types[^1], g, t2.module, c.decoder.config)
result = t2.kind result = t2.kind
proc rangeCheckAnalysis(c: var AliveContext; g: PackedModuleGraph; tree: PackedTree; n: NodePos) = proc rangeCheckAnalysis(c: var AliveContext; g: PackedModuleGraph; tree: PackedTree; n: NodePos) =

View file

@ -7,12 +7,8 @@ The frontend produces a set of `.rod` files. Every `.nim` module
produces its own `.rod` file. produces its own `.rod` file.
- The IR must be a faithful representation of the AST in memory. - The IR must be a faithful representation of the AST in memory.
- The backend can do its own caching but doesn't have to. - The backend can do its own caching but doesn't have to. In the
- We know by comparing 'nim check compiler/nim' against 'nim c compiler/nim' current implementation the backend also caches its results.
that 2/3 of the compiler's runtime is spent in the frontend. Hence we
implement IC for the frontend first and only later for the backend. The
backend will recompile everything until we implement its own caching
mechanisms.
Advantage of the "set of files" vs the previous global database: Advantage of the "set of files" vs the previous global database:
- By construction, we either read from the `.rod` file or from the - By construction, we either read from the `.rod` file or from the

View file

@ -51,7 +51,12 @@ type
emittedTypeInfo*: seq[string] emittedTypeInfo*: seq[string]
backendFlags*: set[ModuleBackendFlag] backendFlags*: set[ModuleBackendFlag]
sh*: Shared syms*: seq[PackedSym]
types*: seq[PackedType]
strings*: BiTable[string] # we could share these between modules.
numbers*: BiTable[BiggestInt] # we also store floats in here so
# that we can assure that every bit is kept
cfg: PackedConfig cfg: PackedConfig
PackedEncoder* = object PackedEncoder* = object
@ -66,6 +71,50 @@ type
symMarker*: IntSet #Table[ItemId, SymId] # ItemId.item -> SymId symMarker*: IntSet #Table[ItemId, SymId] # ItemId.item -> SymId
config*: ConfigRef config*: ConfigRef
proc toString*(tree: PackedTree; n: NodePos; m: PackedModule; nesting: int;
result: var string) =
let pos = n.int
if result.len > 0 and result[^1] notin {' ', '\n'}:
result.add ' '
result.add $tree[pos].kind
case tree.nodes[pos].kind
of nkNone, nkEmpty, nkNilLit, nkType: discard
of nkIdent, nkStrLit..nkTripleStrLit:
result.add " "
result.add m.strings[LitId tree.nodes[pos].operand]
of nkSym:
result.add " "
result.add m.strings[m.syms[tree.nodes[pos].operand].name]
of directIntLit:
result.add " "
result.addInt tree.nodes[pos].operand
of externSIntLit:
result.add " "
result.addInt m.numbers[LitId tree.nodes[pos].operand]
of externUIntLit:
result.add " "
result.add $cast[uint64](m.numbers[LitId tree.nodes[pos].operand])
of nkFloatLit..nkFloat128Lit:
result.add " "
result.add $cast[BiggestFloat](m.numbers[LitId tree.nodes[pos].operand])
else:
result.add "(\n"
for i in 1..(nesting+1)*2: result.add ' '
for child in sonsReadonly(tree, n):
toString(tree, child, m, nesting + 1, result)
result.add "\n"
for i in 1..nesting*2: result.add ' '
result.add ")"
#for i in 1..nesting*2: result.add ' '
proc toString*(tree: PackedTree; n: NodePos; m: PackedModule): string =
result = ""
toString(tree, n, m, 0, result)
proc debug*(tree: PackedTree; m: PackedModule) =
stdout.write toString(tree, NodePos 0, m)
proc isActive*(e: PackedEncoder): bool = e.config != nil proc isActive*(e: PackedEncoder): bool = e.config != nil
proc disable(e: var PackedEncoder) = e.config = nil proc disable(e: var PackedEncoder) = e.config = nil
@ -134,14 +183,14 @@ proc toLitId(x: FileIndex; c: var PackedEncoder; m: var PackedModule): LitId =
result = c.filenames.getOrDefault(x) result = c.filenames.getOrDefault(x)
if result == LitId(0): if result == LitId(0):
let p = msgs.toFullPath(c.config, x) let p = msgs.toFullPath(c.config, x)
result = getOrIncl(m.sh.strings, p) result = getOrIncl(m.strings, p)
c.filenames[x] = result c.filenames[x] = result
c.lastFile = x c.lastFile = x
c.lastLit = result c.lastLit = result
assert result != LitId(0) assert result != LitId(0)
proc toFileIndex*(x: LitId; m: PackedModule; config: ConfigRef): FileIndex = proc toFileIndex*(x: LitId; m: PackedModule; config: ConfigRef): FileIndex =
result = msgs.fileInfoIdx(config, AbsoluteFile m.sh.strings[x]) result = msgs.fileInfoIdx(config, AbsoluteFile m.strings[x])
proc includesIdentical(m: var PackedModule; config: ConfigRef): bool = proc includesIdentical(m: var PackedModule; config: ConfigRef): bool =
for it in mitems(m.includes): for it in mitems(m.includes):
@ -151,7 +200,6 @@ proc includesIdentical(m: var PackedModule; config: ConfigRef): bool =
proc initEncoder*(c: var PackedEncoder; m: var PackedModule; moduleSym: PSym; config: ConfigRef; pc: PackedConfig) = proc initEncoder*(c: var PackedEncoder; m: var PackedModule; moduleSym: PSym; config: ConfigRef; pc: PackedConfig) =
## setup a context for serializing to packed ast ## setup a context for serializing to packed ast
m.sh = Shared()
c.thisModule = moduleSym.itemId.module c.thisModule = moduleSym.itemId.module
c.config = config c.config = config
m.moduleFlags = moduleSym.flags m.moduleFlags = moduleSym.flags
@ -179,11 +227,11 @@ proc addImportFileDep*(c: var PackedEncoder; m: var PackedModule; f: FileIndex)
m.imports.add toLitId(f, c, m) m.imports.add toLitId(f, c, m)
proc addHidden*(c: var PackedEncoder; m: var PackedModule; s: PSym) = proc addHidden*(c: var PackedEncoder; m: var PackedModule; s: PSym) =
let nameId = getOrIncl(m.sh.strings, s.name.s) let nameId = getOrIncl(m.strings, s.name.s)
m.hidden.add((nameId, s.itemId.item)) m.hidden.add((nameId, s.itemId.item))
proc addExported*(c: var PackedEncoder; m: var PackedModule; s: PSym) = proc addExported*(c: var PackedEncoder; m: var PackedModule; s: PSym) =
let nameId = getOrIncl(m.sh.strings, s.name.s) let nameId = getOrIncl(m.strings, s.name.s)
m.exports.add((nameId, s.itemId.item)) m.exports.add((nameId, s.itemId.item))
proc addConverter*(c: var PackedEncoder; m: var PackedModule; s: PSym) = proc addConverter*(c: var PackedEncoder; m: var PackedModule; s: PSym) =
@ -201,12 +249,12 @@ proc addMethod*(c: var PackedEncoder; m: var PackedModule; s: PSym) =
m.methods.add s.itemId.item m.methods.add 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.strings, s.name.s)
m.reexports.add((nameId, PackedItemId(module: toLitId(s.itemId.module.FileIndex, c, m), m.reexports.add((nameId, PackedItemId(module: toLitId(s.itemId.module.FileIndex, c, m),
item: s.itemId.item))) item: s.itemId.item)))
proc addCompilerProc*(c: var PackedEncoder; m: var PackedModule; s: PSym) = proc addCompilerProc*(c: var PackedEncoder; m: var PackedModule; s: PSym) =
let nameId = getOrIncl(m.sh.strings, s.name.s) let nameId = getOrIncl(m.strings, s.name.s)
m.compilerProcs.add((nameId, s.itemId.item)) m.compilerProcs.add((nameId, s.itemId.item))
proc toPackedNode*(n: PNode; ir: var PackedTree; c: var PackedEncoder; m: var PackedModule) proc toPackedNode*(n: PNode; ir: var PackedTree; c: var PackedEncoder; m: var PackedModule)
@ -225,11 +273,11 @@ proc flush(c: var PackedEncoder; m: var PackedModule) =
proc toLitId(x: string; m: var PackedModule): LitId = proc toLitId(x: string; m: var PackedModule): LitId =
## store a string as a literal ## store a string as a literal
result = getOrIncl(m.sh.strings, x) result = getOrIncl(m.strings, x)
proc toLitId(x: BiggestInt; m: var PackedModule): LitId = proc toLitId(x: BiggestInt; m: var PackedModule): LitId =
## store an integer as a literal ## store an integer as a literal
result = getOrIncl(m.sh.numbers, x) result = getOrIncl(m.numbers, x)
proc toPackedInfo(x: TLineInfo; c: var PackedEncoder; m: var PackedModule): PackedLineInfo = proc toPackedInfo(x: TLineInfo; c: var PackedEncoder; m: var PackedModule): PackedLineInfo =
PackedLineInfo(line: x.line, col: x.col, file: toLitId(x.fileIndex, c, m)) PackedLineInfo(line: x.line, col: x.col, file: toLitId(x.fileIndex, c, m))
@ -299,8 +347,8 @@ proc storeType(t: PType; c: var PackedEncoder; m: var PackedModule): PackedItemI
result = PackedItemId(module: toLitId(t.uniqueId.module.FileIndex, c, m), item: t.uniqueId.item) result = PackedItemId(module: toLitId(t.uniqueId.module.FileIndex, c, m), item: t.uniqueId.item)
if t.uniqueId.module == c.thisModule and not c.typeMarker.containsOrIncl(t.uniqueId.item): if t.uniqueId.module == c.thisModule and not c.typeMarker.containsOrIncl(t.uniqueId.item):
if t.uniqueId.item >= m.sh.types.len: if t.uniqueId.item >= m.types.len:
setLen m.sh.types, t.uniqueId.item+1 setLen m.types, t.uniqueId.item+1
var p = PackedType(kind: t.kind, flags: t.flags, callConv: t.callConv, var p = PackedType(kind: t.kind, flags: t.flags, callConv: t.callConv,
size: t.size, align: t.align, nonUniqueId: t.itemId.item, size: t.size, align: t.align, nonUniqueId: t.itemId.item,
@ -315,7 +363,7 @@ proc storeType(t: PType; c: var PackedEncoder; m: var PackedModule): PackedItemI
p.owner = t.owner.safeItemId(c, m) p.owner = t.owner.safeItemId(c, m)
# fill the reserved slot, nothing else: # fill the reserved slot, nothing else:
m.sh.types[t.uniqueId.item] = p m.types[t.uniqueId.item] = p
proc toPackedLib(l: PLib; c: var PackedEncoder; m: var PackedModule): PackedLib = proc toPackedLib(l: PLib; c: var PackedEncoder; m: var PackedModule): PackedLib =
## the plib hangs off the psym via the .annex field ## the plib hangs off the psym via the .annex field
@ -334,8 +382,8 @@ proc storeSym*(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId
result = PackedItemId(module: toLitId(s.itemId.module.FileIndex, c, m), item: s.itemId.item) result = PackedItemId(module: toLitId(s.itemId.module.FileIndex, c, m), item: s.itemId.item)
if s.itemId.module == c.thisModule and not c.symMarker.containsOrIncl(s.itemId.item): if s.itemId.module == c.thisModule and not c.symMarker.containsOrIncl(s.itemId.item):
if s.itemId.item >= m.sh.syms.len: if s.itemId.item >= m.syms.len:
setLen m.sh.syms, s.itemId.item+1 setLen m.syms, s.itemId.item+1
assert sfForward notin s.flags assert sfForward notin s.flags
@ -363,7 +411,7 @@ proc storeSym*(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId
p.cname = toLitId(s.cname, m) p.cname = toLitId(s.cname, m)
# fill the reserved slot, nothing else: # fill the reserved slot, nothing else:
m.sh.syms[s.itemId.item] = p m.syms[s.itemId.item] = p
proc addModuleRef(n: PNode; ir: var PackedTree; c: var PackedEncoder; m: var PackedModule) = proc addModuleRef(n: PNode; ir: var PackedTree; c: var PackedEncoder; m: var PackedModule) =
## add a remote symbol reference to the tree ## add a remote symbol reference to the tree
@ -387,7 +435,7 @@ proc toPackedNode*(n: PNode; ir: var PackedTree; c: var PackedEncoder; m: var Pa
typeId: storeTypeLater(n.typ, c, m), info: info) typeId: storeTypeLater(n.typ, c, m), info: info)
of nkIdent: of nkIdent:
ir.nodes.add PackedNode(kind: n.kind, flags: n.flags, ir.nodes.add PackedNode(kind: n.kind, flags: n.flags,
operand: int32 getOrIncl(m.sh.strings, n.ident.s), operand: int32 getOrIncl(m.strings, n.ident.s),
typeId: storeTypeLater(n.typ, c, m), info: info) typeId: storeTypeLater(n.typ, c, m), info: info)
of nkSym: of nkSym:
if n.sym.itemId.module == c.thisModule: if n.sym.itemId.module == c.thisModule:
@ -405,15 +453,15 @@ proc toPackedNode*(n: PNode; ir: var PackedTree; c: var PackedEncoder; m: var Pa
typeId: storeTypeLater(n.typ, c, m), info: info) typeId: storeTypeLater(n.typ, c, m), info: info)
of externIntLit: of externIntLit:
ir.nodes.add PackedNode(kind: n.kind, flags: n.flags, ir.nodes.add PackedNode(kind: n.kind, flags: n.flags,
operand: int32 getOrIncl(m.sh.numbers, n.intVal), operand: int32 getOrIncl(m.numbers, n.intVal),
typeId: storeTypeLater(n.typ, c, m), info: info) typeId: storeTypeLater(n.typ, c, m), info: info)
of nkStrLit..nkTripleStrLit: of nkStrLit..nkTripleStrLit:
ir.nodes.add PackedNode(kind: n.kind, flags: n.flags, ir.nodes.add PackedNode(kind: n.kind, flags: n.flags,
operand: int32 getOrIncl(m.sh.strings, n.strVal), operand: int32 getOrIncl(m.strings, n.strVal),
typeId: storeTypeLater(n.typ, c, m), info: info) typeId: storeTypeLater(n.typ, c, m), info: info)
of nkFloatLit..nkFloat128Lit: of nkFloatLit..nkFloat128Lit:
ir.nodes.add PackedNode(kind: n.kind, flags: n.flags, ir.nodes.add PackedNode(kind: n.kind, flags: n.flags,
operand: int32 getOrIncl(m.sh.numbers, cast[BiggestInt](n.floatVal)), operand: int32 getOrIncl(m.numbers, cast[BiggestInt](n.floatVal)),
typeId: storeTypeLater(n.typ, c, m), info: info) typeId: storeTypeLater(n.typ, c, m), info: info)
else: else:
let patchPos = ir.prepare(n.kind, n.flags, let patchPos = ir.prepare(n.kind, n.flags,
@ -499,7 +547,6 @@ proc loadError(err: RodFileError; filename: AbsoluteFile; config: ConfigRef;) =
proc loadRodFile*(filename: AbsoluteFile; m: var PackedModule; config: ConfigRef; proc loadRodFile*(filename: AbsoluteFile; m: var PackedModule; config: ConfigRef;
ignoreConfig = false): RodFileError = ignoreConfig = false): RodFileError =
m.sh = Shared()
var f = rodfiles.open(filename.string) var f = rodfiles.open(filename.string)
f.loadHeader() f.loadHeader()
f.loadSection configSection f.loadSection configSection
@ -519,7 +566,7 @@ proc loadRodFile*(filename: AbsoluteFile; m: var PackedModule; config: ConfigRef
f.loadSection section f.loadSection section
f.load data f.load data
loadTabSection stringsSection, m.sh.strings loadTabSection stringsSection, m.strings
loadSeqSection checkSumsSection, m.includes loadSeqSection checkSumsSection, m.includes
if not includesIdentical(m, config): if not includesIdentical(m, config):
@ -527,7 +574,7 @@ proc loadRodFile*(filename: AbsoluteFile; m: var PackedModule; config: ConfigRef
loadSeqSection depsSection, m.imports loadSeqSection depsSection, m.imports
loadTabSection numbersSection, m.sh.numbers loadTabSection numbersSection, m.numbers
loadSeqSection exportsSection, m.exports loadSeqSection exportsSection, m.exports
loadSeqSection hiddenSection, m.hidden loadSeqSection hiddenSection, m.hidden
@ -545,8 +592,8 @@ proc loadRodFile*(filename: AbsoluteFile; m: var PackedModule; config: ConfigRef
loadSeqSection toReplaySection, m.toReplay.nodes loadSeqSection toReplaySection, m.toReplay.nodes
loadSeqSection topLevelSection, m.topLevel.nodes loadSeqSection topLevelSection, m.topLevel.nodes
loadSeqSection bodiesSection, m.bodies.nodes loadSeqSection bodiesSection, m.bodies.nodes
loadSeqSection symsSection, m.sh.syms loadSeqSection symsSection, m.syms
loadSeqSection typesSection, m.sh.types loadSeqSection typesSection, m.types
loadSeqSection typeInstCacheSection, m.typeInstCache loadSeqSection typeInstCacheSection, m.typeInstCache
loadSeqSection procInstCacheSection, m.procInstCache loadSeqSection procInstCacheSection, m.procInstCache
@ -586,13 +633,13 @@ proc saveRodFile*(filename: AbsoluteFile; encoder: var PackedEncoder; m: var Pac
f.storeSection section f.storeSection section
f.store data f.store data
storeTabSection stringsSection, m.sh.strings storeTabSection stringsSection, m.strings
storeSeqSection checkSumsSection, m.includes storeSeqSection checkSumsSection, m.includes
storeSeqSection depsSection, m.imports storeSeqSection depsSection, m.imports
storeTabSection numbersSection, m.sh.numbers storeTabSection numbersSection, m.numbers
storeSeqSection exportsSection, m.exports storeSeqSection exportsSection, m.exports
storeSeqSection hiddenSection, m.hidden storeSeqSection hiddenSection, m.hidden
@ -610,9 +657,9 @@ proc saveRodFile*(filename: AbsoluteFile; encoder: var PackedEncoder; m: var Pac
storeSeqSection topLevelSection, m.topLevel.nodes storeSeqSection topLevelSection, m.topLevel.nodes
storeSeqSection bodiesSection, m.bodies.nodes storeSeqSection bodiesSection, m.bodies.nodes
storeSeqSection symsSection, m.sh.syms storeSeqSection symsSection, m.syms
storeSeqSection typesSection, m.sh.types storeSeqSection typesSection, m.types
storeSeqSection typeInstCacheSection, m.typeInstCache storeSeqSection typeInstCacheSection, m.typeInstCache
storeSeqSection procInstCacheSection, m.procInstCache storeSeqSection procInstCacheSection, m.procInstCache
@ -700,17 +747,17 @@ proc loadNodes*(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int;
of nkEmpty, nkNilLit, nkType: of nkEmpty, nkNilLit, nkType:
discard discard
of nkIdent: of nkIdent:
result.ident = getIdent(c.cache, g[thisModule].fromDisk.sh.strings[n.litId]) result.ident = getIdent(c.cache, g[thisModule].fromDisk.strings[n.litId])
of nkSym: of nkSym:
result.sym = loadSym(c, g, thisModule, PackedItemId(module: LitId(0), item: tree.nodes[n.int].operand)) result.sym = loadSym(c, g, thisModule, PackedItemId(module: LitId(0), item: tree.nodes[n.int].operand))
of directIntLit: of directIntLit:
result.intVal = tree.nodes[n.int].operand result.intVal = tree.nodes[n.int].operand
of externIntLit: of externIntLit:
result.intVal = g[thisModule].fromDisk.sh.numbers[n.litId] result.intVal = g[thisModule].fromDisk.numbers[n.litId]
of nkStrLit..nkTripleStrLit: of nkStrLit..nkTripleStrLit:
result.strVal = g[thisModule].fromDisk.sh.strings[n.litId] result.strVal = g[thisModule].fromDisk.strings[n.litId]
of nkFloatLit..nkFloat128Lit: of nkFloatLit..nkFloat128Lit:
result.floatVal = cast[BiggestFloat](g[thisModule].fromDisk.sh.numbers[n.litId]) result.floatVal = cast[BiggestFloat](g[thisModule].fromDisk.numbers[n.litId])
of nkModuleRef: of nkModuleRef:
let (n1, n2) = sons2(tree, n) let (n1, n2) = sons2(tree, n)
assert n1.kind == nkInt32Lit assert n1.kind == nkInt32Lit
@ -767,7 +814,7 @@ proc symHeaderFromPacked(c: var PackedDecoder; g: var PackedModuleGraph;
options: s.options, options: s.options,
position: if s.kind in {skForVar, skVar, skLet, skTemp}: 0 else: s.position, position: if s.kind in {skForVar, skVar, skLet, skTemp}: 0 else: s.position,
offset: if s.kind in routineKinds: defaultOffset else: s.offset, offset: if s.kind in routineKinds: defaultOffset else: s.offset,
name: getIdent(c.cache, g[si].fromDisk.sh.strings[s.name]) name: getIdent(c.cache, g[si].fromDisk.strings[s.name])
) )
template loadAstBody(p, field) = template loadAstBody(p, field) =
@ -785,7 +832,7 @@ proc loadLib(c: var PackedDecoder; g: var PackedModuleGraph;
result = nil result = nil
else: else:
result = PLib(generated: l.generated, isOverriden: l.isOverriden, result = PLib(generated: l.generated, isOverriden: l.isOverriden,
kind: l.kind, name: rope g[si].fromDisk.sh.strings[l.name]) kind: l.kind, name: rope g[si].fromDisk.strings[l.name])
loadAstBody(l, path) loadAstBody(l, path)
proc symBodyFromPacked(c: var PackedDecoder; g: var PackedModuleGraph; proc symBodyFromPacked(c: var PackedDecoder; g: var PackedModuleGraph;
@ -798,14 +845,14 @@ proc symBodyFromPacked(c: var PackedDecoder; g: var PackedModuleGraph;
loadAstBody(s, ast) loadAstBody(s, ast)
result.annex = loadLib(c, g, si, item, s.annex) result.annex = loadLib(c, g, si, item, s.annex)
when hasFFI: when hasFFI:
result.cname = g[si].fromDisk.sh.strings[s.cname] result.cname = g[si].fromDisk.strings[s.cname]
if s.kind in {skLet, skVar, skField, skForVar}: if s.kind in {skLet, skVar, skField, skForVar}:
result.guard = loadSym(c, g, si, s.guard) result.guard = loadSym(c, g, si, s.guard)
result.bitsize = s.bitsize result.bitsize = s.bitsize
result.alignment = s.alignment result.alignment = s.alignment
result.owner = loadSym(c, g, si, s.owner) result.owner = loadSym(c, g, si, s.owner)
let externalName = g[si].fromDisk.sh.strings[s.externalName] let externalName = g[si].fromDisk.strings[s.externalName]
if externalName != "": if externalName != "":
result.loc.r = rope externalName result.loc.r = rope externalName
result.loc.flags = s.locFlags result.loc.flags = s.locFlags
@ -818,14 +865,14 @@ proc loadSym(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; s:
assert g[si].status in {loaded, storing, stored} assert g[si].status in {loaded, storing, stored}
if not g[si].symsInit: if not g[si].symsInit:
g[si].symsInit = true g[si].symsInit = true
setLen g[si].syms, g[si].fromDisk.sh.syms.len setLen g[si].syms, g[si].fromDisk.syms.len
if g[si].syms[s.item] == nil: if g[si].syms[s.item] == nil:
if g[si].fromDisk.sh.syms[s.item].kind != skModule: if g[si].fromDisk.syms[s.item].kind != skModule:
result = symHeaderFromPacked(c, g, g[si].fromDisk.sh.syms[s.item], si, s.item) result = symHeaderFromPacked(c, g, g[si].fromDisk.syms[s.item], si, s.item)
# store it here early on, so that recursions work properly: # store it here early on, so that recursions work properly:
g[si].syms[s.item] = result g[si].syms[s.item] = result
symBodyFromPacked(c, g, g[si].fromDisk.sh.syms[s.item], si, s.item, result) symBodyFromPacked(c, g, g[si].fromDisk.syms[s.item], si, s.item, result)
else: else:
result = g[si].module result = g[si].module
assert result != nil assert result != nil
@ -866,13 +913,13 @@ proc loadType(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; t
if not g[si].typesInit: if not g[si].typesInit:
g[si].typesInit = true g[si].typesInit = true
setLen g[si].types, g[si].fromDisk.sh.types.len setLen g[si].types, g[si].fromDisk.types.len
if g[si].types[t.item] == nil: if g[si].types[t.item] == nil:
result = typeHeaderFromPacked(c, g, g[si].fromDisk.sh.types[t.item], si, t.item) result = typeHeaderFromPacked(c, g, g[si].fromDisk.types[t.item], si, t.item)
# store it here early on, so that recursions work properly: # store it here early on, so that recursions work properly:
g[si].types[t.item] = result g[si].types[t.item] = result
typeBodyFromPacked(c, g, g[si].fromDisk.sh.types[t.item], si, t.item, result) typeBodyFromPacked(c, g, g[si].fromDisk.types[t.item], si, t.item, result)
else: else:
result = g[si].types[t.item] result = g[si].types[t.item]
assert result.itemId.item > 0 assert result.itemId.item > 0
@ -897,7 +944,7 @@ proc setupLookupTables(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCa
let e2 = let e2 =
when e[1] is PackedItemId: e[1] when e[1] is PackedItemId: e[1]
else: PackedItemId(module: LitId(0), item: e[1]) else: PackedItemId(module: LitId(0), item: e[1])
iface.mgetOrPut(cache.getIdent(m.fromDisk.sh.strings[nameLit]), @[]).add(e2) iface.mgetOrPut(cache.getIdent(m.fromDisk.strings[nameLit]), @[]).add(e2)
for e in m.fromDisk.exports: for e in m.fromDisk.exports:
m.iface.impl(e) m.iface.impl(e)
@ -1000,7 +1047,7 @@ proc loadProcBody*(config: ConfigRef, cache: IdentCache;
lastFile: FileIndex(-1), lastFile: FileIndex(-1),
config: config, config: config,
cache: cache) cache: cache)
let pos = g[mId].fromDisk.sh.syms[s.itemId.item].ast let pos = g[mId].fromDisk.syms[s.itemId.item].ast
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)
@ -1042,15 +1089,15 @@ proc translateId*(id: PackedItemId; g: PackedModuleGraph; thisModule: int; confi
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.syms):
if m.sh.syms[i].kind == skUnknown: if m.syms[i].kind == skUnknown:
echo "EMPTY ID ", i, " module ", moduleId, " ", toFullPath(config, FileIndex(moduleId)) echo "EMPTY ID ", i, " module ", moduleId, " ", toFullPath(config, FileIndex(moduleId))
inc bugs inc bugs
assert bugs == 0 assert bugs == 0
when false: when false:
var nones = 0 var nones = 0
for i in 1 .. high(m.sh.types): for i in 1 .. high(m.types):
inc nones, m.sh.types[i].kind == tyNone inc nones, m.types[i].kind == tyNone
assert nones < 1 assert nones < 1
proc simulateLoadedModule*(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache; proc simulateLoadedModule*(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache;
@ -1133,13 +1180,13 @@ proc interfaceSymbol*(config: ConfigRef, cache: IdentCache;
result = loadSym(decoder, g, int(module), values[0]) result = loadSym(decoder, g, int(module), values[0])
proc idgenFromLoadedModule*(m: LoadedModule): IdGenerator = proc idgenFromLoadedModule*(m: LoadedModule): IdGenerator =
IdGenerator(module: m.module.itemId.module, symId: int32 m.fromDisk.sh.syms.len, IdGenerator(module: m.module.itemId.module, symId: int32 m.fromDisk.syms.len,
typeId: int32 m.fromDisk.sh.types.len) typeId: int32 m.fromDisk.types.len)
proc searchForCompilerproc*(m: LoadedModule; name: string): int32 = proc searchForCompilerproc*(m: LoadedModule; name: string): int32 =
# slow, linear search, but the results are cached: # slow, linear search, but the results are cached:
for it in items(m.fromDisk.compilerProcs): for it in items(m.fromDisk.compilerProcs):
if m.fromDisk.sh.strings[it[0]] == name: if m.fromDisk.strings[it[0]] == name:
return it[1] return it[1]
return -1 return -1
@ -1154,26 +1201,26 @@ proc rodViewer*(rodfile: AbsoluteFile; config: ConfigRef, cache: IdentCache) =
when true: when true:
echo "exports:" echo "exports:"
for ex in m.exports: for ex in m.exports:
echo " ", m.sh.strings[ex[0]], " local ID: ", ex[1] echo " ", m.strings[ex[0]], " local ID: ", ex[1]
assert ex[0] == m.sh.syms[ex[1]].name assert ex[0] == m.syms[ex[1]].name
# ex[1] int32 # ex[1] int32
echo "reexports:" echo "reexports:"
for ex in m.reexports: for ex in m.reexports:
echo " ", m.sh.strings[ex[0]] echo " ", m.strings[ex[0]]
# reexports*: seq[(LitId, PackedItemId)] # reexports*: seq[(LitId, PackedItemId)]
echo "hidden: " & $m.hidden.len echo "hidden: " & $m.hidden.len
for ex in m.hidden: for ex in m.hidden:
echo " ", m.sh.strings[ex[0]], " local ID: ", ex[1] echo " ", m.strings[ex[0]], " local ID: ", ex[1]
echo "all symbols" echo "all symbols"
for i in 0..high(m.sh.syms): for i in 0..high(m.syms):
if m.sh.syms[i].name != LitId(0): if m.syms[i].name != LitId(0):
echo " ", m.sh.strings[m.sh.syms[i].name], " local ID: ", i, " kind ", m.sh.syms[i].kind echo " ", m.strings[m.syms[i].name], " local ID: ", i, " kind ", m.syms[i].kind
else: else:
echo " <anon symbol?> local ID: ", i, " kind ", m.sh.syms[i].kind echo " <anon symbol?> local ID: ", i, " kind ", m.syms[i].kind
echo "symbols: ", m.sh.syms.len, " types: ", m.sh.types.len, echo "symbols: ", m.syms.len, " types: ", m.types.len,
" top level nodes: ", m.topLevel.nodes.len, " other nodes: ", m.bodies.nodes.len, " top level nodes: ", m.topLevel.nodes.len, " other nodes: ", m.bodies.nodes.len,
" strings: ", m.sh.strings.len, " numbers: ", m.sh.numbers.len " strings: ", m.strings.len, " numbers: ", m.numbers.len

View file

@ -42,12 +42,12 @@ proc checkType(c: var CheckedContext; typeId: PackedItemId) =
if not c.checkedTypes.containsOrIncl(itemId): if not c.checkedTypes.containsOrIncl(itemId):
let oldThisModule = c.thisModule let oldThisModule = c.thisModule
c.thisModule = itemId.module c.thisModule = itemId.module
checkTypeObj c, c.g.packed[itemId.module].fromDisk.sh.types[itemId.item] checkTypeObj c, c.g.packed[itemId.module].fromDisk.types[itemId.item]
c.thisModule = oldThisModule c.thisModule = oldThisModule
proc checkSym(c: var CheckedContext; s: PackedSym) = proc checkSym(c: var CheckedContext; s: PackedSym) =
if s.name != LitId(0): if s.name != LitId(0):
assert c.g.packed[c.thisModule].fromDisk.sh.strings.hasLitId s.name assert c.g.packed[c.thisModule].fromDisk.strings.hasLitId s.name
checkType c, s.typ checkType c, s.typ
if s.ast != emptyNodeId: if s.ast != emptyNodeId:
checkNode(c, c.g.packed[c.thisModule].fromDisk.bodies, NodePos s.ast) checkNode(c, c.g.packed[c.thisModule].fromDisk.bodies, NodePos s.ast)
@ -57,14 +57,14 @@ proc checkSym(c: var CheckedContext; s: PackedSym) =
proc checkLocalSym(c: var CheckedContext; item: int32) = proc checkLocalSym(c: var CheckedContext; item: int32) =
let itemId = ItemId(module: c.thisModule, item: item) let itemId = ItemId(module: c.thisModule, item: item)
if not c.checkedSyms.containsOrIncl(itemId): if not c.checkedSyms.containsOrIncl(itemId):
checkSym c, c.g.packed[c.thisModule].fromDisk.sh.syms[item] checkSym c, c.g.packed[c.thisModule].fromDisk.syms[item]
proc checkForeignSym(c: var CheckedContext; symId: PackedItemId) = proc checkForeignSym(c: var CheckedContext; symId: PackedItemId) =
let itemId = translateId(symId, c.g.packed, c.thisModule, c.g.config) let itemId = translateId(symId, c.g.packed, c.thisModule, c.g.config)
if not c.checkedSyms.containsOrIncl(itemId): if not c.checkedSyms.containsOrIncl(itemId):
let oldThisModule = c.thisModule let oldThisModule = c.thisModule
c.thisModule = itemId.module c.thisModule = itemId.module
checkSym c, c.g.packed[itemId.module].fromDisk.sh.syms[itemId.item] checkSym c, c.g.packed[itemId.module].fromDisk.syms[itemId.item]
c.thisModule = oldThisModule c.thisModule = oldThisModule
proc checkNode(c: var CheckedContext; tree: PackedTree; n: NodePos) = proc checkNode(c: var CheckedContext; tree: PackedTree; n: NodePos) =
@ -74,15 +74,15 @@ proc checkNode(c: var CheckedContext; tree: PackedTree; n: NodePos) =
of nkEmpty, nkNilLit, nkType, nkNilRodNode: of nkEmpty, nkNilLit, nkType, nkNilRodNode:
discard discard
of nkIdent: of nkIdent:
assert c.g.packed[c.thisModule].fromDisk.sh.strings.hasLitId n.litId assert c.g.packed[c.thisModule].fromDisk.strings.hasLitId n.litId
of nkSym: of nkSym:
checkLocalSym(c, tree.nodes[n.int].operand) checkLocalSym(c, tree.nodes[n.int].operand)
of directIntLit: of directIntLit:
discard discard
of externIntLit, nkFloatLit..nkFloat128Lit: of externIntLit, nkFloatLit..nkFloat128Lit:
assert c.g.packed[c.thisModule].fromDisk.sh.numbers.hasLitId n.litId assert c.g.packed[c.thisModule].fromDisk.numbers.hasLitId n.litId
of nkStrLit..nkTripleStrLit: of nkStrLit..nkTripleStrLit:
assert c.g.packed[c.thisModule].fromDisk.sh.strings.hasLitId n.litId assert c.g.packed[c.thisModule].fromDisk.strings.hasLitId n.litId
of nkModuleRef: of nkModuleRef:
let (n1, n2) = sons2(tree, n) let (n1, n2) = sons2(tree, n)
assert n1.kind == nkInt32Lit assert n1.kind == nkInt32Lit
@ -97,25 +97,25 @@ proc checkTree(c: var CheckedContext; t: PackedTree) =
proc checkLocalSymIds(c: var CheckedContext; m: PackedModule; symIds: seq[int32]) = proc checkLocalSymIds(c: var CheckedContext; m: PackedModule; symIds: seq[int32]) =
for symId in symIds: for symId in symIds:
assert symId >= 0 and symId < m.sh.syms.len, $symId & " " & $m.sh.syms.len assert symId >= 0 and symId < m.syms.len, $symId & " " & $m.syms.len
proc checkModule(c: var CheckedContext; m: PackedModule) = proc checkModule(c: var CheckedContext; m: PackedModule) =
# We check that: # We check that:
# - Every symbol references existing types and symbols. # - Every symbol references existing types and symbols.
# - Every tree node references existing types and symbols. # - Every tree node references existing types and symbols.
for i in 0..high(m.sh.syms): for i in 0..high(m.syms):
checkLocalSym c, int32(i) checkLocalSym c, int32(i)
checkTree c, m.toReplay checkTree c, m.toReplay
checkTree c, m.topLevel checkTree c, m.topLevel
for e in m.exports: for e in m.exports:
assert e[1] >= 0 and e[1] < m.sh.syms.len assert e[1] >= 0 and e[1] < m.syms.len
assert e[0] == m.sh.syms[e[1]].name assert e[0] == m.syms[e[1]].name
for e in m.compilerProcs: for e in m.compilerProcs:
assert e[1] >= 0 and e[1] < m.sh.syms.len assert e[1] >= 0 and e[1] < m.syms.len
assert e[0] == m.sh.syms[e[1]].name assert e[0] == m.syms[e[1]].name
checkLocalSymIds c, m, m.converters checkLocalSymIds c, m, m.converters
checkLocalSymIds c, m, m.methods checkLocalSymIds c, m, m.methods

View file

@ -35,12 +35,12 @@ proc isTracked(current, trackPos: PackedLineInfo, tokenLen: int): bool =
proc searchLocalSym(c: var NavContext; s: PackedSym; info: PackedLineInfo): bool = proc searchLocalSym(c: var NavContext; s: PackedSym; info: PackedLineInfo): bool =
result = s.name != LitId(0) and result = s.name != LitId(0) and
isTracked(info, c.trackPos, c.g.packed[c.thisModule].fromDisk.sh.strings[s.name].len) isTracked(info, c.trackPos, c.g.packed[c.thisModule].fromDisk.strings[s.name].len)
proc searchForeignSym(c: var NavContext; s: ItemId; info: PackedLineInfo): bool = proc searchForeignSym(c: var NavContext; s: ItemId; info: PackedLineInfo): bool =
let name = c.g.packed[s.module].fromDisk.sh.syms[s.item].name let name = c.g.packed[s.module].fromDisk.syms[s.item].name
result = name != LitId(0) and result = name != LitId(0) and
isTracked(info, c.trackPos, c.g.packed[s.module].fromDisk.sh.strings[name].len) isTracked(info, c.trackPos, c.g.packed[s.module].fromDisk.strings[name].len)
const const
EmptyItemId = ItemId(module: -1'i32, item: -1'i32) EmptyItemId = ItemId(module: -1'i32, item: -1'i32)
@ -51,7 +51,7 @@ proc search(c: var NavContext; tree: PackedTree): ItemId =
case tree.nodes[i].kind case tree.nodes[i].kind
of nkSym: of nkSym:
let item = tree.nodes[i].operand let item = tree.nodes[i].operand
if searchLocalSym(c, c.g.packed[c.thisModule].fromDisk.sh.syms[item], tree.nodes[i].info): if searchLocalSym(c, c.g.packed[c.thisModule].fromDisk.syms[item], tree.nodes[i].info):
return ItemId(module: c.thisModule, item: item) return ItemId(module: c.thisModule, item: item)
of nkModuleRef: of nkModuleRef:
if tree.nodes[i].info.line == c.trackPos.line and tree.nodes[i].info.file == c.trackPos.file: if tree.nodes[i].info.line == c.trackPos.line and tree.nodes[i].info.file == c.trackPos.file:
@ -74,7 +74,7 @@ proc isDecl(tree: PackedTree; n: NodePos): bool =
proc usage(c: var NavContext; info: PackedLineInfo; isDecl: bool) = proc usage(c: var NavContext; info: PackedLineInfo; isDecl: bool) =
var m = "" var m = ""
var file = c.g.packed[c.thisModule].fromDisk.sh.strings[info.file] var file = c.g.packed[c.thisModule].fromDisk.strings[info.file]
if c.outputSep == ' ': if c.outputSep == ' ':
file = os.extractFilename file file = os.extractFilename file
toLocation(m, file, info.line.int, info.col.int + ColOffset) toLocation(m, file, info.line.int, info.col.int + ColOffset)
@ -102,7 +102,7 @@ proc nav(g: ModuleGraph) =
# translate the track position to a packed position: # translate the track position to a packed position:
let unpacked = g.config.m.trackPos let unpacked = g.config.m.trackPos
let mid = unpacked.fileIndex let mid = unpacked.fileIndex
let fileId = g.packed[int32 mid].fromDisk.sh.strings.getKeyId(toFullPath(g.config, mid)) let fileId = g.packed[int32 mid].fromDisk.strings.getKeyId(toFullPath(g.config, mid))
if fileId == LitId(0): if fileId == LitId(0):
internalError(g.config, unpacked, "cannot find a valid file ID") internalError(g.config, unpacked, "cannot find a valid file ID")

View file

@ -98,17 +98,6 @@ type
PackedTree* = object ## usually represents a full Nim module PackedTree* = object ## usually represents a full Nim module
nodes*: seq[PackedNode] nodes*: seq[PackedNode]
#sh*: Shared
Shared* = ref object # shared between different versions of 'Module'.
# (though there is always exactly one valid
# version of a module)
syms*: seq[PackedSym]
types*: seq[PackedType]
strings*: BiTable[string] # we could share these between modules.
numbers*: BiTable[BiggestInt] # we also store floats in here so
# that we can assure that every bit is kept
#config*: ConfigRef
PackedInstantiation* = object PackedInstantiation* = object
key*, sym*: PackedItemId key*, sym*: PackedItemId
@ -374,51 +363,6 @@ const
externUIntLit* = {nkUIntLit, nkUInt8Lit, nkUInt16Lit, nkUInt32Lit, nkUInt64Lit} externUIntLit* = {nkUIntLit, nkUInt8Lit, nkUInt16Lit, nkUInt32Lit, nkUInt64Lit}
directIntLit* = nkInt32Lit directIntLit* = nkInt32Lit
proc toString*(tree: PackedTree; n: NodePos; sh: Shared; nesting: int;
result: var string) =
let pos = n.int
if result.len > 0 and result[^1] notin {' ', '\n'}:
result.add ' '
result.add $tree[pos].kind
case tree.nodes[pos].kind
of nkNone, nkEmpty, nkNilLit, nkType: discard
of nkIdent, nkStrLit..nkTripleStrLit:
result.add " "
result.add sh.strings[LitId tree.nodes[pos].operand]
of nkSym:
result.add " "
result.add sh.strings[sh.syms[tree.nodes[pos].operand].name]
of directIntLit:
result.add " "
result.addInt tree.nodes[pos].operand
of externSIntLit:
result.add " "
result.addInt sh.numbers[LitId tree.nodes[pos].operand]
of externUIntLit:
result.add " "
result.add $cast[uint64](sh.numbers[LitId tree.nodes[pos].operand])
of nkFloatLit..nkFloat128Lit:
result.add " "
result.add $cast[BiggestFloat](sh.numbers[LitId tree.nodes[pos].operand])
else:
result.add "(\n"
for i in 1..(nesting+1)*2: result.add ' '
for child in sonsReadonly(tree, n):
toString(tree, child, sh, nesting + 1, result)
result.add "\n"
for i in 1..nesting*2: result.add ' '
result.add ")"
#for i in 1..nesting*2: result.add ' '
proc toString*(tree: PackedTree; n: NodePos; sh: Shared): string =
result = ""
toString(tree, n, sh, 0, result)
proc debug*(tree: PackedTree; sh: Shared) =
stdout.write toString(tree, NodePos 0, sh)
when false: when false:
proc identIdImpl(tree: PackedTree; n: NodePos): LitId = proc identIdImpl(tree: PackedTree; n: NodePos): LitId =
if n.kind == nkIdent: if n.kind == nkIdent:

View file

@ -23,7 +23,7 @@ from typetraits import supportsCopyMem
## (`RodFileError`). The file format broken up into sections (`RodSection`) ## (`RodFileError`). The file format broken up into sections (`RodSection`)
## and preceeded by a header (see: `cookie`). The precise layout, section ## and preceeded by a header (see: `cookie`). The precise layout, section
## ordering and data following the section are determined by the user. See ## ordering and data following the section are determined by the user. See
## `ic.loadRoadFile`. ## `ic.loadRodFile`.
## ##
## A basic but "wrong" example of the lifecycle: ## A basic but "wrong" example of the lifecycle:
## --------------------------------------------- ## ---------------------------------------------