diff options
Diffstat (limited to 'compiler/rodimpl.nim')
-rw-r--r-- | compiler/rodimpl.nim | 885 |
1 files changed, 0 insertions, 885 deletions
diff --git a/compiler/rodimpl.nim b/compiler/rodimpl.nim deleted file mode 100644 index 7d24e4e67..000000000 --- a/compiler/rodimpl.nim +++ /dev/null @@ -1,885 +0,0 @@ -# -# -# The Nim Compiler -# (c) Copyright 2018 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## This module implements the new compilation cache. - -import strutils, os, intsets, tables, ropes, db_sqlite, msgs, options, types, - renderer, rodutils, idents, astalgo, btrees, magicsys, cgmeth, extccomp, - btrees, trees, condsyms, nversion - -## Todo: -## - Dependency computation should use *signature* hashes in order to -## avoid recompiling dependent modules. -## - Patch the rest of the compiler to do lazy loading of proc bodies. -## - Patch the C codegen to cache proc bodies and maybe types. - -template db(): DbConn = g.incr.db - -proc encodeConfig(g: ModuleGraph): string = - result = newStringOfCap(100) - result.add RodFileVersion - for d in definedSymbolNames(g.config.symbols): - result.add ' ' - result.add d - - template serialize(field) = - result.add ' ' - result.add($g.config.field) - - depConfigFields(serialize) - -proc needsRecompile(g: ModuleGraph; fileIdx: FileIndex; fullpath: string; - cycleCheck: var IntSet): bool = - let root = db.getRow(sql"select id, fullhash from filenames where fullpath = ?", - fullpath) - if root[0].len == 0: return true - if root[1] != hashFileCached(g.config, fileIdx, fullpath): - return true - # cycle detection: assume "not changed" is correct. - if cycleCheck.containsOrIncl(int fileIdx): - return false - # check dependencies (recursively): - for row in db.fastRows(sql"select fullpath from filenames where id in (select dependency from deps where module = ?)", - root[0]): - let dep = row[0] - if needsRecompile(g, g.config.fileInfoIdx(dep), dep, cycleCheck): - return true - return false - -proc getModuleId*(g: ModuleGraph; fileIdx: FileIndex; fullpath: string): int = - if g.config.symbolFiles in {disabledSf, writeOnlySf} or - g.incr.configChanged: - return getID() - let module = g.incr.db.getRow( - sql"select id, fullHash, nimid from modules where fullpath = ?", fullpath) - let currentFullhash = hashFileCached(g.config, fileIdx, fullpath) - if module[0].len == 0: - result = getID() - db.exec(sql"insert into modules(fullpath, interfHash, fullHash, nimid) values (?, ?, ?, ?)", - fullpath, "", currentFullhash, result) - else: - result = parseInt(module[2]) - if currentFullhash == module[1]: - # not changed, so use the cached AST: - doAssert(result != 0) - var cycleCheck = initIntSet() - if not needsRecompile(g, fileIdx, fullpath, cycleCheck): - echo "cached successfully! ", fullpath - return -result - db.exec(sql"update modules set fullHash = ? where id = ?", currentFullhash, module[0]) - db.exec(sql"delete from deps where module = ?", module[0]) - db.exec(sql"delete from types where module = ?", module[0]) - db.exec(sql"delete from syms where module = ?", module[0]) - db.exec(sql"delete from toplevelstmts where module = ?", module[0]) - db.exec(sql"delete from statics where module = ?", module[0]) - -proc pushType(w: var Writer, t: PType) = - if not containsOrIncl(w.tmarks, t.id): - w.tstack.add(t) - -proc pushSym(w: var Writer, s: PSym) = - if not containsOrIncl(w.smarks, s.id): - w.sstack.add(s) - -template w: untyped = g.incr.w - -proc encodeNode(g: ModuleGraph; fInfo: TLineInfo, n: PNode, - result: var string) = - if n == nil: - # nil nodes have to be stored too: - result.add("()") - return - result.add('(') - encodeVInt(ord(n.kind), result) - # we do not write comments for now - # Line information takes easily 20% or more of the filesize! Therefore we - # omit line information if it is the same as the parent's line information: - if fInfo.fileIndex != n.info.fileIndex: - result.add('?') - encodeVInt(n.info.col, result) - result.add(',') - encodeVInt(int n.info.line, result) - result.add(',') - encodeVInt(toDbFileId(g.incr, g.config, n.info.fileIndex), result) - elif fInfo.line != n.info.line: - result.add('?') - encodeVInt(n.info.col, result) - result.add(',') - encodeVInt(int n.info.line, result) - elif fInfo.col != n.info.col: - result.add('?') - encodeVInt(n.info.col, result) - # No need to output the file index, as this is the serialization of one - # file. - let f = n.flags * PersistentNodeFlags - if f != {}: - result.add('$') - encodeVInt(cast[int32](f), result) - if n.typ != nil: - result.add('^') - encodeVInt(n.typ.id, result) - pushType(w, n.typ) - case n.kind - of nkCharLit..nkUInt64Lit: - if n.intVal != 0: - result.add('!') - encodeVBiggestInt(n.intVal, result) - of nkFloatLit..nkFloat64Lit: - if n.floatVal != 0.0: - result.add('!') - encodeStr($n.floatVal, result) - of nkStrLit..nkTripleStrLit: - if n.strVal != "": - result.add('!') - encodeStr(n.strVal, result) - of nkIdent: - result.add('!') - encodeStr(n.ident.s, result) - of nkSym: - result.add('!') - encodeVInt(n.sym.id, result) - pushSym(w, n.sym) - else: - for i in countup(0, sonsLen(n) - 1): - encodeNode(g, n.info, n.sons[i], result) - add(result, ')') - -proc encodeLoc(g: ModuleGraph; loc: TLoc, result: var string) = - var oldLen = result.len - result.add('<') - if loc.k != low(loc.k): encodeVInt(ord(loc.k), result) - if loc.storage != low(loc.storage): - add(result, '*') - encodeVInt(ord(loc.storage), result) - if loc.flags != {}: - add(result, '$') - encodeVInt(cast[int32](loc.flags), result) - if loc.lode != nil: - add(result, '^') - encodeNode(g, unknownLineInfo(), loc.lode, result) - if loc.r != nil: - add(result, '!') - encodeStr($loc.r, result) - if oldLen + 1 == result.len: - # no data was necessary, so remove the '<' again: - setLen(result, oldLen) - else: - add(result, '>') - -proc encodeType(g: ModuleGraph, t: PType, result: var string) = - if t == nil: - # nil nodes have to be stored too: - result.add("[]") - return - # we need no surrounding [] here because the type is in a line of its own - if t.kind == tyForward: internalError(g.config, "encodeType: tyForward") - # for the new rodfile viewer we use a preceding [ so that the data section - # can easily be disambiguated: - add(result, '[') - encodeVInt(ord(t.kind), result) - add(result, '+') - encodeVInt(t.id, result) - if t.n != nil: - encodeNode(g, unknownLineInfo(), t.n, result) - if t.flags != {}: - add(result, '$') - encodeVInt(cast[int32](t.flags), result) - if t.callConv != low(t.callConv): - add(result, '?') - encodeVInt(ord(t.callConv), result) - if t.owner != nil: - add(result, '*') - encodeVInt(t.owner.id, result) - pushSym(w, t.owner) - if t.sym != nil: - add(result, '&') - encodeVInt(t.sym.id, result) - pushSym(w, t.sym) - if t.size != - 1: - add(result, '/') - encodeVBiggestInt(t.size, result) - if t.align != 2: - add(result, '=') - encodeVInt(t.align, result) - if t.lockLevel.ord != UnspecifiedLockLevel.ord: - add(result, '\14') - encodeVInt(t.lockLevel.int16, result) - if t.destructor != nil and t.destructor.id != 0: - add(result, '\15') - encodeVInt(t.destructor.id, result) - pushSym(w, t.destructor) - if t.deepCopy != nil: - add(result, '\16') - encodeVInt(t.deepcopy.id, result) - pushSym(w, t.deepcopy) - if t.assignment != nil: - add(result, '\17') - encodeVInt(t.assignment.id, result) - pushSym(w, t.assignment) - if t.sink != nil: - add(result, '\18') - encodeVInt(t.sink.id, result) - pushSym(w, t.sink) - for i, s in items(t.methods): - add(result, '\19') - encodeVInt(i, result) - add(result, '\20') - encodeVInt(s.id, result) - pushSym(w, s) - encodeLoc(g, t.loc, result) - for i in countup(0, sonsLen(t) - 1): - if t.sons[i] == nil: - add(result, "^()") - else: - add(result, '^') - encodeVInt(t.sons[i].id, result) - pushType(w, t.sons[i]) - -proc encodeLib(g: ModuleGraph, lib: PLib, info: TLineInfo, result: var string) = - add(result, '|') - encodeVInt(ord(lib.kind), result) - add(result, '|') - encodeStr($lib.name, result) - add(result, '|') - encodeNode(g, info, lib.path, result) - -proc encodeInstantiations(g: ModuleGraph; s: seq[PInstantiation]; - result: var string) = - for t in s: - result.add('\15') - encodeVInt(t.sym.id, result) - pushSym(w, t.sym) - for tt in t.concreteTypes: - result.add('\17') - encodeVInt(tt.id, result) - pushType(w, tt) - result.add('\20') - encodeVInt(t.compilesId, result) - -proc encodeSym(g: ModuleGraph, s: PSym, result: var string) = - if s == nil: - # nil nodes have to be stored too: - result.add("{}") - return - # we need no surrounding {} here because the symbol is in a line of its own - encodeVInt(ord(s.kind), result) - result.add('+') - encodeVInt(s.id, result) - result.add('&') - encodeStr(s.name.s, result) - if s.typ != nil: - result.add('^') - encodeVInt(s.typ.id, result) - pushType(w, s.typ) - result.add('?') - if s.info.col != -1'i16: encodeVInt(s.info.col, result) - result.add(',') - encodeVInt(int s.info.line, result) - result.add(',') - encodeVInt(toDbFileId(g.incr, g.config, s.info.fileIndex), result) - if s.owner != nil: - result.add('*') - encodeVInt(s.owner.id, result) - pushSym(w, s.owner) - if s.flags != {}: - result.add('$') - encodeVInt(cast[int32](s.flags), result) - if s.magic != mNone: - result.add('@') - encodeVInt(ord(s.magic), result) - result.add('!') - encodeVInt(cast[int32](s.options), result) - if s.position != 0: - result.add('%') - encodeVInt(s.position, result) - if s.offset != - 1: - result.add('`') - encodeVInt(s.offset, result) - encodeLoc(g, s.loc, result) - if s.annex != nil: encodeLib(g, s.annex, s.info, result) - if s.constraint != nil: - add(result, '#') - encodeNode(g, unknownLineInfo(), s.constraint, result) - case s.kind - of skType, skGenericParam: - for t in s.typeInstCache: - result.add('\14') - encodeVInt(t.id, result) - pushType(w, t) - of routineKinds: - encodeInstantiations(g, s.procInstCache, result) - if s.gcUnsafetyReason != nil: - result.add('\16') - encodeVInt(s.gcUnsafetyReason.id, result) - pushSym(w, s.gcUnsafetyReason) - of skModule, skPackage: - encodeInstantiations(g, s.usedGenerics, result) - # we don't serialize: - #tab*: TStrTable # interface table for modules - of skLet, skVar, skField, skForVar: - if s.guard != nil: - result.add('\18') - encodeVInt(s.guard.id, result) - pushSym(w, s.guard) - if s.bitsize != 0: - result.add('\19') - encodeVInt(s.bitsize, result) - else: discard - # lazy loading will soon reload the ast lazily, so the ast needs to be - # the last entry of a symbol: - if s.ast != nil: - # we used to attempt to save space here by only storing a dummy AST if - # it is not necessary, but Nim's heavy compile-time evaluation features - # make that unfeasible nowadays: - encodeNode(g, s.info, s.ast, result) - -proc storeSym(g: ModuleGraph; s: PSym) = - if sfForward in s.flags and s.kind != skModule: - w.forwardedSyms.add s - return - var buf = newStringOfCap(160) - encodeSym(g, s, buf) - # XXX only store the name for exported symbols in order to speed up lookup - # times once we enable the skStub logic. - let m = getModule(s) - let mid = if m == nil: 0 else: abs(m.id) - db.exec(sql"insert into syms(nimid, module, name, data, exported) values (?, ?, ?, ?, ?)", - s.id, mid, s.name.s, buf, ord(sfExported in s.flags)) - -proc storeType(g: ModuleGraph; t: PType) = - var buf = newStringOfCap(160) - encodeType(g, t, buf) - let m = if t.owner != nil: getModule(t.owner) else: nil - let mid = if m == nil: 0 else: abs(m.id) - db.exec(sql"insert into types(nimid, module, data) values (?, ?, ?)", - t.id, mid, buf) - -proc storeNode*(g: ModuleGraph; module: PSym; n: PNode) = - if g.config.symbolFiles == disabledSf: return - var buf = newStringOfCap(160) - encodeNode(g, module.info, n, buf) - db.exec(sql"insert into toplevelstmts(module, position, data) values (?, ?, ?)", - abs(module.id), module.offset, buf) - inc module.offset - var i = 0 - while true: - if i > 10_000: - doAssert false, "loop never ends!" - if w.sstack.len > 0: - let s = w.sstack.pop() - when false: - echo "popped ", s.name.s, " ", s.id - storeSym(g, s) - elif w.tstack.len > 0: - let t = w.tstack.pop() - storeType(g, t) - when false: - echo "popped type ", typeToString(t), " ", t.id - else: - break - inc i - -proc recordStmt*(g: ModuleGraph; module: PSym; n: PNode) = - storeNode(g, module, n) - -proc storeRemaining*(g: ModuleGraph; module: PSym) = - if g.config.symbolFiles == disabledSf: return - var stillForwarded: seq[PSym] = @[] - for s in w.forwardedSyms: - if sfForward notin s.flags: - storeSym(g, s) - else: - stillForwarded.add s - swap w.forwardedSyms, stillForwarded - -# ---------------- decoder ----------------------------------- - -type - BlobReader = object - s: string - pos: int - -using - b: var BlobReader - g: ModuleGraph - -proc loadSym(g; id: int, info: TLineInfo): PSym -proc loadType(g; id: int, info: TLineInfo): PType - -proc decodeLineInfo(g; b; info: var TLineInfo) = - if b.s[b.pos] == '?': - inc(b.pos) - if b.s[b.pos] == ',': info.col = -1'i16 - else: info.col = int16(decodeVInt(b.s, b.pos)) - if b.s[b.pos] == ',': - inc(b.pos) - if b.s[b.pos] == ',': info.line = 0'u16 - else: info.line = uint16(decodeVInt(b.s, b.pos)) - if b.s[b.pos] == ',': - inc(b.pos) - info.fileIndex = fromDbFileId(g.incr, g.config, decodeVInt(b.s, b.pos)) - -proc skipNode(b) = - assert b.s[b.pos] == '(' - var par = 0 - var pos = b.pos+1 - while true: - case b.s[pos] - of ')': - if par == 0: break - dec par - of '(': inc par - else: discard - inc pos - b.pos = pos+1 # skip ')' - -proc decodeNodeLazyBody(g; b; fInfo: TLineInfo, - belongsTo: PSym): PNode = - result = nil - if b.s[b.pos] == '(': - inc(b.pos) - if b.s[b.pos] == ')': - inc(b.pos) - return # nil node - result = newNodeI(TNodeKind(decodeVInt(b.s, b.pos)), fInfo) - decodeLineInfo(g, b, result.info) - if b.s[b.pos] == '$': - inc(b.pos) - result.flags = cast[TNodeFlags](int32(decodeVInt(b.s, b.pos))) - if b.s[b.pos] == '^': - inc(b.pos) - var id = decodeVInt(b.s, b.pos) - result.typ = loadType(g, id, result.info) - case result.kind - of nkCharLit..nkUInt64Lit: - if b.s[b.pos] == '!': - inc(b.pos) - result.intVal = decodeVBiggestInt(b.s, b.pos) - of nkFloatLit..nkFloat64Lit: - if b.s[b.pos] == '!': - inc(b.pos) - var fl = decodeStr(b.s, b.pos) - result.floatVal = parseFloat(fl) - of nkStrLit..nkTripleStrLit: - if b.s[b.pos] == '!': - inc(b.pos) - result.strVal = decodeStr(b.s, b.pos) - else: - result.strVal = "" - of nkIdent: - if b.s[b.pos] == '!': - inc(b.pos) - var fl = decodeStr(b.s, b.pos) - result.ident = g.cache.getIdent(fl) - else: - internalError(g.config, result.info, "decodeNode: nkIdent") - of nkSym: - if b.s[b.pos] == '!': - inc(b.pos) - var id = decodeVInt(b.s, b.pos) - result.sym = loadSym(g, id, result.info) - else: - internalError(g.config, result.info, "decodeNode: nkSym") - else: - var i = 0 - while b.s[b.pos] != ')': - when false: - if belongsTo != nil and i == bodyPos: - addSonNilAllowed(result, nil) - belongsTo.offset = b.pos - skipNode(b) - else: - discard - addSonNilAllowed(result, decodeNodeLazyBody(g, b, result.info, nil)) - inc i - if b.s[b.pos] == ')': inc(b.pos) - else: internalError(g.config, result.info, "decodeNode: ')' missing") - else: - internalError(g.config, fInfo, "decodeNode: '(' missing " & $b.pos) - -proc decodeNode(g; b; fInfo: TLineInfo): PNode = - result = decodeNodeLazyBody(g, b, fInfo, nil) - -proc decodeLoc(g; b; loc: var TLoc, info: TLineInfo) = - if b.s[b.pos] == '<': - inc(b.pos) - if b.s[b.pos] in {'0'..'9', 'a'..'z', 'A'..'Z'}: - loc.k = TLocKind(decodeVInt(b.s, b.pos)) - else: - loc.k = low(loc.k) - if b.s[b.pos] == '*': - inc(b.pos) - loc.storage = TStorageLoc(decodeVInt(b.s, b.pos)) - else: - loc.storage = low(loc.storage) - if b.s[b.pos] == '$': - inc(b.pos) - loc.flags = cast[TLocFlags](int32(decodeVInt(b.s, b.pos))) - else: - loc.flags = {} - if b.s[b.pos] == '^': - inc(b.pos) - loc.lode = decodeNode(g, b, info) - # rrGetType(b, decodeVInt(b.s, b.pos), info) - else: - loc.lode = nil - if b.s[b.pos] == '!': - inc(b.pos) - loc.r = rope(decodeStr(b.s, b.pos)) - else: - loc.r = nil - if b.s[b.pos] == '>': inc(b.pos) - else: internalError(g.config, info, "decodeLoc " & b.s[b.pos]) - -proc loadBlob(g; query: SqlQuery; id: int): BlobReader = - let blob = db.getValue(query, id) - if blob.len == 0: - internalError(g.config, "symbolfiles: cannot find ID " & $ id) - result = BlobReader(pos: 0) - shallowCopy(result.s, blob) - # ensure we can read without index checks: - result.s.add '\0' - -proc loadType(g; id: int; info: TLineInfo): PType = - result = g.incr.r.types.getOrDefault(id) - if result != nil: return result - var b = loadBlob(g, sql"select data from types where nimid = ?", id) - - if b.s[b.pos] == '[': - inc(b.pos) - if b.s[b.pos] == ']': - inc(b.pos) - return # nil type - new(result) - result.kind = TTypeKind(decodeVInt(b.s, b.pos)) - if b.s[b.pos] == '+': - inc(b.pos) - result.id = decodeVInt(b.s, b.pos) - setId(result.id) - #if debugIds: registerID(result) - else: - internalError(g.config, info, "decodeType: no id") - # here this also avoids endless recursion for recursive type - g.incr.r.types.add(result.id, result) - if b.s[b.pos] == '(': result.n = decodeNode(g, b, unknownLineInfo()) - if b.s[b.pos] == '$': - inc(b.pos) - result.flags = cast[TTypeFlags](int32(decodeVInt(b.s, b.pos))) - if b.s[b.pos] == '?': - inc(b.pos) - result.callConv = TCallingConvention(decodeVInt(b.s, b.pos)) - if b.s[b.pos] == '*': - inc(b.pos) - result.owner = loadSym(g, decodeVInt(b.s, b.pos), info) - if b.s[b.pos] == '&': - inc(b.pos) - result.sym = loadSym(g, decodeVInt(b.s, b.pos), info) - if b.s[b.pos] == '/': - inc(b.pos) - result.size = decodeVInt(b.s, b.pos) - else: - result.size = -1 - if b.s[b.pos] == '=': - inc(b.pos) - result.align = decodeVInt(b.s, b.pos).int16 - else: - result.align = 2 - - if b.s[b.pos] == '\14': - inc(b.pos) - result.lockLevel = decodeVInt(b.s, b.pos).TLockLevel - else: - result.lockLevel = UnspecifiedLockLevel - - if b.s[b.pos] == '\15': - inc(b.pos) - result.destructor = loadSym(g, decodeVInt(b.s, b.pos), info) - if b.s[b.pos] == '\16': - inc(b.pos) - result.deepCopy = loadSym(g, decodeVInt(b.s, b.pos), info) - if b.s[b.pos] == '\17': - inc(b.pos) - result.assignment = loadSym(g, decodeVInt(b.s, b.pos), info) - if b.s[b.pos] == '\18': - inc(b.pos) - result.sink = loadSym(g, decodeVInt(b.s, b.pos), info) - while b.s[b.pos] == '\19': - inc(b.pos) - let x = decodeVInt(b.s, b.pos) - doAssert b.s[b.pos] == '\20' - inc(b.pos) - let y = loadSym(g, decodeVInt(b.s, b.pos), info) - result.methods.safeAdd((x, y)) - decodeLoc(g, b, result.loc, info) - while b.s[b.pos] == '^': - inc(b.pos) - if b.s[b.pos] == '(': - inc(b.pos) - if b.s[b.pos] == ')': inc(b.pos) - else: internalError(g.config, info, "decodeType ^(" & b.s[b.pos]) - rawAddSon(result, nil) - else: - let d = decodeVInt(b.s, b.pos) - rawAddSon(result, loadType(g, d, info)) - -proc decodeLib(g; b; info: TLineInfo): PLib = - result = nil - if b.s[b.pos] == '|': - new(result) - inc(b.pos) - result.kind = TLibKind(decodeVInt(b.s, b.pos)) - if b.s[b.pos] != '|': internalError(g.config, "decodeLib: 1") - inc(b.pos) - result.name = rope(decodeStr(b.s, b.pos)) - if b.s[b.pos] != '|': internalError(g.config, "decodeLib: 2") - inc(b.pos) - result.path = decodeNode(g, b, info) - -proc decodeInstantiations(g; b; info: TLineInfo; - s: var seq[PInstantiation]) = - while b.s[b.pos] == '\15': - inc(b.pos) - var ii: PInstantiation - new ii - ii.sym = loadSym(g, decodeVInt(b.s, b.pos), info) - ii.concreteTypes = @[] - while b.s[b.pos] == '\17': - inc(b.pos) - ii.concreteTypes.add loadType(g, decodeVInt(b.s, b.pos), info) - if b.s[b.pos] == '\20': - inc(b.pos) - ii.compilesId = decodeVInt(b.s, b.pos) - s.safeAdd ii - -proc loadSymFromBlob(g; b; info: TLineInfo): PSym = - if b.s[b.pos] == '{': - inc(b.pos) - if b.s[b.pos] == '}': - inc(b.pos) - return # nil sym - var k = TSymKind(decodeVInt(b.s, b.pos)) - var id: int - if b.s[b.pos] == '+': - inc(b.pos) - id = decodeVInt(b.s, b.pos) - setId(id) - else: - internalError(g.config, info, "decodeSym: no id") - var ident: PIdent - if b.s[b.pos] == '&': - inc(b.pos) - ident = g.cache.getIdent(decodeStr(b.s, b.pos)) - else: - internalError(g.config, info, "decodeSym: no ident") - #echo "decoding: {", ident.s - new(result) - result.id = id - result.kind = k - result.name = ident # read the rest of the symbol description: - g.incr.r.syms.add(result.id, result) - if b.s[b.pos] == '^': - inc(b.pos) - result.typ = loadType(g, decodeVInt(b.s, b.pos), info) - decodeLineInfo(g, b, result.info) - if b.s[b.pos] == '*': - inc(b.pos) - result.owner = loadSym(g, decodeVInt(b.s, b.pos), result.info) - if b.s[b.pos] == '$': - inc(b.pos) - result.flags = cast[TSymFlags](int32(decodeVInt(b.s, b.pos))) - if b.s[b.pos] == '@': - inc(b.pos) - result.magic = TMagic(decodeVInt(b.s, b.pos)) - if b.s[b.pos] == '!': - inc(b.pos) - result.options = cast[TOptions](int32(decodeVInt(b.s, b.pos))) - if b.s[b.pos] == '%': - inc(b.pos) - result.position = decodeVInt(b.s, b.pos) - if b.s[b.pos] == '`': - inc(b.pos) - result.offset = decodeVInt(b.s, b.pos) - else: - result.offset = -1 - decodeLoc(g, b, result.loc, result.info) - result.annex = decodeLib(g, b, info) - if b.s[b.pos] == '#': - inc(b.pos) - result.constraint = decodeNode(g, b, unknownLineInfo()) - case result.kind - of skType, skGenericParam: - while b.s[b.pos] == '\14': - inc(b.pos) - result.typeInstCache.safeAdd loadType(g, decodeVInt(b.s, b.pos), result.info) - of routineKinds: - decodeInstantiations(g, b, result.info, result.procInstCache) - if b.s[b.pos] == '\16': - inc(b.pos) - result.gcUnsafetyReason = loadSym(g, decodeVInt(b.s, b.pos), result.info) - of skModule, skPackage: - decodeInstantiations(g, b, result.info, result.usedGenerics) - of skLet, skVar, skField, skForVar: - if b.s[b.pos] == '\18': - inc(b.pos) - result.guard = loadSym(g, decodeVInt(b.s, b.pos), result.info) - if b.s[b.pos] == '\19': - inc(b.pos) - result.bitsize = decodeVInt(b.s, b.pos).int16 - else: discard - - if b.s[b.pos] == '(': - #if result.kind in routineKinds: - # result.ast = decodeNodeLazyBody(b, result.info, result) - #else: - result.ast = decodeNode(g, b, result.info) - if sfCompilerProc in result.flags: - registerCompilerProc(g, result) - #echo "loading ", result.name.s - -proc loadSym(g; id: int; info: TLineInfo): PSym = - result = g.incr.r.syms.getOrDefault(id) - if result != nil: return result - var b = loadBlob(g, sql"select data from syms where nimid = ?", id) - result = loadSymFromBlob(g, b, info) - doAssert id == result.id, "symbol ID is not consistent!" - -proc loadModuleSymTab(g; module: PSym) = - ## goal: fill module.tab - g.incr.r.syms.add(module.id, module) - for row in db.fastRows(sql"select nimid, data from syms where module = ? and exported = 1", abs(module.id)): - let id = parseInt(row[0]) - var s = g.incr.r.syms.getOrDefault(id) - if s == nil: - var b = BlobReader(pos: 0) - shallowCopy(b.s, row[1]) - # ensure we can read without index checks: - b.s.add '\0' - s = loadSymFromBlob(g, b, module.info) - assert s != nil - strTableAdd(module.tab, s) - if sfSystemModule in module.flags: - g.systemModule = module - -proc replay(g: ModuleGraph; module: PSym; n: PNode) = - # XXX check if we need to replay nkStaticStmt here. - case n.kind - #of nkStaticStmt: - #evalStaticStmt(module, g, n[0], module) - #of nkVarSection, nkLetSection: - # nkVarSections are already covered by the vmgen which produces nkStaticStmt - of nkMethodDef: - methodDef(g, n[namePos].sym, fromCache=true) - of nkCommentStmt: - # pragmas are complex and can be user-overriden via templates. So - # instead of using the original ``nkPragma`` nodes, we rely on the - # fact that pragmas.nim was patched to produce specialized recorded - # statements for us in the form of ``nkCommentStmt`` with (key, value) - # pairs. Ordinary nkCommentStmt nodes never have children so this is - # not ambiguous. - # Fortunately only a tiny subset of the available pragmas need to - # be replayed here. This is always a subset of ``pragmas.stmtPragmas``. - if n.len >= 2: - internalAssert g.config, n[0].kind == nkStrLit and n[1].kind == nkStrLit - case n[0].strVal - of "hint": message(g.config, n.info, hintUser, n[1].strVal) - of "warning": message(g.config, n.info, warnUser, n[1].strVal) - of "error": localError(g.config, n.info, errUser, n[1].strVal) - of "compile": - internalAssert g.config, n.len == 3 and n[2].kind == nkStrLit - var cf = Cfile(cname: n[1].strVal, obj: n[2].strVal, - flags: {CfileFlag.External}) - extccomp.addExternalFileToCompile(g.config, cf) - of "link": - extccomp.addExternalFileToLink(g.config, n[1].strVal) - of "passl": - extccomp.addLinkOption(g.config, n[1].strVal) - of "passc": - extccomp.addCompileOption(g.config, n[1].strVal) - of "cppdefine": - options.cppDefine(g.config, n[1].strVal) - of "inc": - let destKey = n[1].strVal - let by = n[2].intVal - let v = getOrDefault(g.cacheCounters, destKey) - g.cacheCounters[destKey] = v+by - of "put": - let destKey = n[1].strVal - let key = n[2].strVal - let val = n[3] - if not contains(g.cacheTables, destKey): - g.cacheTables[destKey] = initBTree[string, PNode]() - if not contains(g.cacheTables[destKey], key): - g.cacheTables[destKey].add(key, val) - else: - internalError(g.config, n.info, "key already exists: " & key) - of "incl": - let destKey = n[1].strVal - let val = n[2] - if not contains(g.cacheSeqs, destKey): - g.cacheSeqs[destKey] = newTree(nkStmtList, val) - else: - block search: - for existing in g.cacheSeqs[destKey]: - if exprStructuralEquivalent(existing, val, strictSymEquality=true): - break search - g.cacheSeqs[destKey].add val - of "add": - let destKey = n[1].strVal - let val = n[2] - if not contains(g.cacheSeqs, destKey): - g.cacheSeqs[destKey] = newTree(nkStmtList, val) - else: - g.cacheSeqs[destKey].add val - else: - internalAssert g.config, false - of nkImportStmt: - for x in n: - internalAssert g.config, x.kind == nkStrLit - let imported = g.importModuleCallback(g, module, fileInfoIdx(g.config, n[0].strVal)) - internalAssert g.config, imported.id < 0 - of nkStmtList, nkStmtListExpr: - for x in n: replay(g, module, x) - else: discard "nothing to do for this node" - -proc loadNode*(g: ModuleGraph; module: PSym): PNode = - loadModuleSymTab(g, module) - result = newNodeI(nkStmtList, module.info) - for row in db.rows(sql"select data from toplevelstmts where module = ? order by position asc", - abs module.id): - - var b = BlobReader(pos: 0) - # ensure we can read without index checks: - b.s = row[0] & '\0' - result.add decodeNode(g, b, module.info) - - db.exec(sql"insert into controlblock(idgen) values (?)", gFrontEndId) - replay(g, module, result) - -proc setupModuleCache*(g: ModuleGraph) = - if g.config.symbolFiles == disabledSf: return - g.recordStmt = recordStmt - let dbfile = getNimcacheDir(g.config) / "rodfiles.db" - if g.config.symbolFiles == writeOnlySf: - removeFile(dbfile) - if not fileExists(dbfile): - db = open(connection=dbfile, user="nim", password="", - database="nim") - createDb(db) - db.exec(sql"insert into config(config) values (?)", encodeConfig(g)) - else: - db = open(connection=dbfile, user="nim", password="", - database="nim") - let oldConfig = db.getValue(sql"select config from config") - g.incr.configChanged = oldConfig != encodeConfig(g) - db.exec(sql"pragma journal_mode=off") - db.exec(sql"pragma SYNCHRONOUS=off") - db.exec(sql"pragma LOCKING_MODE=exclusive") - let lastId = db.getValue(sql"select max(idgen) from controlblock") - if lastId.len > 0: - idgen.setId(parseInt lastId) |