symbol files: more progress

This commit is contained in:
Araq 2018-02-20 01:15:43 +01:00
commit 2fcc163746
5 changed files with 107 additions and 32 deletions

View file

@ -169,12 +169,14 @@ proc compileModule*(graph: ModuleGraph; fileIdx: int32; cache: IdentCache, flags
if sfMainModule in result.flags: if sfMainModule in result.flags:
gMainPackageId = result.owner.id gMainPackageId = result.owner.id
when false:
if gCmd in {cmdCompileToC, cmdCompileToCpp, cmdCheck, cmdIdeTools}: if gCmd in {cmdCompileToC, cmdCompileToCpp, cmdCheck, cmdIdeTools}:
rd = handleSymbolFile(result, cache) rd = handleSymbolFile(result, cache)
if result.id < 0: if result.id < 0:
internalError("handleSymbolFile should have set the module's ID") internalError("handleSymbolFile should have set the module's ID")
return return
else: else:
discard
result.id = getModuleId(toFullPath(fileIdx)) result.id = getModuleId(toFullPath(fileIdx))
discard processModule(graph, result, discard processModule(graph, result,
if sfMainModule in flags and gProjectIsStdin: stdin.llStreamOpen else: nil, if sfMainModule in flags and gProjectIsStdin: stdin.llStreamOpen else: nil,

View file

@ -7,13 +7,13 @@
# distribution, for details about the copyright. # distribution, for details about the copyright.
# #
# This module implements the passes functionality. A pass must implement the ## This module implements the passes functionality. A pass must implement the
# `TPass` interface. ## `TPass` interface.
import import
strutils, options, ast, astalgo, llstream, msgs, platform, os, strutils, options, ast, astalgo, llstream, msgs, platform, os,
condsyms, idents, renderer, types, extccomp, math, magicsys, nversion, condsyms, idents, renderer, types, extccomp, math, magicsys, nversion,
nimsets, syntaxes, times, rodread, idgen, modulegraphs, reorder nimsets, syntaxes, times, rodread, idgen, modulegraphs, reorder, rod
type type
@ -29,7 +29,8 @@ type
TPassProcess* = proc (p: PPassContext, topLevelStmt: PNode): PNode {.nimcall.} TPassProcess* = proc (p: PPassContext, topLevelStmt: PNode): PNode {.nimcall.}
TPass* = tuple[open: TPassOpen, openCached: TPassOpenCached, TPass* = tuple[open: TPassOpen, openCached: TPassOpenCached,
process: TPassProcess, close: TPassClose] process: TPassProcess, close: TPassClose,
isFrontend: bool]
TPassData* = tuple[input: PNode, closeOutput: PNode] TPassData* = tuple[input: PNode, closeOutput: PNode]
TPasses* = openArray[TPass] TPasses* = openArray[TPass]
@ -41,11 +42,13 @@ type
proc makePass*(open: TPassOpen = nil, proc makePass*(open: TPassOpen = nil,
openCached: TPassOpenCached = nil, openCached: TPassOpenCached = nil,
process: TPassProcess = nil, process: TPassProcess = nil,
close: TPassClose = nil): TPass = close: TPassClose = nil,
isFrontend = false): TPass =
result.open = open result.open = open
result.openCached = openCached result.openCached = openCached
result.close = close result.close = close
result.process = process result.process = process
result.isFrontend = isFrontend
# the semantic checker needs these: # the semantic checker needs these:
var var
@ -178,7 +181,34 @@ proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream,
a: TPassContextArray a: TPassContextArray
s: PLLStream s: PLLStream
fileIdx = module.fileIdx fileIdx = module.fileIdx
if rd == nil: if module.id < 0:
# new module caching mechanism:
for i in 0..<gPassesLen:
if not isNil(gPasses[i].open) and not gPasses[i].isFrontend:
a[i] = gPasses[i].open(graph, module, cache)
else:
a[i] = nil
var stmtIndex = 0
var doContinue = true
while doContinue:
let n = loadNode(module, stmtIndex)
if n == nil or graph.stopCompile(): break
inc stmtIndex
var m = n
for i in 0..<gPassesLen:
if not isNil(gPasses[i].process) and not gPasses[i].isFrontend:
m = gPasses[i].process(a[i], m)
if isNil(m):
doContinue = false
break
var m: PNode = nil
for i in 0..<gPassesLen:
if not isNil(gPasses[i].close) and not gPasses[i].isFrontend:
m = gPasses[i].close(graph, a[i], m)
a[i] = nil
elif rd == nil:
openPasses(graph, a, module, cache) openPasses(graph, a, module, cache)
if stream == nil: if stream == nil:
let filename = fileIdx.toFullPathConsiderDirty let filename = fileIdx.toFullPathConsiderDirty

View file

@ -14,7 +14,7 @@ import ast, idgen
when not defined(nimSymbolfiles): when not defined(nimSymbolfiles):
template setupModuleCache* = discard template setupModuleCache* = discard
template storeNode*(module: PSym; n: PNode) = discard template storeNode*(module: PSym; n: PNode) = discard
template loadNode*(module: PSym; index: var int): PNode = discard template loadNode*(module: PSym; index: var int): PNode = PNode(nil)
template getModuleId*(fullpath: string): int = getID() template getModuleId*(fullpath: string): int = getID()

View file

@ -7,10 +7,10 @@
# distribution, for details about the copyright. # distribution, for details about the copyright.
# #
## This module implements the canonalization for the various caching mechanisms. ## This module implements the new compilation cache.
import strutils, os, intsets, tables, ropes, db_sqlite, msgs, options, types, import strutils, os, intsets, tables, ropes, db_sqlite, msgs, options, types,
renderer, rodutils, std / sha1, idents renderer, rodutils, std / sha1, idents, astalgo, magicsys
var db: DbConn var db: DbConn
@ -20,7 +20,7 @@ proc getModuleId*(fullpath: string): int =
sql"select id, fullHash from modules where fullpath = ?", fullpath) sql"select id, fullHash from modules where fullpath = ?", fullpath)
let currentFullhash = $secureHashFile(fullpath) let currentFullhash = $secureHashFile(fullpath)
if module[0].len == 0: if module[0].len == 0:
result = int db.insertID(sql"insert into modules(fullpath, interfHash, fullHash) values (?, ?)", result = int db.insertID(sql"insert into modules(fullpath, interfHash, fullHash) values (?, ?, ?)",
fullpath, "", currentFullhash) fullpath, "", currentFullhash)
else: else:
result = parseInt(module[0]) result = parseInt(module[0])
@ -74,6 +74,19 @@ proc pushSym(w: PRodWriter, s: PSym) =
if not containsOrIncl(w.smarks, s.id): if not containsOrIncl(w.smarks, s.id):
w.sstack.add(s) w.sstack.add(s)
proc toDbFileId(fullpath: string): int =
let id = db.getValue(sql"select id from filenames where fullpath = ?",
fullpath)
if id.len == 0:
result = int db.insertID(sql"insert into filenames(fullpath) values (?)", fullpath)
else:
result = parseInt(id)
proc fromDbFileId(dbId: int): int32 =
let fullpath = db.getValue(sql"select fullpath from filenames where id = ?", dbId)
doAssert fullpath.len > 0, "cannot find file name for DB ID " & $dbId
result = fileInfoIdx(fullpath)
proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode, proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode,
result: var string) = result: var string) =
if n == nil: if n == nil:
@ -91,7 +104,7 @@ proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode,
result.add(',') result.add(',')
encodeVInt(n.info.line, result) encodeVInt(n.info.line, result)
result.add(',') result.add(',')
encodeVInt(n.info.fileIndex, result) encodeVInt(toDbFileId(n.info.toFullPath), result)
elif fInfo.line != n.info.line: elif fInfo.line != n.info.line:
result.add('?') result.add('?')
encodeVInt(n.info.col, result) encodeVInt(n.info.col, result)
@ -269,7 +282,7 @@ proc encodeSym(w: PRodWriter, s: PSym, result: var string) =
result.add(',') result.add(',')
if s.info.line != -1'i16: encodeVInt(s.info.line, result) if s.info.line != -1'i16: encodeVInt(s.info.line, result)
result.add(',') result.add(',')
encodeVInt(s.info.fileIndex, result) encodeVInt(toDbFileId(s.info.toFullPath), result)
if s.owner != nil: if s.owner != nil:
result.add('*') result.add('*')
encodeVInt(s.owner.id, result) encodeVInt(s.owner.id, result)
@ -331,8 +344,8 @@ proc storeSym(w: PRodWriter; s: PSym) =
encodeSym(w, s, buf) encodeSym(w, s, buf)
# XXX only store the name for exported symbols in order to speed up lookup # XXX only store the name for exported symbols in order to speed up lookup
# times once we enable the skStub logic. # times once we enable the skStub logic.
db.exec(sql"insert into syms(nimid, module, name, data) values (?, ?, ?, ?)", db.exec(sql"insert into syms(nimid, module, name, data, exported) values (?, ?, ?, ?, ?)",
s.id, abs(w.module.id), s.name.s, buf) s.id, abs(w.module.id), s.name.s, buf, ord(sfExported in s.flags))
proc storeType(w: PRodWriter; t: PType) = proc storeType(w: PRodWriter; t: PType) =
var buf = newStringOfCap(160) var buf = newStringOfCap(160)
@ -410,7 +423,7 @@ proc decodeLineInfo(r; b; info: var TLineInfo) =
else: info.line = int16(decodeVInt(b.s, b.pos)) else: info.line = int16(decodeVInt(b.s, b.pos))
if b.s[b.pos] == ',': if b.s[b.pos] == ',':
inc(b.pos) inc(b.pos)
info.fileIndex = int32(decodeVInt(b.s, b.pos)) info.fileIndex = fromDbFileId(decodeVInt(b.s, b.pos))
proc skipNode(b) = proc skipNode(b) =
assert b.s[b.pos] == '(' assert b.s[b.pos] == '('
@ -642,25 +655,21 @@ proc decodeInstantiations(r; b; info: TLineInfo;
ii.compilesId = decodeVInt(b.s, b.pos) ii.compilesId = decodeVInt(b.s, b.pos)
s.safeAdd ii s.safeAdd ii
proc loadSym(r; id: int; info: TLineInfo): PSym = proc loadSymFromBlob(r; b; info: TLineInfo): PSym =
var
id: int
ident: PIdent
result = r.syms.getOrDefault(id)
if result != nil: return result
var b = loadBlob(sql"select data from syms where nimid = ?", id)
if b.s[b.pos] == '{': if b.s[b.pos] == '{':
inc(b.pos) inc(b.pos)
if b.s[b.pos] == '}': if b.s[b.pos] == '}':
inc(b.pos) inc(b.pos)
return # nil sym return # nil sym
var k = TSymKind(decodeVInt(b.s, b.pos)) var k = TSymKind(decodeVInt(b.s, b.pos))
var id: int
if b.s[b.pos] == '+': if b.s[b.pos] == '+':
inc(b.pos) inc(b.pos)
id = decodeVInt(b.s, b.pos) id = decodeVInt(b.s, b.pos)
setId(id) setId(id)
else: else:
internalError(info, "decodeSym: no id") internalError(info, "decodeSym: no id")
var ident: PIdent
if b.s[b.pos] == '&': if b.s[b.pos] == '&':
inc(b.pos) inc(b.pos)
ident = r.cache.getIdent(decodeStr(b.s, b.pos)) ident = r.cache.getIdent(decodeStr(b.s, b.pos))
@ -729,9 +738,34 @@ proc loadSym(r; id: int; info: TLineInfo): PSym =
# result.ast = decodeNodeLazyBody(b, result.info, result) # result.ast = decodeNodeLazyBody(b, result.info, result)
#else: #else:
result.ast = decodeNode(r, b, result.info) result.ast = decodeNode(r, b, result.info)
if sfCompilerProc in result.flags:
registerCompilerProc(result)
proc loadSym(r; id: int; info: TLineInfo): PSym =
result = 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)
doAssert id == result.id, "symbol ID is not consistent!"
proc loadModuleSymTab(r; module: PSym) =
## goal: fill module.tab
gr.syms[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)
if s == nil:
var b = BlobReader(pos: 0)
shallowCopy(b.s, row[1])
s = loadSymFromBlob(r, b, module.info)
assert s != nil
strTableAdd(module.tab, s)
if sfSystemModule in module.flags:
magicsys.systemModule = module
proc loadNode*(module: PSym; index: var int): PNode = proc loadNode*(module: PSym; index: var int): PNode =
if index == 0: if index == 0:
loadModuleSymTab(gr, module)
index = parseInt db.getValue( index = parseInt db.getValue(
sql"select min(id) from toplevelstmts where module = ?", abs module.id) sql"select min(id) from toplevelstmts where module = ?", abs module.id)
var b = BlobReader(pos: 0) var b = BlobReader(pos: 0)
@ -749,6 +783,14 @@ proc createDb() =
); );
""") """)
db.exec(sql"""
create table if not exists filenames(
id integer primary key,
fullpath varchar(8000) not null
);
""")
db.exec sql"create index if not exists FilenameIx on filenames(fullpath);"
db.exec(sql""" db.exec(sql"""
create table if not exists modules( create table if not exists modules(
id integer primary key, id integer primary key,
@ -779,6 +821,7 @@ proc createDb() =
module integer not null, module integer not null,
name varchar(256) not null, name varchar(256) not null,
data blob not null, data blob not null,
exported int not null,
foreign key (module) references module(id) foreign key (module) references module(id)
); );
""") """)
@ -798,7 +841,6 @@ proc createDb() =
""") """)
db.exec sql"create index TopLevelStmtByModuleIdx on toplevelstmts(module);" db.exec sql"create index TopLevelStmtByModuleIdx on toplevelstmts(module);"
db.exec(sql""" db.exec(sql"""
create table if not exists statics( create table if not exists statics(
id integer primary key, id integer primary key,

View file

@ -621,4 +621,5 @@ proc myClose(graph: ModuleGraph; context: PPassContext, n: PNode): PNode =
popProcCon(c) popProcCon(c)
if c.runnableExamples != nil: testExamples(c) if c.runnableExamples != nil: testExamples(c)
const semPass* = makePass(myOpen, myOpenCached, myProcess, myClose) const semPass* = makePass(myOpen, myOpenCached, myProcess, myClose,
isFrontend = true)