rodimpl.nim 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2018 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ## This module implements the new compilation cache.
  10. import strutils, os, intsets, tables, ropes, db_sqlite, msgs, options, types,
  11. renderer, rodutils, idents, astalgo, btrees, magicsys, cgmeth, extccomp,
  12. btrees, trees, condsyms, nversion, pathutils
  13. ## Todo:
  14. ## - Dependency computation should use *signature* hashes in order to
  15. ## avoid recompiling dependent modules.
  16. ## - Patch the rest of the compiler to do lazy loading of proc bodies.
  17. ## - Patch the C codegen to cache proc bodies and maybe types.
  18. template db(): DbConn = g.incr.db
  19. proc encodeConfig(g: ModuleGraph): string =
  20. result = newStringOfCap(100)
  21. result.add RodFileVersion
  22. for d in definedSymbolNames(g.config.symbols):
  23. result.add ' '
  24. result.add d
  25. template serialize(field) =
  26. result.add ' '
  27. result.add($g.config.field)
  28. depConfigFields(serialize)
  29. proc needsRecompile(g: ModuleGraph; fileIdx: FileIndex; fullpath: AbsoluteFile;
  30. cycleCheck: var IntSet): bool =
  31. let root = db.getRow(sql"select id, fullhash from filenames where fullpath = ?",
  32. fullpath.string)
  33. if root[0].len == 0: return true
  34. if root[1] != hashFileCached(g.config, fileIdx, fullpath):
  35. return true
  36. # cycle detection: assume "not changed" is correct.
  37. if cycleCheck.containsOrIncl(int fileIdx):
  38. return false
  39. # check dependencies (recursively):
  40. for row in db.fastRows(sql"select fullpath from filenames where id in (select dependency from deps where module = ?)",
  41. root[0]):
  42. let dep = AbsoluteFile row[0]
  43. if needsRecompile(g, g.config.fileInfoIdx(dep), dep, cycleCheck):
  44. return true
  45. return false
  46. proc getModuleId*(g: ModuleGraph; fileIdx: FileIndex; fullpath: AbsoluteFile): int =
  47. ## Analyse the known dependency graph.
  48. if g.config.symbolFiles == disabledSf: return getID()
  49. when false:
  50. if g.config.symbolFiles in {disabledSf, writeOnlySf} or
  51. g.incr.configChanged:
  52. return getID()
  53. let module = g.incr.db.getRow(
  54. sql"select id, fullHash, nimid from modules where fullpath = ?", string fullpath)
  55. let currentFullhash = hashFileCached(g.config, fileIdx, fullpath)
  56. if module[0].len == 0:
  57. result = getID()
  58. db.exec(sql"insert into modules(fullpath, interfHash, fullHash, nimid) values (?, ?, ?, ?)",
  59. string fullpath, "", currentFullhash, result)
  60. else:
  61. result = parseInt(module[2])
  62. if currentFullhash == module[1]:
  63. # not changed, so use the cached AST:
  64. doAssert(result != 0)
  65. var cycleCheck = initIntSet()
  66. if not needsRecompile(g, fileIdx, fullpath, cycleCheck) and not g.incr.configChanged:
  67. echo "cached successfully! ", string fullpath
  68. return -result
  69. db.exec(sql"update modules set fullHash = ? where id = ?", currentFullhash, module[0])
  70. db.exec(sql"delete from deps where module = ?", module[0])
  71. db.exec(sql"delete from types where module = ?", module[0])
  72. db.exec(sql"delete from syms where module = ?", module[0])
  73. db.exec(sql"delete from toplevelstmts where module = ?", module[0])
  74. db.exec(sql"delete from statics where module = ?", module[0])
  75. proc pushType(w: var Writer, t: PType) =
  76. if not containsOrIncl(w.tmarks, t.id):
  77. w.tstack.add(t)
  78. proc pushSym(w: var Writer, s: PSym) =
  79. if not containsOrIncl(w.smarks, s.id):
  80. w.sstack.add(s)
  81. template w: untyped = g.incr.w
  82. proc encodeNode(g: ModuleGraph; fInfo: TLineInfo, n: PNode,
  83. result: var string) =
  84. if n == nil:
  85. # nil nodes have to be stored too:
  86. result.add("()")
  87. return
  88. result.add('(')
  89. encodeVInt(ord(n.kind), result)
  90. # we do not write comments for now
  91. # Line information takes easily 20% or more of the filesize! Therefore we
  92. # omit line information if it is the same as the parent's line information:
  93. if fInfo.fileIndex != n.info.fileIndex:
  94. result.add('?')
  95. encodeVInt(n.info.col, result)
  96. result.add(',')
  97. encodeVInt(int n.info.line, result)
  98. result.add(',')
  99. encodeVInt(toDbFileId(g.incr, g.config, n.info.fileIndex), result)
  100. elif fInfo.line != n.info.line:
  101. result.add('?')
  102. encodeVInt(n.info.col, result)
  103. result.add(',')
  104. encodeVInt(int n.info.line, result)
  105. elif fInfo.col != n.info.col:
  106. result.add('?')
  107. encodeVInt(n.info.col, result)
  108. # No need to output the file index, as this is the serialization of one
  109. # file.
  110. let f = n.flags * PersistentNodeFlags
  111. if f != {}:
  112. result.add('$')
  113. encodeVInt(cast[int32](f), result)
  114. if n.typ != nil:
  115. result.add('^')
  116. encodeVInt(n.typ.id, result)
  117. pushType(w, n.typ)
  118. case n.kind
  119. of nkCharLit..nkUInt64Lit:
  120. if n.intVal != 0:
  121. result.add('!')
  122. encodeVBiggestInt(n.intVal, result)
  123. of nkFloatLit..nkFloat64Lit:
  124. if n.floatVal != 0.0:
  125. result.add('!')
  126. encodeStr($n.floatVal, result)
  127. of nkStrLit..nkTripleStrLit:
  128. if n.strVal != "":
  129. result.add('!')
  130. encodeStr(n.strVal, result)
  131. of nkIdent:
  132. result.add('!')
  133. encodeStr(n.ident.s, result)
  134. of nkSym:
  135. result.add('!')
  136. encodeVInt(n.sym.id, result)
  137. pushSym(w, n.sym)
  138. else:
  139. for i in countup(0, sonsLen(n) - 1):
  140. encodeNode(g, n.info, n.sons[i], result)
  141. add(result, ')')
  142. proc encodeLoc(g: ModuleGraph; loc: TLoc, result: var string) =
  143. var oldLen = result.len
  144. result.add('<')
  145. if loc.k != low(loc.k): encodeVInt(ord(loc.k), result)
  146. if loc.storage != low(loc.storage):
  147. add(result, '*')
  148. encodeVInt(ord(loc.storage), result)
  149. if loc.flags != {}:
  150. add(result, '$')
  151. encodeVInt(cast[int32](loc.flags), result)
  152. if loc.lode != nil:
  153. add(result, '^')
  154. encodeNode(g, unknownLineInfo(), loc.lode, result)
  155. if loc.r != nil:
  156. add(result, '!')
  157. encodeStr($loc.r, result)
  158. if oldLen + 1 == result.len:
  159. # no data was necessary, so remove the '<' again:
  160. setLen(result, oldLen)
  161. else:
  162. add(result, '>')
  163. proc encodeType(g: ModuleGraph, t: PType, result: var string) =
  164. if t == nil:
  165. # nil nodes have to be stored too:
  166. result.add("[]")
  167. return
  168. # we need no surrounding [] here because the type is in a line of its own
  169. if t.kind == tyForward: internalError(g.config, "encodeType: tyForward")
  170. # for the new rodfile viewer we use a preceding [ so that the data section
  171. # can easily be disambiguated:
  172. add(result, '[')
  173. encodeVInt(ord(t.kind), result)
  174. add(result, '+')
  175. encodeVInt(t.id, result)
  176. if t.n != nil:
  177. encodeNode(g, unknownLineInfo(), t.n, result)
  178. if t.flags != {}:
  179. add(result, '$')
  180. encodeVInt(cast[int32](t.flags), result)
  181. if t.callConv != low(t.callConv):
  182. add(result, '?')
  183. encodeVInt(ord(t.callConv), result)
  184. if t.owner != nil:
  185. add(result, '*')
  186. encodeVInt(t.owner.id, result)
  187. pushSym(w, t.owner)
  188. if t.sym != nil:
  189. add(result, '&')
  190. encodeVInt(t.sym.id, result)
  191. pushSym(w, t.sym)
  192. if t.size != - 1:
  193. add(result, '/')
  194. encodeVBiggestInt(t.size, result)
  195. if t.align != 2:
  196. add(result, '=')
  197. encodeVInt(t.align, result)
  198. if t.lockLevel.ord != UnspecifiedLockLevel.ord:
  199. add(result, '\14')
  200. encodeVInt(t.lockLevel.int16, result)
  201. if t.destructor != nil and t.destructor.id != 0:
  202. add(result, '\15')
  203. encodeVInt(t.destructor.id, result)
  204. pushSym(w, t.destructor)
  205. if t.deepCopy != nil:
  206. add(result, '\16')
  207. encodeVInt(t.deepcopy.id, result)
  208. pushSym(w, t.deepcopy)
  209. if t.assignment != nil:
  210. add(result, '\17')
  211. encodeVInt(t.assignment.id, result)
  212. pushSym(w, t.assignment)
  213. if t.sink != nil:
  214. add(result, '\18')
  215. encodeVInt(t.sink.id, result)
  216. pushSym(w, t.sink)
  217. for i, s in items(t.methods):
  218. add(result, '\19')
  219. encodeVInt(i, result)
  220. add(result, '\20')
  221. encodeVInt(s.id, result)
  222. pushSym(w, s)
  223. encodeLoc(g, t.loc, result)
  224. for i in countup(0, sonsLen(t) - 1):
  225. if t.sons[i] == nil:
  226. add(result, "^()")
  227. else:
  228. add(result, '^')
  229. encodeVInt(t.sons[i].id, result)
  230. pushType(w, t.sons[i])
  231. proc encodeLib(g: ModuleGraph, lib: PLib, info: TLineInfo, result: var string) =
  232. add(result, '|')
  233. encodeVInt(ord(lib.kind), result)
  234. add(result, '|')
  235. encodeStr($lib.name, result)
  236. add(result, '|')
  237. encodeNode(g, info, lib.path, result)
  238. proc encodeInstantiations(g: ModuleGraph; s: seq[PInstantiation];
  239. result: var string) =
  240. for t in s:
  241. result.add('\15')
  242. encodeVInt(t.sym.id, result)
  243. pushSym(w, t.sym)
  244. for tt in t.concreteTypes:
  245. result.add('\17')
  246. encodeVInt(tt.id, result)
  247. pushType(w, tt)
  248. result.add('\20')
  249. encodeVInt(t.compilesId, result)
  250. proc encodeSym(g: ModuleGraph, s: PSym, result: var string) =
  251. if s == nil:
  252. # nil nodes have to be stored too:
  253. result.add("{}")
  254. return
  255. # we need no surrounding {} here because the symbol is in a line of its own
  256. encodeVInt(ord(s.kind), result)
  257. result.add('+')
  258. encodeVInt(s.id, result)
  259. result.add('&')
  260. encodeStr(s.name.s, result)
  261. if s.typ != nil:
  262. result.add('^')
  263. encodeVInt(s.typ.id, result)
  264. pushType(w, s.typ)
  265. result.add('?')
  266. if s.info.col != -1'i16: encodeVInt(s.info.col, result)
  267. result.add(',')
  268. encodeVInt(int s.info.line, result)
  269. result.add(',')
  270. encodeVInt(toDbFileId(g.incr, g.config, s.info.fileIndex), result)
  271. if s.owner != nil:
  272. result.add('*')
  273. encodeVInt(s.owner.id, result)
  274. pushSym(w, s.owner)
  275. if s.flags != {}:
  276. result.add('$')
  277. encodeVInt(cast[int32](s.flags), result)
  278. if s.magic != mNone:
  279. result.add('@')
  280. encodeVInt(ord(s.magic), result)
  281. result.add('!')
  282. encodeVInt(cast[int32](s.options), result)
  283. if s.position != 0:
  284. result.add('%')
  285. encodeVInt(s.position, result)
  286. if s.offset != - 1:
  287. result.add('`')
  288. encodeVInt(s.offset, result)
  289. encodeLoc(g, s.loc, result)
  290. if s.annex != nil: encodeLib(g, s.annex, s.info, result)
  291. if s.constraint != nil:
  292. add(result, '#')
  293. encodeNode(g, unknownLineInfo(), s.constraint, result)
  294. case s.kind
  295. of skType, skGenericParam:
  296. for t in s.typeInstCache:
  297. result.add('\14')
  298. encodeVInt(t.id, result)
  299. pushType(w, t)
  300. of routineKinds:
  301. encodeInstantiations(g, s.procInstCache, result)
  302. if s.gcUnsafetyReason != nil:
  303. result.add('\16')
  304. encodeVInt(s.gcUnsafetyReason.id, result)
  305. pushSym(w, s.gcUnsafetyReason)
  306. of skModule, skPackage:
  307. encodeInstantiations(g, s.usedGenerics, result)
  308. # we don't serialize:
  309. #tab*: TStrTable # interface table for modules
  310. of skLet, skVar, skField, skForVar:
  311. if s.guard != nil:
  312. result.add('\18')
  313. encodeVInt(s.guard.id, result)
  314. pushSym(w, s.guard)
  315. if s.bitsize != 0:
  316. result.add('\19')
  317. encodeVInt(s.bitsize, result)
  318. else: discard
  319. # lazy loading will soon reload the ast lazily, so the ast needs to be
  320. # the last entry of a symbol:
  321. if s.ast != nil:
  322. # we used to attempt to save space here by only storing a dummy AST if
  323. # it is not necessary, but Nim's heavy compile-time evaluation features
  324. # make that unfeasible nowadays:
  325. encodeNode(g, s.info, s.ast, result)
  326. proc storeSym(g: ModuleGraph; s: PSym) =
  327. if sfForward in s.flags and s.kind != skModule:
  328. w.forwardedSyms.add s
  329. return
  330. var buf = newStringOfCap(160)
  331. encodeSym(g, s, buf)
  332. # XXX only store the name for exported symbols in order to speed up lookup
  333. # times once we enable the skStub logic.
  334. let m = getModule(s)
  335. let mid = if m == nil: 0 else: abs(m.id)
  336. db.exec(sql"insert into syms(nimid, module, name, data, exported) values (?, ?, ?, ?, ?)",
  337. s.id, mid, s.name.s, buf, ord(sfExported in s.flags))
  338. proc storeType(g: ModuleGraph; t: PType) =
  339. var buf = newStringOfCap(160)
  340. encodeType(g, t, buf)
  341. let m = if t.owner != nil: getModule(t.owner) else: nil
  342. let mid = if m == nil: 0 else: abs(m.id)
  343. db.exec(sql"insert into types(nimid, module, data) values (?, ?, ?)",
  344. t.id, mid, buf)
  345. proc storeNode*(g: ModuleGraph; module: PSym; n: PNode) =
  346. if g.config.symbolFiles == disabledSf: return
  347. var buf = newStringOfCap(160)
  348. encodeNode(g, module.info, n, buf)
  349. db.exec(sql"insert into toplevelstmts(module, position, data) values (?, ?, ?)",
  350. abs(module.id), module.offset, buf)
  351. inc module.offset
  352. var i = 0
  353. while true:
  354. if i > 10_000:
  355. doAssert false, "loop never ends!"
  356. if w.sstack.len > 0:
  357. let s = w.sstack.pop()
  358. when false:
  359. echo "popped ", s.name.s, " ", s.id
  360. storeSym(g, s)
  361. elif w.tstack.len > 0:
  362. let t = w.tstack.pop()
  363. storeType(g, t)
  364. when false:
  365. echo "popped type ", typeToString(t), " ", t.id
  366. else:
  367. break
  368. inc i
  369. proc recordStmt*(g: ModuleGraph; module: PSym; n: PNode) =
  370. storeNode(g, module, n)
  371. proc storeRemaining*(g: ModuleGraph; module: PSym) =
  372. if g.config.symbolFiles == disabledSf: return
  373. var stillForwarded: seq[PSym] = @[]
  374. for s in w.forwardedSyms:
  375. if sfForward notin s.flags:
  376. storeSym(g, s)
  377. else:
  378. stillForwarded.add s
  379. swap w.forwardedSyms, stillForwarded
  380. # ---------------- decoder -----------------------------------
  381. type
  382. BlobReader = object
  383. s: string
  384. pos: int
  385. using
  386. b: var BlobReader
  387. g: ModuleGraph
  388. proc loadSym(g; id: int, info: TLineInfo): PSym
  389. proc loadType(g; id: int, info: TLineInfo): PType
  390. proc decodeLineInfo(g; b; info: var TLineInfo) =
  391. if b.s[b.pos] == '?':
  392. inc(b.pos)
  393. if b.s[b.pos] == ',': info.col = -1'i16
  394. else: info.col = int16(decodeVInt(b.s, b.pos))
  395. if b.s[b.pos] == ',':
  396. inc(b.pos)
  397. if b.s[b.pos] == ',': info.line = 0'u16
  398. else: info.line = uint16(decodeVInt(b.s, b.pos))
  399. if b.s[b.pos] == ',':
  400. inc(b.pos)
  401. info.fileIndex = fromDbFileId(g.incr, g.config, decodeVInt(b.s, b.pos))
  402. proc skipNode(b) =
  403. assert b.s[b.pos] == '('
  404. var par = 0
  405. var pos = b.pos+1
  406. while true:
  407. case b.s[pos]
  408. of ')':
  409. if par == 0: break
  410. dec par
  411. of '(': inc par
  412. else: discard
  413. inc pos
  414. b.pos = pos+1 # skip ')'
  415. proc decodeNodeLazyBody(g; b; fInfo: TLineInfo,
  416. belongsTo: PSym): PNode =
  417. result = nil
  418. if b.s[b.pos] == '(':
  419. inc(b.pos)
  420. if b.s[b.pos] == ')':
  421. inc(b.pos)
  422. return # nil node
  423. result = newNodeI(TNodeKind(decodeVInt(b.s, b.pos)), fInfo)
  424. decodeLineInfo(g, b, result.info)
  425. if b.s[b.pos] == '$':
  426. inc(b.pos)
  427. result.flags = cast[TNodeFlags](int32(decodeVInt(b.s, b.pos)))
  428. if b.s[b.pos] == '^':
  429. inc(b.pos)
  430. var id = decodeVInt(b.s, b.pos)
  431. result.typ = loadType(g, id, result.info)
  432. case result.kind
  433. of nkCharLit..nkUInt64Lit:
  434. if b.s[b.pos] == '!':
  435. inc(b.pos)
  436. result.intVal = decodeVBiggestInt(b.s, b.pos)
  437. of nkFloatLit..nkFloat64Lit:
  438. if b.s[b.pos] == '!':
  439. inc(b.pos)
  440. var fl = decodeStr(b.s, b.pos)
  441. result.floatVal = parseFloat(fl)
  442. of nkStrLit..nkTripleStrLit:
  443. if b.s[b.pos] == '!':
  444. inc(b.pos)
  445. result.strVal = decodeStr(b.s, b.pos)
  446. else:
  447. result.strVal = ""
  448. of nkIdent:
  449. if b.s[b.pos] == '!':
  450. inc(b.pos)
  451. var fl = decodeStr(b.s, b.pos)
  452. result.ident = g.cache.getIdent(fl)
  453. else:
  454. internalError(g.config, result.info, "decodeNode: nkIdent")
  455. of nkSym:
  456. if b.s[b.pos] == '!':
  457. inc(b.pos)
  458. var id = decodeVInt(b.s, b.pos)
  459. result.sym = loadSym(g, id, result.info)
  460. else:
  461. internalError(g.config, result.info, "decodeNode: nkSym")
  462. else:
  463. var i = 0
  464. while b.s[b.pos] != ')':
  465. when false:
  466. if belongsTo != nil and i == bodyPos:
  467. addSonNilAllowed(result, nil)
  468. belongsTo.offset = b.pos
  469. skipNode(b)
  470. else:
  471. discard
  472. addSonNilAllowed(result, decodeNodeLazyBody(g, b, result.info, nil))
  473. inc i
  474. if b.s[b.pos] == ')': inc(b.pos)
  475. else: internalError(g.config, result.info, "decodeNode: ')' missing")
  476. else:
  477. internalError(g.config, fInfo, "decodeNode: '(' missing " & $b.pos)
  478. proc decodeNode(g; b; fInfo: TLineInfo): PNode =
  479. result = decodeNodeLazyBody(g, b, fInfo, nil)
  480. proc decodeLoc(g; b; loc: var TLoc, info: TLineInfo) =
  481. if b.s[b.pos] == '<':
  482. inc(b.pos)
  483. if b.s[b.pos] in {'0'..'9', 'a'..'z', 'A'..'Z'}:
  484. loc.k = TLocKind(decodeVInt(b.s, b.pos))
  485. else:
  486. loc.k = low(loc.k)
  487. if b.s[b.pos] == '*':
  488. inc(b.pos)
  489. loc.storage = TStorageLoc(decodeVInt(b.s, b.pos))
  490. else:
  491. loc.storage = low(loc.storage)
  492. if b.s[b.pos] == '$':
  493. inc(b.pos)
  494. loc.flags = cast[TLocFlags](int32(decodeVInt(b.s, b.pos)))
  495. else:
  496. loc.flags = {}
  497. if b.s[b.pos] == '^':
  498. inc(b.pos)
  499. loc.lode = decodeNode(g, b, info)
  500. # rrGetType(b, decodeVInt(b.s, b.pos), info)
  501. else:
  502. loc.lode = nil
  503. if b.s[b.pos] == '!':
  504. inc(b.pos)
  505. loc.r = rope(decodeStr(b.s, b.pos))
  506. else:
  507. loc.r = nil
  508. if b.s[b.pos] == '>': inc(b.pos)
  509. else: internalError(g.config, info, "decodeLoc " & b.s[b.pos])
  510. proc loadBlob(g; query: SqlQuery; id: int): BlobReader =
  511. let blob = db.getValue(query, id)
  512. if blob.len == 0:
  513. internalError(g.config, "symbolfiles: cannot find ID " & $ id)
  514. result = BlobReader(pos: 0)
  515. shallowCopy(result.s, blob)
  516. # ensure we can read without index checks:
  517. result.s.add '\0'
  518. proc loadType(g; id: int; info: TLineInfo): PType =
  519. result = g.incr.r.types.getOrDefault(id)
  520. if result != nil: return result
  521. var b = loadBlob(g, sql"select data from types where nimid = ?", id)
  522. if b.s[b.pos] == '[':
  523. inc(b.pos)
  524. if b.s[b.pos] == ']':
  525. inc(b.pos)
  526. return # nil type
  527. new(result)
  528. result.kind = TTypeKind(decodeVInt(b.s, b.pos))
  529. if b.s[b.pos] == '+':
  530. inc(b.pos)
  531. result.id = decodeVInt(b.s, b.pos)
  532. setId(result.id)
  533. #if debugIds: registerID(result)
  534. else:
  535. internalError(g.config, info, "decodeType: no id")
  536. # here this also avoids endless recursion for recursive type
  537. g.incr.r.types.add(result.id, result)
  538. if b.s[b.pos] == '(': result.n = decodeNode(g, b, unknownLineInfo())
  539. if b.s[b.pos] == '$':
  540. inc(b.pos)
  541. result.flags = cast[TTypeFlags](int32(decodeVInt(b.s, b.pos)))
  542. if b.s[b.pos] == '?':
  543. inc(b.pos)
  544. result.callConv = TCallingConvention(decodeVInt(b.s, b.pos))
  545. if b.s[b.pos] == '*':
  546. inc(b.pos)
  547. result.owner = loadSym(g, decodeVInt(b.s, b.pos), info)
  548. if b.s[b.pos] == '&':
  549. inc(b.pos)
  550. result.sym = loadSym(g, decodeVInt(b.s, b.pos), info)
  551. if b.s[b.pos] == '/':
  552. inc(b.pos)
  553. result.size = decodeVInt(b.s, b.pos)
  554. else:
  555. result.size = -1
  556. if b.s[b.pos] == '=':
  557. inc(b.pos)
  558. result.align = decodeVInt(b.s, b.pos).int16
  559. else:
  560. result.align = 2
  561. if b.s[b.pos] == '\14':
  562. inc(b.pos)
  563. result.lockLevel = decodeVInt(b.s, b.pos).TLockLevel
  564. else:
  565. result.lockLevel = UnspecifiedLockLevel
  566. if b.s[b.pos] == '\15':
  567. inc(b.pos)
  568. result.destructor = loadSym(g, decodeVInt(b.s, b.pos), info)
  569. if b.s[b.pos] == '\16':
  570. inc(b.pos)
  571. result.deepCopy = loadSym(g, decodeVInt(b.s, b.pos), info)
  572. if b.s[b.pos] == '\17':
  573. inc(b.pos)
  574. result.assignment = loadSym(g, decodeVInt(b.s, b.pos), info)
  575. if b.s[b.pos] == '\18':
  576. inc(b.pos)
  577. result.sink = loadSym(g, decodeVInt(b.s, b.pos), info)
  578. while b.s[b.pos] == '\19':
  579. inc(b.pos)
  580. let x = decodeVInt(b.s, b.pos)
  581. doAssert b.s[b.pos] == '\20'
  582. inc(b.pos)
  583. let y = loadSym(g, decodeVInt(b.s, b.pos), info)
  584. result.methods.add((x, y))
  585. decodeLoc(g, b, result.loc, info)
  586. while b.s[b.pos] == '^':
  587. inc(b.pos)
  588. if b.s[b.pos] == '(':
  589. inc(b.pos)
  590. if b.s[b.pos] == ')': inc(b.pos)
  591. else: internalError(g.config, info, "decodeType ^(" & b.s[b.pos])
  592. rawAddSon(result, nil)
  593. else:
  594. let d = decodeVInt(b.s, b.pos)
  595. rawAddSon(result, loadType(g, d, info))
  596. proc decodeLib(g; b; info: TLineInfo): PLib =
  597. result = nil
  598. if b.s[b.pos] == '|':
  599. new(result)
  600. inc(b.pos)
  601. result.kind = TLibKind(decodeVInt(b.s, b.pos))
  602. if b.s[b.pos] != '|': internalError(g.config, "decodeLib: 1")
  603. inc(b.pos)
  604. result.name = rope(decodeStr(b.s, b.pos))
  605. if b.s[b.pos] != '|': internalError(g.config, "decodeLib: 2")
  606. inc(b.pos)
  607. result.path = decodeNode(g, b, info)
  608. proc decodeInstantiations(g; b; info: TLineInfo;
  609. s: var seq[PInstantiation]) =
  610. while b.s[b.pos] == '\15':
  611. inc(b.pos)
  612. var ii: PInstantiation
  613. new ii
  614. ii.sym = loadSym(g, decodeVInt(b.s, b.pos), info)
  615. ii.concreteTypes = @[]
  616. while b.s[b.pos] == '\17':
  617. inc(b.pos)
  618. ii.concreteTypes.add loadType(g, decodeVInt(b.s, b.pos), info)
  619. if b.s[b.pos] == '\20':
  620. inc(b.pos)
  621. ii.compilesId = decodeVInt(b.s, b.pos)
  622. s.add ii
  623. proc loadSymFromBlob(g; b; info: TLineInfo): PSym =
  624. if b.s[b.pos] == '{':
  625. inc(b.pos)
  626. if b.s[b.pos] == '}':
  627. inc(b.pos)
  628. return # nil sym
  629. var k = TSymKind(decodeVInt(b.s, b.pos))
  630. var id: int
  631. if b.s[b.pos] == '+':
  632. inc(b.pos)
  633. id = decodeVInt(b.s, b.pos)
  634. setId(id)
  635. else:
  636. internalError(g.config, info, "decodeSym: no id")
  637. var ident: PIdent
  638. if b.s[b.pos] == '&':
  639. inc(b.pos)
  640. ident = g.cache.getIdent(decodeStr(b.s, b.pos))
  641. else:
  642. internalError(g.config, info, "decodeSym: no ident")
  643. #echo "decoding: {", ident.s
  644. new(result)
  645. result.id = id
  646. result.kind = k
  647. result.name = ident # read the rest of the symbol description:
  648. g.incr.r.syms.add(result.id, result)
  649. if b.s[b.pos] == '^':
  650. inc(b.pos)
  651. result.typ = loadType(g, decodeVInt(b.s, b.pos), info)
  652. decodeLineInfo(g, b, result.info)
  653. if b.s[b.pos] == '*':
  654. inc(b.pos)
  655. result.owner = loadSym(g, decodeVInt(b.s, b.pos), result.info)
  656. if b.s[b.pos] == '$':
  657. inc(b.pos)
  658. result.flags = cast[TSymFlags](int32(decodeVInt(b.s, b.pos)))
  659. if b.s[b.pos] == '@':
  660. inc(b.pos)
  661. result.magic = TMagic(decodeVInt(b.s, b.pos))
  662. if b.s[b.pos] == '!':
  663. inc(b.pos)
  664. result.options = cast[TOptions](int32(decodeVInt(b.s, b.pos)))
  665. if b.s[b.pos] == '%':
  666. inc(b.pos)
  667. result.position = decodeVInt(b.s, b.pos)
  668. if b.s[b.pos] == '`':
  669. inc(b.pos)
  670. result.offset = decodeVInt(b.s, b.pos)
  671. else:
  672. result.offset = -1
  673. decodeLoc(g, b, result.loc, result.info)
  674. result.annex = decodeLib(g, b, info)
  675. if b.s[b.pos] == '#':
  676. inc(b.pos)
  677. result.constraint = decodeNode(g, b, unknownLineInfo())
  678. case result.kind
  679. of skType, skGenericParam:
  680. while b.s[b.pos] == '\14':
  681. inc(b.pos)
  682. result.typeInstCache.add loadType(g, decodeVInt(b.s, b.pos), result.info)
  683. of routineKinds:
  684. decodeInstantiations(g, b, result.info, result.procInstCache)
  685. if b.s[b.pos] == '\16':
  686. inc(b.pos)
  687. result.gcUnsafetyReason = loadSym(g, decodeVInt(b.s, b.pos), result.info)
  688. of skModule, skPackage:
  689. decodeInstantiations(g, b, result.info, result.usedGenerics)
  690. of skLet, skVar, skField, skForVar:
  691. if b.s[b.pos] == '\18':
  692. inc(b.pos)
  693. result.guard = loadSym(g, decodeVInt(b.s, b.pos), result.info)
  694. if b.s[b.pos] == '\19':
  695. inc(b.pos)
  696. result.bitsize = decodeVInt(b.s, b.pos).int16
  697. else: discard
  698. if b.s[b.pos] == '(':
  699. #if result.kind in routineKinds:
  700. # result.ast = decodeNodeLazyBody(b, result.info, result)
  701. #else:
  702. result.ast = decodeNode(g, b, result.info)
  703. if sfCompilerProc in result.flags:
  704. registerCompilerProc(g, result)
  705. #echo "loading ", result.name.s
  706. proc loadSym(g; id: int; info: TLineInfo): PSym =
  707. result = g.incr.r.syms.getOrDefault(id)
  708. if result != nil: return result
  709. var b = loadBlob(g, sql"select data from syms where nimid = ?", id)
  710. result = loadSymFromBlob(g, b, info)
  711. doAssert id == result.id, "symbol ID is not consistent!"
  712. proc loadModuleSymTab(g; module: PSym) =
  713. ## goal: fill module.tab
  714. g.incr.r.syms.add(module.id, module)
  715. for row in db.fastRows(sql"select nimid, data from syms where module = ? and exported = 1", abs(module.id)):
  716. let id = parseInt(row[0])
  717. var s = g.incr.r.syms.getOrDefault(id)
  718. if s == nil:
  719. var b = BlobReader(pos: 0)
  720. shallowCopy(b.s, row[1])
  721. # ensure we can read without index checks:
  722. b.s.add '\0'
  723. s = loadSymFromBlob(g, b, module.info)
  724. assert s != nil
  725. strTableAdd(module.tab, s)
  726. if sfSystemModule in module.flags:
  727. g.systemModule = module
  728. proc replay(g: ModuleGraph; module: PSym; n: PNode) =
  729. # XXX check if we need to replay nkStaticStmt here.
  730. case n.kind
  731. #of nkStaticStmt:
  732. #evalStaticStmt(module, g, n[0], module)
  733. #of nkVarSection, nkLetSection:
  734. # nkVarSections are already covered by the vmgen which produces nkStaticStmt
  735. of nkMethodDef:
  736. methodDef(g, n[namePos].sym, fromCache=true)
  737. of nkCommentStmt:
  738. # pragmas are complex and can be user-overriden via templates. So
  739. # instead of using the original ``nkPragma`` nodes, we rely on the
  740. # fact that pragmas.nim was patched to produce specialized recorded
  741. # statements for us in the form of ``nkCommentStmt`` with (key, value)
  742. # pairs. Ordinary nkCommentStmt nodes never have children so this is
  743. # not ambiguous.
  744. # Fortunately only a tiny subset of the available pragmas need to
  745. # be replayed here. This is always a subset of ``pragmas.stmtPragmas``.
  746. if n.len >= 2:
  747. internalAssert g.config, n[0].kind == nkStrLit and n[1].kind == nkStrLit
  748. case n[0].strVal
  749. of "hint": message(g.config, n.info, hintUser, n[1].strVal)
  750. of "warning": message(g.config, n.info, warnUser, n[1].strVal)
  751. of "error": localError(g.config, n.info, errUser, n[1].strVal)
  752. of "compile":
  753. internalAssert g.config, n.len == 3 and n[2].kind == nkStrLit
  754. var cf = Cfile(cname: AbsoluteFile n[1].strVal, obj: AbsoluteFile n[2].strVal,
  755. flags: {CfileFlag.External})
  756. extccomp.addExternalFileToCompile(g.config, cf)
  757. of "link":
  758. extccomp.addExternalFileToLink(g.config, AbsoluteFile n[1].strVal)
  759. of "passl":
  760. extccomp.addLinkOption(g.config, n[1].strVal)
  761. of "passc":
  762. extccomp.addCompileOption(g.config, n[1].strVal)
  763. of "cppdefine":
  764. options.cppDefine(g.config, n[1].strVal)
  765. of "inc":
  766. let destKey = n[1].strVal
  767. let by = n[2].intVal
  768. let v = getOrDefault(g.cacheCounters, destKey)
  769. g.cacheCounters[destKey] = v+by
  770. of "put":
  771. let destKey = n[1].strVal
  772. let key = n[2].strVal
  773. let val = n[3]
  774. if not contains(g.cacheTables, destKey):
  775. g.cacheTables[destKey] = initBTree[string, PNode]()
  776. if not contains(g.cacheTables[destKey], key):
  777. g.cacheTables[destKey].add(key, val)
  778. else:
  779. internalError(g.config, n.info, "key already exists: " & key)
  780. of "incl":
  781. let destKey = n[1].strVal
  782. let val = n[2]
  783. if not contains(g.cacheSeqs, destKey):
  784. g.cacheSeqs[destKey] = newTree(nkStmtList, val)
  785. else:
  786. block search:
  787. for existing in g.cacheSeqs[destKey]:
  788. if exprStructuralEquivalent(existing, val, strictSymEquality=true):
  789. break search
  790. g.cacheSeqs[destKey].add val
  791. of "add":
  792. let destKey = n[1].strVal
  793. let val = n[2]
  794. if not contains(g.cacheSeqs, destKey):
  795. g.cacheSeqs[destKey] = newTree(nkStmtList, val)
  796. else:
  797. g.cacheSeqs[destKey].add val
  798. else:
  799. internalAssert g.config, false
  800. of nkImportStmt:
  801. for x in n:
  802. internalAssert g.config, x.kind == nkStrLit
  803. let imported = g.importModuleCallback(g, module, fileInfoIdx(g.config, AbsoluteFile n[0].strVal))
  804. internalAssert g.config, imported.id < 0
  805. of nkStmtList, nkStmtListExpr:
  806. for x in n: replay(g, module, x)
  807. else: discard "nothing to do for this node"
  808. proc loadNode*(g: ModuleGraph; module: PSym): PNode =
  809. loadModuleSymTab(g, module)
  810. result = newNodeI(nkStmtList, module.info)
  811. for row in db.rows(sql"select data from toplevelstmts where module = ? order by position asc",
  812. abs module.id):
  813. var b = BlobReader(pos: 0)
  814. # ensure we can read without index checks:
  815. b.s = row[0] & '\0'
  816. result.add decodeNode(g, b, module.info)
  817. db.exec(sql"insert into controlblock(idgen) values (?)", gFrontEndId)
  818. replay(g, module, result)
  819. proc setupModuleCache*(g: ModuleGraph) =
  820. if g.config.symbolFiles == disabledSf: return
  821. g.recordStmt = recordStmt
  822. let dbfile = getNimcacheDir(g.config) / RelativeFile"rodfiles.db"
  823. if g.config.symbolFiles == writeOnlySf:
  824. removeFile(dbfile)
  825. if not fileExists(dbfile):
  826. db = open(connection=string dbfile, user="nim", password="",
  827. database="nim")
  828. createDb(db)
  829. db.exec(sql"insert into config(config) values (?)", encodeConfig(g))
  830. else:
  831. db = open(connection=string dbfile, user="nim", password="",
  832. database="nim")
  833. let oldConfig = db.getValue(sql"select config from config")
  834. g.incr.configChanged = oldConfig != encodeConfig(g)
  835. db.exec(sql"pragma journal_mode=off")
  836. # This MUST be turned off, otherwise it's way too slow even for testing purposes:
  837. db.exec(sql"pragma SYNCHRONOUS=off")
  838. db.exec(sql"pragma LOCKING_MODE=exclusive")
  839. let lastId = db.getValue(sql"select max(idgen) from controlblock")
  840. if lastId.len > 0:
  841. idgen.setId(parseInt lastId)