incremental compilation subsystem compiles again

This commit is contained in:
Andreas Rumpf
2018-05-30 20:27:41 +02:00
parent 31d9df9e75
commit a36c779f39
3 changed files with 149 additions and 188 deletions

View File

@@ -15,7 +15,8 @@ const nimIncremental* = defined(nimIncremental)
import options, lineinfos
when nimIncremental:
import ast, intsets, btrees, db_sqlite
import ast, msgs, intsets, btrees, db_sqlite, std / sha1
from strutils import parseInt
type
Writer* = object
@@ -44,30 +45,29 @@ when nimIncremental:
proc hashFileCached*(conf: ConfigRef; fileIdx: FileIndex; fullpath: string): string =
result = msgs.getHash(fileIdx)
result = msgs.getHash(conf, fileIdx)
if result.len == 0:
result = $secureHashFile(fullpath)
msgs.setHash(fileIdx, result)
msgs.setHash(conf, fileIdx, result)
proc toDbFileId*(fileIdx: int32): int =
if fileIdx == -1: return -1
let fullpath = fileIdx.toFullPath
let row = db.getRow(sql"select id, fullhash from filenames where fullpath = ?",
proc toDbFileId*(incr: var IncrementalCtx; conf: ConfigRef; fileIdx: FileIndex): int =
if fileIdx == FileIndex(-1): return -1
let fullpath = toFullPath(conf, fileIdx)
let row = incr.db.getRow(sql"select id, fullhash from filenames where fullpath = ?",
fullpath)
let id = row[0]
let fullhash = hashFileCached(fileIdx, fullpath)
let fullhash = hashFileCached(conf, fileIdx, fullpath)
if id.len == 0:
result = int db.insertID(sql"insert into filenames(fullpath, fullhash) values (?, ?)",
result = int incr.db.insertID(sql"insert into filenames(fullpath, fullhash) values (?, ?)",
fullpath, fullhash)
else:
if row[1] != fullhash:
db.exec(sql"update filenames set fullhash = ? where fullpath = ?", fullhash, fullpath)
incr.db.exec(sql"update filenames set fullhash = ? where fullpath = ?", fullhash, fullpath)
result = parseInt(id)
proc fromDbFileId*(incr: var IncrementalCtx; conf: ConfigRef; dbId: int): FileIndex =
if dbId == -1: return -1
let fullpath = db.getValue(sql"select fullpath from filenames where id = ?", dbId)
if dbId == -1: return FileIndex(-1)
let fullpath = incr.db.getValue(sql"select fullpath from filenames where id = ?", dbId)
doAssert fullpath.len > 0, "cannot find file name for DB ID " & $dbId
result = fileInfoIdx(conf, fullpath)

View File

@@ -6,6 +6,7 @@ path:"$projectPath/.."
define:booting
define:nimcore
define:nimIncremental
#import:"$projectpath/testability"
@if windows:

View File

@@ -10,7 +10,7 @@
## This module implements the new compilation cache.
import strutils, os, intsets, tables, ropes, db_sqlite, msgs, options, types,
renderer, rodutils, std / sha1, idents, astalgo, magicsys
renderer, rodutils, idents, astalgo, btrees, magicsys
## Todo:
## - Implement the 'import' replay logic so that the codegen runs over
@@ -19,45 +19,44 @@ import strutils, os, intsets, tables, ropes, db_sqlite, msgs, options, types,
## dependencies.
## - Test multi methods.
## - Implement the limited VM support based on sets.
## - Depencency computation should use signature hashes in order to
## - Depencency computation should use *signature* hashes in order to
## avoid recompiling dependent modules.
template db(): DbConn = g.incr.db
proc needsRecompile(g: ModuleGraph; fileIdx: int32; fullpath: string;
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(fileIdx, fullpath):
if root[1] != hashFileCached(g.config, fileIdx, fullpath):
return true
# cycle detection: assume "not changed" is correct.
if cycleCheck.containsOrIncl(fileIdx):
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, dep.fileInfoIdx, dep, cycleCheck):
if needsRecompile(g, g.config.fileInfoIdx(dep), dep, cycleCheck):
return true
return false
proc getModuleId*(g: ModuleGraph; fileIdx: int32; fullpath: string): int =
if gSymbolFiles != v2Sf: return getID()
let module = db.getRow(
proc getModuleId*(g: ModuleGraph; fileIdx: FileIndex; fullpath: string): int =
if g.config.symbolFiles != v2Sf: return getID()
let module = g.incr.db.getRow(
sql"select id, fullHash from modules where fullpath = ?", fullpath)
let currentFullhash = hashFileCached(fileIdx, fullpath)
let currentFullhash = hashFileCached(g.config, fileIdx, fullpath)
if module[0].len == 0:
result = int db.insertID(sql"insert into modules(fullpath, interfHash, fullHash) values (?, ?, ?)",
fullpath, "", currentFullhash)
else:
result = parseInt(module[0])
if currentFullhash == module[1]:
# not changed, so use the cached AST (even if it might be wrong
# due to its dependencies):
# not changed, so use the cached AST:
doAssert(result != 0)
var cycleCheck = initIntSet()
if not needsRecompile(fileIdx, fullpath, cycleCheck):
if not needsRecompile(g, fileIdx, fullpath, cycleCheck):
return -result
db.exec(sql"update modules set fullHash = ? where id = ?", currentFullhash, module[0])
db.exec(sql"delete from deps where module = ?", module[0])
@@ -66,20 +65,6 @@ proc getModuleId*(g: ModuleGraph; fileIdx: int32; fullpath: string): int =
db.exec(sql"delete from toplevelstmts where module = ?", module[0])
db.exec(sql"delete from statics where module = ?", module[0])
type
TRodWriter = object
module: PSym
sstack: seq[PSym] # a stack of symbols to process
tstack: seq[PType] # a stack of types to process
tmarks, smarks: IntSet
forwardedSyms: seq[PSym]
PRodWriter = var TRodWriter
proc initRodWriter(module: PSym): TRodWriter =
result = TRodWriter(module: module, sstack: @[], tstack: @[],
tmarks: initIntSet(), smarks: initIntSet(), forwardedSyms: @[])
when false:
proc getDefines(): string =
result = ""
@@ -87,18 +72,17 @@ when false:
if result.len != 0: add(result, " ")
add(result, d)
const
rodNL = "\L"
proc pushType(w: PRodWriter, t: PType) =
proc pushType(w: var Writer, t: PType) =
if not containsOrIncl(w.tmarks, t.id):
w.tstack.add(t)
proc pushSym(w: PRodWriter, s: PSym) =
proc pushSym(w: var Writer, s: PSym) =
if not containsOrIncl(w.smarks, s.id):
w.sstack.add(s)
proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode,
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:
@@ -113,14 +97,14 @@ proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode,
result.add('?')
encodeVInt(n.info.col, result)
result.add(',')
encodeVInt(n.info.line, result)
encodeVInt(int n.info.line, result)
result.add(',')
encodeVInt(toDbFileId(n.info.fileIndex), result)
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(n.info.line, result)
encodeVInt(int n.info.line, result)
elif fInfo.col != n.info.col:
result.add('?')
encodeVInt(n.info.col, result)
@@ -156,10 +140,10 @@ proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode,
pushSym(w, n.sym)
else:
for i in countup(0, sonsLen(n) - 1):
encodeNode(w, n.info, n.sons[i], result)
encodeNode(g, n.info, n.sons[i], result)
add(result, ')')
proc encodeLoc(w: PRodWriter, loc: TLoc, result: var string) =
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)
@@ -171,7 +155,7 @@ proc encodeLoc(w: PRodWriter, loc: TLoc, result: var string) =
encodeVInt(cast[int32](loc.flags), result)
if loc.lode != nil:
add(result, '^')
encodeNode(w, unknownLineInfo(), loc.lode, result)
encodeNode(g, unknownLineInfo(), loc.lode, result)
#encodeVInt(cast[int32](loc.t.id), result)
#pushType(w, loc.t)
if loc.r != nil:
@@ -183,13 +167,13 @@ proc encodeLoc(w: PRodWriter, loc: TLoc, result: var string) =
else:
add(result, '>')
proc encodeType(w: PRodWriter, t: PType, result: var string) =
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("encodeType: tyForward")
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, '[')
@@ -197,7 +181,7 @@ proc encodeType(w: PRodWriter, t: PType, result: var string) =
add(result, '+')
encodeVInt(t.id, result)
if t.n != nil:
encodeNode(w, w.module.info, t.n, result)
encodeNode(g, unknownLineInfo(), t.n, result)
if t.flags != {}:
add(result, '$')
encodeVInt(cast[int32](t.flags), result)
@@ -243,7 +227,7 @@ proc encodeType(w: PRodWriter, t: PType, result: var string) =
add(result, '\20')
encodeVInt(s.id, result)
pushSym(w, s)
encodeLoc(w, t.loc, result)
encodeLoc(g, t.loc, result)
for i in countup(0, sonsLen(t) - 1):
if t.sons[i] == nil:
add(result, "^()")
@@ -252,15 +236,15 @@ proc encodeType(w: PRodWriter, t: PType, result: var string) =
encodeVInt(t.sons[i].id, result)
pushType(w, t.sons[i])
proc encodeLib(w: PRodWriter, lib: PLib, info: TLineInfo, result: var string) =
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(w, info, lib.path, result)
encodeNode(g, info, lib.path, result)
proc encodeInstantiations(w: PRodWriter; s: seq[PInstantiation];
proc encodeInstantiations(g: ModuleGraph; s: seq[PInstantiation];
result: var string) =
for t in s:
result.add('\15')
@@ -273,7 +257,7 @@ proc encodeInstantiations(w: PRodWriter; s: seq[PInstantiation];
result.add('\20')
encodeVInt(t.compilesId, result)
proc encodeSym(w: PRodWriter, s: PSym, result: var string) =
proc encodeSym(g: ModuleGraph, s: PSym, result: var string) =
if s == nil:
# nil nodes have to be stored too:
result.add("{}")
@@ -291,9 +275,9 @@ proc encodeSym(w: PRodWriter, s: PSym, result: var string) =
result.add('?')
if s.info.col != -1'i16: encodeVInt(s.info.col, result)
result.add(',')
if s.info.line != -1'i16: encodeVInt(s.info.line, result)
encodeVInt(int s.info.line, result)
result.add(',')
encodeVInt(toDbFileId(s.info.fileIndex), result)
encodeVInt(toDbFileId(g.incr, g.config, s.info.fileIndex), result)
if s.owner != nil:
result.add('*')
encodeVInt(s.owner.id, result)
@@ -312,11 +296,11 @@ proc encodeSym(w: PRodWriter, s: PSym, result: var string) =
if s.offset != - 1:
result.add('`')
encodeVInt(s.offset, result)
encodeLoc(w, s.loc, result)
if s.annex != nil: encodeLib(w, s.annex, s.info, result)
encodeLoc(g, s.loc, result)
if s.annex != nil: encodeLib(g, s.annex, s.info, result)
if s.constraint != nil:
add(result, '#')
encodeNode(w, unknownLineInfo(), s.constraint, result)
encodeNode(g, unknownLineInfo(), s.constraint, result)
case s.kind
of skType, skGenericParam:
for t in s.typeInstCache:
@@ -324,13 +308,13 @@ proc encodeSym(w: PRodWriter, s: PSym, result: var string) =
encodeVInt(t.id, result)
pushType(w, t)
of routineKinds:
encodeInstantiations(w, s.procInstCache, result)
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(w, s.usedGenerics, result)
encodeInstantiations(g, s.usedGenerics, result)
# we don't serialize:
#tab*: TStrTable # interface table for modules
of skLet, skVar, skField, skForVar:
@@ -348,47 +332,44 @@ proc encodeSym(w: PRodWriter, s: PSym, result: var string) =
# 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(w, s.info, s.ast, result)
encodeNode(g, s.info, s.ast, result)
proc storeSym(w: PRodWriter; s: PSym) =
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(w, s, buf)
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.
db.exec(sql"insert into syms(nimid, module, name, data, exported) values (?, ?, ?, ?, ?)",
s.id, abs(w.module.id), s.name.s, buf, ord(sfExported in s.flags))
s.id, abs(getModule(s).id), s.name.s, buf, ord(sfExported in s.flags))
proc storeType(w: PRodWriter; t: PType) =
proc storeType(g: ModuleGraph; t: PType) =
var buf = newStringOfCap(160)
encodeType(w, t, buf)
encodeType(g, t, buf)
db.exec(sql"insert into types(nimid, module, data) values (?, ?, ?)",
t.id, abs(w.module.id), buf)
var w = initRodWriter(nil)
t.id, abs(getModule(t.owner).id), buf)
proc storeNode*(g: ModuleGraph; module: PSym; n: PNode) =
if gSymbolFiles != v2Sf: return
w.module = module
if g.config.symbolFiles != v2Sf: return
var buf = newStringOfCap(160)
encodeNode(w, module.info, n, buf)
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:
quit "loop never ends!"
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(w, s)
storeSym(g, s)
elif w.tstack.len > 0:
let t = w.tstack.pop()
storeType(w, t)
storeType(g, t)
when false:
echo "popped type ", typeToString(t), " ", t.id
else:
@@ -396,57 +377,39 @@ proc storeNode*(g: ModuleGraph; module: PSym; n: PNode) =
inc i
proc storeRemaining*(g: ModuleGraph; module: PSym) =
if gSymbolFiles != v2Sf: return
w.module = module
if g.config.symbolFiles != v2Sf: return
for s in w.forwardedSyms:
assert sfForward notin s.flags
storeSym(w, s)
storeSym(g, s)
w.forwardedSyms.setLen 0
# ---------------- decoder -----------------------------------
type
TRodReader = object
module: PSym
#sstack: seq[(PSym, ptr PSym)] # a stack of symbols to process
#tstack: seq[(PType, ptr PType)] # a stack of types to process
#tmarks, smarks: IntSet
syms: Table[int, PSym] ## XXX make this more efficient
types: Table[int, PType]
cache: IdentCache
BlobReader = object
s: string
pos: int
PRodReader = var TRodReader
proc initRodReader(cache: IdentCache): TRodReader =
TRodReader(module: nil,
syms: initTable[int, PSym](), types: initTable[int, PType](),
cache: cache)
var gr = initRodReader(newIdentCache())
using
r: PRodReader
r: var Reader
b: var BlobReader
g: ModuleGraph
proc loadSym(r; id: int, info: TLineInfo): PSym
proc loadType(r; id: int, info: TLineInfo): PType
proc loadSym(g; id: int, info: TLineInfo): PSym
proc loadType(g; id: int, info: TLineInfo): PType
proc decodeLineInfo(r; b; info: var TLineInfo) =
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 = -1'i16
else: info.line = int16(decodeVInt(b.s, 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(decodeVInt(b.s, b.pos))
info.fileIndex = fromDbFileId(g.incr, g.config, decodeVInt(b.s, b.pos))
proc skipNode(b) =
assert b.s[b.pos] == '('
@@ -462,7 +425,7 @@ proc skipNode(b) =
inc pos
b.pos = pos+1 # skip ')'
proc decodeNodeLazyBody(r; b; fInfo: TLineInfo,
proc decodeNodeLazyBody(g; b; fInfo: TLineInfo,
belongsTo: PSym): PNode =
result = nil
if b.s[b.pos] == '(':
@@ -471,14 +434,14 @@ proc decodeNodeLazyBody(r; b; fInfo: TLineInfo,
inc(b.pos)
return # nil node
result = newNodeI(TNodeKind(decodeVInt(b.s, b.pos)), fInfo)
decodeLineInfo(r, b, result.info)
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(r, id, result.info)
result.typ = loadType(g, id, result.info)
case result.kind
of nkCharLit..nkUInt64Lit:
if b.s[b.pos] == '!':
@@ -499,16 +462,16 @@ proc decodeNodeLazyBody(r; b; fInfo: TLineInfo,
if b.s[b.pos] == '!':
inc(b.pos)
var fl = decodeStr(b.s, b.pos)
result.ident = r.cache.getIdent(fl)
result.ident = g.cache.getIdent(fl)
else:
internalError(result.info, "decodeNode: nkIdent")
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(r, id, result.info)
result.sym = loadSym(g, id, result.info)
else:
internalError(result.info, "decodeNode: nkSym")
internalError(g.config, result.info, "decodeNode: nkSym")
else:
var i = 0
while b.s[b.pos] != ')':
@@ -519,17 +482,17 @@ proc decodeNodeLazyBody(r; b; fInfo: TLineInfo,
skipNode(b)
else:
discard
addSonNilAllowed(result, decodeNodeLazyBody(r, b, result.info, nil))
addSonNilAllowed(result, decodeNodeLazyBody(g, b, result.info, nil))
inc i
if b.s[b.pos] == ')': inc(b.pos)
else: internalError(result.info, "decodeNode: ')' missing")
else: internalError(g.config, result.info, "decodeNode: ')' missing")
else:
internalError(fInfo, "decodeNode: '(' missing " & $b.pos)
internalError(g.config, fInfo, "decodeNode: '(' missing " & $b.pos)
proc decodeNode(r; b; fInfo: TLineInfo): PNode =
result = decodeNodeLazyBody(r, b, fInfo, nil)
proc decodeNode(g; b; fInfo: TLineInfo): PNode =
result = decodeNodeLazyBody(g, b, fInfo, nil)
proc decodeLoc(r; b; loc: var TLoc, info: TLineInfo) =
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'}:
@@ -548,7 +511,7 @@ proc decodeLoc(r; b; loc: var TLoc, info: TLineInfo) =
loc.flags = {}
if b.s[b.pos] == '^':
inc(b.pos)
loc.lode = decodeNode(r, b, info)
loc.lode = decodeNode(g, b, info)
# rrGetType(b, decodeVInt(b.s, b.pos), info)
else:
loc.lode = nil
@@ -558,19 +521,19 @@ proc decodeLoc(r; b; loc: var TLoc, info: TLineInfo) =
else:
loc.r = nil
if b.s[b.pos] == '>': inc(b.pos)
else: internalError(info, "decodeLoc " & b.s[b.pos])
else: internalError(g.config, info, "decodeLoc " & b.s[b.pos])
proc loadBlob(query: SqlQuery; id: int): BlobReader =
proc loadBlob(g; query: SqlQuery; id: int): BlobReader =
let blob = db.getValue(query, id)
if blob.len == 0:
internalError("symbolfiles: cannot find ID " & $ id)
internalError(g.config, "symbolfiles: cannot find ID " & $ id)
result = BlobReader(pos: 0)
shallowCopy(result.s, blob)
proc loadType(r; id: int; info: TLineInfo): PType =
result = r.types.getOrDefault(id)
proc loadType(g; id: int; info: TLineInfo): PType =
result = g.incr.r.types.getOrDefault(id)
if result != nil: return result
var b = loadBlob(sql"select data from types where nimid = ?", id)
var b = loadBlob(g, sql"select data from types where nimid = ?", id)
if b.s[b.pos] == '[':
inc(b.pos)
@@ -585,10 +548,10 @@ proc loadType(r; id: int; info: TLineInfo): PType =
setId(result.id)
#if debugIds: registerID(result)
else:
internalError(info, "decodeType: no id")
internalError(g.config, info, "decodeType: no id")
# here this also avoids endless recursion for recursive type
r.types[result.id] = result
if b.s[b.pos] == '(': result.n = decodeNode(r, b, unknownLineInfo())
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)))
@@ -597,10 +560,10 @@ proc loadType(r; id: int; info: TLineInfo): PType =
result.callConv = TCallingConvention(decodeVInt(b.s, b.pos))
if b.s[b.pos] == '*':
inc(b.pos)
result.owner = loadSym(r, decodeVInt(b.s, b.pos), info)
result.owner = loadSym(g, decodeVInt(b.s, b.pos), info)
if b.s[b.pos] == '&':
inc(b.pos)
result.sym = loadSym(r, decodeVInt(b.s, b.pos), info)
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)
@@ -620,65 +583,65 @@ proc loadType(r; id: int; info: TLineInfo): PType =
if b.s[b.pos] == '\15':
inc(b.pos)
result.destructor = loadSym(r, decodeVInt(b.s, b.pos), info)
result.destructor = loadSym(g, decodeVInt(b.s, b.pos), info)
if b.s[b.pos] == '\16':
inc(b.pos)
result.deepCopy = loadSym(r, decodeVInt(b.s, b.pos), info)
result.deepCopy = loadSym(g, decodeVInt(b.s, b.pos), info)
if b.s[b.pos] == '\17':
inc(b.pos)
result.assignment = loadSym(r, decodeVInt(b.s, b.pos), info)
result.assignment = loadSym(g, decodeVInt(b.s, b.pos), info)
if b.s[b.pos] == '\18':
inc(b.pos)
result.sink = loadSym(r, decodeVInt(b.s, b.pos), info)
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(r, decodeVInt(b.s, b.pos), info)
let y = loadSym(g, decodeVInt(b.s, b.pos), info)
result.methods.safeAdd((x, y))
decodeLoc(r, b, result.loc, info)
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(info, "decodeType ^(" & b.s[b.pos])
else: internalError(g.config, info, "decodeType ^(" & b.s[b.pos])
rawAddSon(result, nil)
else:
var d = decodeVInt(b.s, b.pos)
rawAddSon(result, loadType(r, d, info))
let d = decodeVInt(b.s, b.pos)
rawAddSon(result, loadType(g, d, info))
proc decodeLib(r; b; info: TLineInfo): PLib =
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("decodeLib: 1")
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("decodeLib: 2")
if b.s[b.pos] != '|': internalError(g.config, "decodeLib: 2")
inc(b.pos)
result.path = decodeNode(r, b, info)
result.path = decodeNode(g, b, info)
proc decodeInstantiations(r; b; info: TLineInfo;
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(r, decodeVInt(b.s, b.pos), info)
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(r, decodeVInt(b.s, b.pos), info)
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(r; b; info: TLineInfo): PSym =
proc loadSymFromBlob(g; b; info: TLineInfo): PSym =
if b.s[b.pos] == '{':
inc(b.pos)
if b.s[b.pos] == '}':
@@ -691,26 +654,26 @@ proc loadSymFromBlob(r; b; info: TLineInfo): PSym =
id = decodeVInt(b.s, b.pos)
setId(id)
else:
internalError(info, "decodeSym: no id")
internalError(g.config, info, "decodeSym: no id")
var ident: PIdent
if b.s[b.pos] == '&':
inc(b.pos)
ident = r.cache.getIdent(decodeStr(b.s, b.pos))
ident = g.cache.getIdent(decodeStr(b.s, b.pos))
else:
internalError(info, "decodeSym: no ident")
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:
r.syms[result.id] = result
g.incr.r.syms.add(result.id, result)
if b.s[b.pos] == '^':
inc(b.pos)
result.typ = loadType(r, decodeVInt(b.s, b.pos), info)
decodeLineInfo(r, b, result.info)
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(r, decodeVInt(b.s, b.pos), result.info)
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)))
@@ -720,8 +683,6 @@ proc loadSymFromBlob(r; b; info: TLineInfo): PSym =
if b.s[b.pos] == '!':
inc(b.pos)
result.options = cast[TOptions](int32(decodeVInt(b.s, b.pos)))
else:
result.options = r.module.options
if b.s[b.pos] == '%':
inc(b.pos)
result.position = decodeVInt(b.s, b.pos)
@@ -729,28 +690,28 @@ proc loadSymFromBlob(r; b; info: TLineInfo): PSym =
inc(b.pos)
result.offset = decodeVInt(b.s, b.pos)
else:
result.offset = - 1
decodeLoc(r, b, result.loc, result.info)
result.annex = decodeLib(r, b, info)
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(r, b, unknownLineInfo())
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(r, decodeVInt(b.s, b.pos), result.info)
result.typeInstCache.safeAdd loadType(g, decodeVInt(b.s, b.pos), result.info)
of routineKinds:
decodeInstantiations(r, b, result.info, result.procInstCache)
decodeInstantiations(g, b, result.info, result.procInstCache)
if b.s[b.pos] == '\16':
inc(b.pos)
result.gcUnsafetyReason = loadSym(r, decodeVInt(b.s, b.pos), result.info)
result.gcUnsafetyReason = loadSym(g, decodeVInt(b.s, b.pos), result.info)
of skModule, skPackage:
decodeInstantiations(r, b, result.info, result.usedGenerics)
decodeInstantiations(g, b, result.info, result.usedGenerics)
of skLet, skVar, skField, skForVar:
if b.s[b.pos] == '\18':
inc(b.pos)
result.guard = loadSym(r, decodeVInt(b.s, b.pos), result.info)
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
@@ -760,37 +721,37 @@ proc loadSymFromBlob(r; b; info: TLineInfo): PSym =
#if result.kind in routineKinds:
# result.ast = decodeNodeLazyBody(b, result.info, result)
#else:
result.ast = decodeNode(r, b, result.info)
result.ast = decodeNode(g, b, result.info)
if sfCompilerProc in result.flags:
registerCompilerProc(result)
registerCompilerProc(g, result)
#echo "loading ", result.name.s
proc loadSym(r; id: int; info: TLineInfo): PSym =
result = r.syms.getOrDefault(id)
proc loadSym(g; id: int; info: TLineInfo): PSym =
result = g.incr.r.syms.getOrDefault(id)
if result != nil: return result
var b = loadBlob(sql"select data from syms where nimid = ?", id)
result = loadSymFromBlob(r, b, info)
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(r; module: PSym) =
proc loadModuleSymTab(g; module: PSym) =
## goal: fill module.tab
gr.syms[module.id] = module
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 = r.syms.getOrDefault(id)
var s = g.incr.r.syms.getOrDefault(id)
if s == nil:
var b = BlobReader(pos: 0)
shallowCopy(b.s, row[1])
s = loadSymFromBlob(r, b, module.info)
s = loadSymFromBlob(g, b, module.info)
assert s != nil
strTableAdd(module.tab, s)
if sfSystemModule in module.flags:
magicsys.systemModule = module
g.systemModule = module
proc loadNode*(g: ModuleGraph; module: PSym; index: int): PNode =
assert gSymbolFiles == v2Sf
assert g.config.symbolFiles == v2Sf
if index == 0:
loadModuleSymTab(gr, module)
loadModuleSymTab(g, module)
#index = parseInt db.getValue(
# sql"select min(id) from toplevelstmts where module = ?", abs module.id)
var b = BlobReader(pos: 0)
@@ -799,16 +760,15 @@ proc loadNode*(g: ModuleGraph; module: PSym; index: int): PNode =
if b.s.len == 0:
db.exec(sql"insert into controlblock(idgen) values (?)", gFrontEndId)
return nil # end marker
gr.module = module
result = decodeNode(gr, b, module.info)
result = decodeNode(g, b, module.info)
proc setupModuleCache*(g: ModuleGraph) =
if gSymbolFiles != v2Sf: return
if g.config.symbolFiles != v2Sf: return
let dbfile = getNimcacheDir(g.config) / "rodfiles.db"
if not fileExists(dbfile):
db = open(connection=dbfile, user="nim", password="",
database="nim")
createDb()
createDb(db)
else:
db = open(connection=dbfile, user="nim", password="",
database="nim")