ic.nim 48 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2020 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. import std/[hashes, tables, intsets, monotimes]
  10. import packed_ast, bitabs, rodfiles
  11. import ".." / [ast, idents, lineinfos, msgs, ropes, options,
  12. pathutils, condsyms, packages, modulepaths]
  13. #import ".." / [renderer, astalgo]
  14. from std/os import removeFile, isAbsolute
  15. import ../../dist/checksums/src/checksums/sha1
  16. import iclineinfos
  17. when defined(nimPreviewSlimSystem):
  18. import std/[syncio, assertions, formatfloat]
  19. type
  20. PackedConfig* = object
  21. backend: TBackend
  22. selectedGC: TGCMode
  23. cCompiler: TSystemCC
  24. options: TOptions
  25. globalOptions: TGlobalOptions
  26. ModuleBackendFlag* = enum
  27. HasDatInitProc
  28. HasModuleInitProc
  29. PackedModule* = object ## the parts of a PackedEncoder that are part of the .rod file
  30. definedSymbols: string
  31. moduleFlags: TSymFlags
  32. includes*: seq[(LitId, string)] # first entry is the module filename itself
  33. imports: seq[LitId] # the modules this module depends on
  34. toReplay*: PackedTree # pragmas and VM specific state to replay.
  35. topLevel*: PackedTree # top level statements
  36. bodies*: PackedTree # other trees. Referenced from typ.n and sym.ast by their position.
  37. #producedGenerics*: Table[GenericKey, SymId]
  38. exports*: seq[(LitId, int32)]
  39. hidden: seq[(LitId, int32)]
  40. reexports: seq[(LitId, PackedItemId)]
  41. compilerProcs*: seq[(LitId, int32)]
  42. converters*, methods*, trmacros*, pureEnums*: seq[int32]
  43. typeInstCache*: seq[(PackedItemId, PackedItemId)]
  44. procInstCache*: seq[PackedInstantiation]
  45. attachedOps*: seq[(PackedItemId, TTypeAttachedOp, PackedItemId)]
  46. methodsPerGenericType*: seq[(PackedItemId, int, PackedItemId)]
  47. enumToStringProcs*: seq[(PackedItemId, PackedItemId)]
  48. methodsPerType*: seq[(PackedItemId, PackedItemId)]
  49. dispatchers*: seq[PackedItemId]
  50. emittedTypeInfo*: seq[string]
  51. backendFlags*: set[ModuleBackendFlag]
  52. syms*: OrderedTable[int32, PackedSym]
  53. types*: OrderedTable[int32, PackedType]
  54. strings*: BiTable[string] # we could share these between modules.
  55. numbers*: BiTable[BiggestInt] # we also store floats in here so
  56. # that we can assure that every bit is kept
  57. man*: LineInfoManager
  58. cfg: PackedConfig
  59. PackedEncoder* = object
  60. #m*: PackedModule
  61. thisModule*: int32
  62. lastFile*: FileIndex # remember the last lookup entry.
  63. lastLit*: LitId
  64. filenames*: Table[FileIndex, LitId]
  65. pendingTypes*: seq[PType]
  66. pendingSyms*: seq[PSym]
  67. typeMarker*: IntSet #Table[ItemId, TypeId] # ItemId.item -> TypeId
  68. symMarker*: IntSet #Table[ItemId, SymId] # ItemId.item -> SymId
  69. config*: ConfigRef
  70. proc toString*(tree: PackedTree; pos: NodePos; m: PackedModule; nesting: int;
  71. result: var string) =
  72. if result.len > 0 and result[^1] notin {' ', '\n'}:
  73. result.add ' '
  74. result.add $tree[pos].kind
  75. case tree[pos].kind
  76. of nkEmpty, nkNilLit, nkType: discard
  77. of nkIdent, nkStrLit..nkTripleStrLit:
  78. result.add " "
  79. result.add m.strings[LitId tree[pos].uoperand]
  80. of nkSym:
  81. result.add " "
  82. result.add m.strings[m.syms[tree[pos].soperand].name]
  83. of directIntLit:
  84. result.add " "
  85. result.addInt tree[pos].soperand
  86. of externSIntLit:
  87. result.add " "
  88. result.addInt m.numbers[LitId tree[pos].uoperand]
  89. of externUIntLit:
  90. result.add " "
  91. result.addInt cast[uint64](m.numbers[LitId tree[pos].uoperand])
  92. of nkFloatLit..nkFloat128Lit:
  93. result.add " "
  94. result.addFloat cast[BiggestFloat](m.numbers[LitId tree[pos].uoperand])
  95. else:
  96. result.add "(\n"
  97. for i in 1..(nesting+1)*2: result.add ' '
  98. for child in sonsReadonly(tree, pos):
  99. toString(tree, child, m, nesting + 1, result)
  100. result.add "\n"
  101. for i in 1..nesting*2: result.add ' '
  102. result.add ")"
  103. #for i in 1..nesting*2: result.add ' '
  104. proc toString*(tree: PackedTree; n: NodePos; m: PackedModule): string =
  105. result = ""
  106. toString(tree, n, m, 0, result)
  107. proc debug*(tree: PackedTree; m: PackedModule) =
  108. stdout.write toString(tree, NodePos 0, m)
  109. proc isActive*(e: PackedEncoder): bool = e.config != nil
  110. proc disable(e: var PackedEncoder) = e.config = nil
  111. template primConfigFields(fn: untyped) {.dirty.} =
  112. fn backend
  113. fn selectedGC
  114. fn cCompiler
  115. fn options
  116. fn globalOptions
  117. proc definedSymbolsAsString(config: ConfigRef): string =
  118. result = newStringOfCap(200)
  119. result.add "config"
  120. for d in definedSymbolNames(config.symbols):
  121. result.add ' '
  122. result.add d
  123. proc rememberConfig(c: var PackedEncoder; m: var PackedModule; config: ConfigRef; pc: PackedConfig) =
  124. m.definedSymbols = definedSymbolsAsString(config)
  125. #template rem(x) =
  126. # c.m.cfg.x = config.x
  127. #primConfigFields rem
  128. m.cfg = pc
  129. const
  130. debugConfigDiff = defined(debugConfigDiff)
  131. when debugConfigDiff:
  132. import hashes, tables, intsets, sha1, strutils, sets
  133. proc configIdentical(m: PackedModule; config: ConfigRef): bool =
  134. result = m.definedSymbols == definedSymbolsAsString(config)
  135. when debugConfigDiff:
  136. if not result:
  137. var wordsA = m.definedSymbols.split(Whitespace).toHashSet()
  138. var wordsB = definedSymbolsAsString(config).split(Whitespace).toHashSet()
  139. for c in wordsA - wordsB:
  140. echo "in A but not in B ", c
  141. for c in wordsB - wordsA:
  142. echo "in B but not in A ", c
  143. template eq(x) =
  144. result = result and m.cfg.x == config.x
  145. when debugConfigDiff:
  146. if m.cfg.x != config.x:
  147. echo "B ", m.cfg.x, " ", config.x
  148. primConfigFields eq
  149. proc rememberStartupConfig*(dest: var PackedConfig, config: ConfigRef) =
  150. template rem(x) =
  151. dest.x = config.x
  152. primConfigFields rem
  153. dest.globalOptions.excl optForceFullMake
  154. proc hashFileCached(conf: ConfigRef; fileIdx: FileIndex): string =
  155. result = msgs.getHash(conf, fileIdx)
  156. if result.len == 0:
  157. let fullpath = msgs.toFullPath(conf, fileIdx)
  158. result = $secureHashFile(fullpath)
  159. msgs.setHash(conf, fileIdx, result)
  160. proc toLitId(x: FileIndex; c: var PackedEncoder; m: var PackedModule): LitId =
  161. ## store a file index as a literal
  162. if x == c.lastFile:
  163. result = c.lastLit
  164. else:
  165. result = c.filenames.getOrDefault(x)
  166. if result == LitId(0):
  167. let p = msgs.toFullPath(c.config, x)
  168. result = getOrIncl(m.strings, p)
  169. c.filenames[x] = result
  170. c.lastFile = x
  171. c.lastLit = result
  172. assert result != LitId(0)
  173. proc toFileIndex*(x: LitId; m: PackedModule; config: ConfigRef): FileIndex =
  174. result = msgs.fileInfoIdx(config, AbsoluteFile m.strings[x])
  175. proc includesIdentical(m: var PackedModule; config: ConfigRef): bool =
  176. for it in mitems(m.includes):
  177. if hashFileCached(config, toFileIndex(it[0], m, config)) != it[1]:
  178. return false
  179. result = true
  180. proc initEncoder*(c: var PackedEncoder; m: var PackedModule; moduleSym: PSym; config: ConfigRef; pc: PackedConfig) =
  181. ## setup a context for serializing to packed ast
  182. c.thisModule = moduleSym.itemId.module
  183. c.config = config
  184. m.moduleFlags = moduleSym.flags
  185. m.bodies = newTreeFrom(m.topLevel)
  186. m.toReplay = newTreeFrom(m.topLevel)
  187. c.lastFile = FileIndex(-10)
  188. let thisNimFile = FileIndex c.thisModule
  189. var h = msgs.getHash(config, thisNimFile)
  190. if h.len == 0:
  191. let fullpath = msgs.toFullPath(config, thisNimFile)
  192. if isAbsolute(fullpath):
  193. # For NimScript compiler API support the main Nim file might be from a stream.
  194. h = $secureHashFile(fullpath)
  195. msgs.setHash(config, thisNimFile, h)
  196. m.includes.add((toLitId(thisNimFile, c, m), h)) # the module itself
  197. rememberConfig(c, m, config, pc)
  198. proc addIncludeFileDep*(c: var PackedEncoder; m: var PackedModule; f: FileIndex) =
  199. m.includes.add((toLitId(f, c, m), hashFileCached(c.config, f)))
  200. proc addImportFileDep*(c: var PackedEncoder; m: var PackedModule; f: FileIndex) =
  201. m.imports.add toLitId(f, c, m)
  202. proc addHidden*(c: var PackedEncoder; m: var PackedModule; s: PSym) =
  203. assert s.kind != skUnknown
  204. let nameId = getOrIncl(m.strings, s.name.s)
  205. m.hidden.add((nameId, s.itemId.item))
  206. assert s.itemId.module == c.thisModule
  207. proc addExported*(c: var PackedEncoder; m: var PackedModule; s: PSym) =
  208. assert s.kind != skUnknown
  209. assert s.itemId.module == c.thisModule
  210. let nameId = getOrIncl(m.strings, s.name.s)
  211. m.exports.add((nameId, s.itemId.item))
  212. proc addConverter*(c: var PackedEncoder; m: var PackedModule; s: PSym) =
  213. assert c.thisModule == s.itemId.module
  214. m.converters.add(s.itemId.item)
  215. proc addTrmacro*(c: var PackedEncoder; m: var PackedModule; s: PSym) =
  216. m.trmacros.add(s.itemId.item)
  217. proc addPureEnum*(c: var PackedEncoder; m: var PackedModule; s: PSym) =
  218. assert s.kind == skType
  219. m.pureEnums.add(s.itemId.item)
  220. proc addMethod*(c: var PackedEncoder; m: var PackedModule; s: PSym) =
  221. m.methods.add s.itemId.item
  222. proc addReexport*(c: var PackedEncoder; m: var PackedModule; s: PSym) =
  223. assert s.kind != skUnknown
  224. if s.kind == skModule: return
  225. let nameId = getOrIncl(m.strings, s.name.s)
  226. m.reexports.add((nameId, PackedItemId(module: toLitId(s.itemId.module.FileIndex, c, m),
  227. item: s.itemId.item)))
  228. proc addCompilerProc*(c: var PackedEncoder; m: var PackedModule; s: PSym) =
  229. let nameId = getOrIncl(m.strings, s.name.s)
  230. m.compilerProcs.add((nameId, s.itemId.item))
  231. proc toPackedNode*(n: PNode; ir: var PackedTree; c: var PackedEncoder; m: var PackedModule)
  232. proc storeSym*(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId
  233. proc storeType(t: PType; c: var PackedEncoder; m: var PackedModule): PackedItemId
  234. proc flush(c: var PackedEncoder; m: var PackedModule) =
  235. ## serialize any pending types or symbols from the context
  236. while true:
  237. if c.pendingTypes.len > 0:
  238. discard storeType(c.pendingTypes.pop, c, m)
  239. elif c.pendingSyms.len > 0:
  240. discard storeSym(c.pendingSyms.pop, c, m)
  241. else:
  242. break
  243. proc toLitId(x: string; m: var PackedModule): LitId =
  244. ## store a string as a literal
  245. result = getOrIncl(m.strings, x)
  246. proc toLitId(x: BiggestInt; m: var PackedModule): LitId =
  247. ## store an integer as a literal
  248. result = getOrIncl(m.numbers, x)
  249. proc toPackedInfo(x: TLineInfo; c: var PackedEncoder; m: var PackedModule): PackedLineInfo =
  250. pack(m.man, toLitId(x.fileIndex, c, m), x.line.int32, x.col.int32)
  251. #PackedLineInfo(line: x.line, col: x.col, file: toLitId(x.fileIndex, c, m))
  252. proc safeItemId(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId {.inline.} =
  253. ## given a symbol, produce an ItemId with the correct properties
  254. ## for local or remote symbols, packing the symbol as necessary
  255. if s == nil or s.kind == skPackage:
  256. result = nilItemId
  257. #elif s.itemId.module == c.thisModule:
  258. # result = PackedItemId(module: LitId(0), item: s.itemId.item)
  259. else:
  260. assert int(s.itemId.module) >= 0
  261. result = PackedItemId(module: toLitId(s.itemId.module.FileIndex, c, m),
  262. item: s.itemId.item)
  263. proc addMissing(c: var PackedEncoder; p: PSym) =
  264. ## consider queuing a symbol for later addition to the packed tree
  265. if p != nil and p.itemId.module == c.thisModule:
  266. if p.itemId.item notin c.symMarker:
  267. if not (sfForward in p.flags and p.kind in routineKinds):
  268. c.pendingSyms.add p
  269. proc addMissing(c: var PackedEncoder; p: PType) =
  270. ## consider queuing a type for later addition to the packed tree
  271. if p != nil and p.uniqueId.module == c.thisModule:
  272. if p.uniqueId.item notin c.typeMarker:
  273. c.pendingTypes.add p
  274. template storeNode(dest, src, field) =
  275. var nodeId: NodeId
  276. if src.field != nil:
  277. nodeId = getNodeId(m.bodies)
  278. toPackedNode(src.field, m.bodies, c, m)
  279. else:
  280. nodeId = emptyNodeId
  281. dest.field = nodeId
  282. proc storeTypeLater(t: PType; c: var PackedEncoder; m: var PackedModule): PackedItemId =
  283. # We store multiple different trees in m.bodies. For this to work out, we
  284. # cannot immediately store types/syms. We enqueue them instead to ensure
  285. # we only write one tree into m.bodies after the other.
  286. if t.isNil: return nilItemId
  287. assert t.uniqueId.module >= 0
  288. assert t.uniqueId.item > 0
  289. result = PackedItemId(module: toLitId(t.uniqueId.module.FileIndex, c, m), item: t.uniqueId.item)
  290. if t.uniqueId.module == c.thisModule:
  291. # the type belongs to this module, so serialize it here, eventually.
  292. addMissing(c, t)
  293. proc storeSymLater(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId =
  294. if s.isNil: return nilItemId
  295. assert s.itemId.module >= 0
  296. assert s.itemId.item >= 0
  297. result = PackedItemId(module: toLitId(s.itemId.module.FileIndex, c, m), item: s.itemId.item)
  298. if s.itemId.module == c.thisModule:
  299. # the sym belongs to this module, so serialize it here, eventually.
  300. addMissing(c, s)
  301. proc storeType(t: PType; c: var PackedEncoder; m: var PackedModule): PackedItemId =
  302. ## serialize a ptype
  303. if t.isNil: return nilItemId
  304. assert t.uniqueId.module >= 0
  305. assert t.uniqueId.item > 0
  306. result = PackedItemId(module: toLitId(t.uniqueId.module.FileIndex, c, m), item: t.uniqueId.item)
  307. if t.uniqueId.module == c.thisModule and not c.typeMarker.containsOrIncl(t.uniqueId.item):
  308. #if t.uniqueId.item >= m.types.len:
  309. # setLen m.types, t.uniqueId.item+1
  310. var p = PackedType(id: t.uniqueId.item, kind: t.kind, flags: t.flags, callConv: t.callConv,
  311. size: t.size, align: t.align, nonUniqueId: t.itemId.item,
  312. paddingAtEnd: t.paddingAtEnd)
  313. storeNode(p, t, n)
  314. p.typeInst = t.typeInst.storeType(c, m)
  315. for kid in kids t:
  316. p.types.add kid.storeType(c, m)
  317. c.addMissing t.sym
  318. p.sym = t.sym.safeItemId(c, m)
  319. c.addMissing t.owner
  320. p.owner = t.owner.safeItemId(c, m)
  321. # fill the reserved slot, nothing else:
  322. m.types[t.uniqueId.item] = p
  323. proc toPackedLib(l: PLib; c: var PackedEncoder; m: var PackedModule): PackedLib =
  324. ## the plib hangs off the psym via the .annex field
  325. if l.isNil: return
  326. result = PackedLib(kind: l.kind, generated: l.generated,
  327. isOverridden: l.isOverridden, name: toLitId($l.name, m)
  328. )
  329. storeNode(result, l, path)
  330. proc storeSym*(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId =
  331. ## serialize a psym
  332. if s.isNil: return nilItemId
  333. assert s.itemId.module >= 0
  334. result = PackedItemId(module: toLitId(s.itemId.module.FileIndex, c, m), item: s.itemId.item)
  335. if s.itemId.module == c.thisModule and not c.symMarker.containsOrIncl(s.itemId.item):
  336. #if s.itemId.item >= m.syms.len:
  337. # setLen m.syms, s.itemId.item+1
  338. assert sfForward notin s.flags
  339. var p = PackedSym(id: s.itemId.item, kind: s.kind, flags: s.flags, info: s.info.toPackedInfo(c, m), magic: s.magic,
  340. position: s.position, offset: s.offset, disamb: s.disamb, options: s.options,
  341. name: s.name.s.toLitId(m))
  342. storeNode(p, s, ast)
  343. storeNode(p, s, constraint)
  344. if s.kind in {skLet, skVar, skField, skForVar}:
  345. c.addMissing s.guard
  346. p.guard = s.guard.safeItemId(c, m)
  347. p.bitsize = s.bitsize
  348. p.alignment = s.alignment
  349. p.externalName = toLitId(s.loc.snippet, m)
  350. p.locFlags = s.loc.flags
  351. c.addMissing s.typ
  352. p.typ = s.typ.storeType(c, m)
  353. c.addMissing s.owner
  354. p.owner = s.owner.safeItemId(c, m)
  355. p.annex = toPackedLib(s.annex, c, m)
  356. when hasFFI:
  357. p.cname = toLitId(s.cname, m)
  358. p.instantiatedFrom = s.instantiatedFrom.safeItemId(c, m)
  359. # fill the reserved slot, nothing else:
  360. m.syms[s.itemId.item] = p
  361. proc addModuleRef(n: PNode; ir: var PackedTree; c: var PackedEncoder; m: var PackedModule) =
  362. ## add a remote symbol reference to the tree
  363. let info = n.info.toPackedInfo(c, m)
  364. if n.typ != n.sym.typ:
  365. ir.addNode(kind = nkModuleRef, operand = 3.int32, # spans 3 nodes in total
  366. info = info, flags = n.flags,
  367. typeId = storeTypeLater(n.typ, c, m))
  368. else:
  369. ir.addNode(kind = nkModuleRef, operand = 3.int32, # spans 3 nodes in total
  370. info = info, flags = n.flags)
  371. ir.addNode(kind = nkNone, info = info,
  372. operand = toLitId(n.sym.itemId.module.FileIndex, c, m).int32)
  373. ir.addNode(kind = nkNone, info = info,
  374. operand = n.sym.itemId.item)
  375. proc toPackedNode*(n: PNode; ir: var PackedTree; c: var PackedEncoder; m: var PackedModule) =
  376. ## serialize a node into the tree
  377. if n == nil:
  378. ir.addNode(kind = nkNilRodNode, operand = 1, info = NoLineInfo)
  379. return
  380. let info = toPackedInfo(n.info, c, m)
  381. case n.kind
  382. of nkNone, nkEmpty, nkNilLit, nkType:
  383. ir.addNode(kind = n.kind, flags = n.flags, operand = 0,
  384. typeId = storeTypeLater(n.typ, c, m), info = info)
  385. of nkIdent:
  386. ir.addNode(kind = n.kind, flags = n.flags,
  387. operand = int32 getOrIncl(m.strings, n.ident.s),
  388. typeId = storeTypeLater(n.typ, c, m), info = info)
  389. of nkSym:
  390. if n.sym.itemId.module == c.thisModule:
  391. # it is a symbol that belongs to the module we're currently
  392. # packing:
  393. let id = n.sym.storeSymLater(c, m).item
  394. if n.typ != n.sym.typ:
  395. ir.addNode(kind = nkSym, flags = n.flags, operand = id,
  396. info = info,
  397. typeId = storeTypeLater(n.typ, c, m))
  398. else:
  399. ir.addNode(kind = nkSym, flags = n.flags, operand = id,
  400. info = info)
  401. else:
  402. # store it as an external module reference:
  403. addModuleRef(n, ir, c, m)
  404. of externIntLit:
  405. ir.addNode(kind = n.kind, flags = n.flags,
  406. operand = int32 getOrIncl(m.numbers, n.intVal),
  407. typeId = storeTypeLater(n.typ, c, m), info = info)
  408. of nkStrLit..nkTripleStrLit:
  409. ir.addNode(kind = n.kind, flags = n.flags,
  410. operand = int32 getOrIncl(m.strings, n.strVal),
  411. typeId = storeTypeLater(n.typ, c, m), info = info)
  412. of nkFloatLit..nkFloat128Lit:
  413. ir.addNode(kind = n.kind, flags = n.flags,
  414. operand = int32 getOrIncl(m.numbers, cast[BiggestInt](n.floatVal)),
  415. typeId = storeTypeLater(n.typ, c, m), info = info)
  416. else:
  417. let patchPos = ir.prepare(n.kind, n.flags,
  418. storeTypeLater(n.typ, c, m), info)
  419. for i in 0..<n.len:
  420. toPackedNode(n[i], ir, c, m)
  421. ir.patch patchPos
  422. proc storeTypeInst*(c: var PackedEncoder; m: var PackedModule; s: PSym; inst: PType) =
  423. m.typeInstCache.add (storeSymLater(s, c, m), storeTypeLater(inst, c, m))
  424. proc addPragmaComputation*(c: var PackedEncoder; m: var PackedModule; n: PNode) =
  425. toPackedNode(n, m.toReplay, c, m)
  426. proc toPackedProcDef(n: PNode; ir: var PackedTree; c: var PackedEncoder; m: var PackedModule) =
  427. let info = toPackedInfo(n.info, c, m)
  428. let patchPos = ir.prepare(n.kind, n.flags,
  429. storeTypeLater(n.typ, c, m), info)
  430. for i in 0..<n.len:
  431. if i != bodyPos:
  432. toPackedNode(n[i], ir, c, m)
  433. else:
  434. # do not serialize the body of the proc, it's unnecessary since
  435. # n[0].sym.ast has the sem'checked variant of it which is what
  436. # everybody should use instead.
  437. ir.addNode(kind = nkEmpty, flags = {}, operand = 0,
  438. typeId = nilItemId, info = info)
  439. ir.patch patchPos
  440. proc toPackedNodeIgnoreProcDefs(n: PNode, encoder: var PackedEncoder; m: var PackedModule) =
  441. case n.kind
  442. of routineDefs:
  443. toPackedProcDef(n, m.topLevel, encoder, m)
  444. when false:
  445. # we serialize n[namePos].sym instead
  446. if n[namePos].kind == nkSym:
  447. let s = n[namePos].sym
  448. discard storeSym(s, encoder, m)
  449. if s.flags * {sfExportc, sfCompilerProc, sfCompileTime} == {sfExportc}:
  450. m.exportCProcs.add(s.itemId.item)
  451. else:
  452. toPackedNode(n, m.topLevel, encoder, m)
  453. of nkStmtList, nkStmtListExpr:
  454. for it in n:
  455. toPackedNodeIgnoreProcDefs(it, encoder, m)
  456. of nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt,
  457. nkFromStmt, nkIncludeStmt:
  458. discard "nothing to do"
  459. else:
  460. toPackedNode(n, m.topLevel, encoder, m)
  461. proc toPackedNodeTopLevel*(n: PNode, encoder: var PackedEncoder; m: var PackedModule) =
  462. toPackedNodeIgnoreProcDefs(n, encoder, m)
  463. flush encoder, m
  464. proc toPackedGeneratedProcDef*(s: PSym, encoder: var PackedEncoder; m: var PackedModule) =
  465. ## Generic procs and generated `=hook`'s need explicit top-level entries so
  466. ## that the code generator can work without having to special case these. These
  467. ## entries will also be useful for other tools and are the cleanest design
  468. ## I can come up with.
  469. assert s.kind in routineKinds
  470. toPackedProcDef(s.ast, m.topLevel, encoder, m)
  471. #flush encoder, m
  472. proc storeAttachedProcDef*(t: PType; op: TTypeAttachedOp; s: PSym,
  473. encoder: var PackedEncoder; m: var PackedModule) =
  474. assert s.kind in routineKinds
  475. assert isActive(encoder)
  476. let tid = storeTypeLater(t, encoder, m)
  477. let sid = storeSymLater(s, encoder, m)
  478. m.attachedOps.add (tid, op, sid)
  479. toPackedGeneratedProcDef(s, encoder, m)
  480. proc storeInstantiation*(c: var PackedEncoder; m: var PackedModule; s: PSym; i: PInstantiation) =
  481. var t = newSeq[PackedItemId](i.concreteTypes.len)
  482. for j in 0..high(i.concreteTypes):
  483. t[j] = storeTypeLater(i.concreteTypes[j], c, m)
  484. m.procInstCache.add PackedInstantiation(key: storeSymLater(s, c, m),
  485. sym: storeSymLater(i.sym, c, m),
  486. concreteTypes: t)
  487. toPackedGeneratedProcDef(i.sym, c, m)
  488. proc storeExpansion*(c: var PackedEncoder; m: var PackedModule; info: TLineInfo; s: PSym) =
  489. toPackedNode(newSymNode(s, info), m.bodies, c, m)
  490. proc loadError(err: RodFileError; filename: AbsoluteFile; config: ConfigRef;) =
  491. case err
  492. of cannotOpen:
  493. rawMessage(config, warnCannotOpenFile, filename.string)
  494. of includeFileChanged:
  495. rawMessage(config, warnFileChanged, filename.string)
  496. else:
  497. rawMessage(config, warnCannotOpenFile, filename.string & " reason: " & $err)
  498. #echo "Error: ", $err, " loading file: ", filename.string
  499. proc toRodFile*(conf: ConfigRef; f: AbsoluteFile; ext = RodExt): AbsoluteFile =
  500. result = changeFileExt(completeGeneratedFilePath(conf,
  501. mangleModuleName(conf, f).AbsoluteFile), ext)
  502. const
  503. BenchIC* = false
  504. when BenchIC:
  505. var gloadBodies: MonoTime
  506. template bench(x, body) =
  507. let start = getMonoTime()
  508. body
  509. x = x + (getMonoTime() - start)
  510. else:
  511. template bench(x, body) = body
  512. proc loadRodFile*(filename: AbsoluteFile; m: var PackedModule; config: ConfigRef;
  513. ignoreConfig = false): RodFileError =
  514. var f = rodfiles.open(filename.string)
  515. f.loadHeader()
  516. f.loadSection configSection
  517. f.loadPrim m.definedSymbols
  518. f.loadPrim m.moduleFlags
  519. f.loadPrim m.cfg
  520. if f.err == ok and not configIdentical(m, config) and not ignoreConfig:
  521. f.err = configMismatch
  522. template loadSeqSection(section, data) {.dirty.} =
  523. f.loadSection section
  524. f.loadSeq data
  525. template loadTableSection(section, data) {.dirty.} =
  526. f.loadSection section
  527. f.loadOrderedTable data
  528. template loadTabSection(section, data) {.dirty.} =
  529. f.loadSection section
  530. f.load data
  531. loadTabSection stringsSection, m.strings
  532. loadSeqSection checkSumsSection, m.includes
  533. if config.cmd != cmdM and not includesIdentical(m, config):
  534. f.err = includeFileChanged
  535. loadSeqSection depsSection, m.imports
  536. bench gloadBodies:
  537. loadTabSection numbersSection, m.numbers
  538. loadSeqSection exportsSection, m.exports
  539. loadSeqSection hiddenSection, m.hidden
  540. loadSeqSection reexportsSection, m.reexports
  541. loadSeqSection compilerProcsSection, m.compilerProcs
  542. loadSeqSection trmacrosSection, m.trmacros
  543. loadSeqSection convertersSection, m.converters
  544. loadSeqSection methodsSection, m.methods
  545. loadSeqSection pureEnumsSection, m.pureEnums
  546. loadTabSection toReplaySection, m.toReplay
  547. loadTabSection topLevelSection, m.topLevel
  548. loadTabSection bodiesSection, m.bodies
  549. loadTableSection symsSection, m.syms
  550. loadTableSection typesSection, m.types
  551. loadSeqSection typeInstCacheSection, m.typeInstCache
  552. loadSeqSection procInstCacheSection, m.procInstCache
  553. loadSeqSection attachedOpsSection, m.attachedOps
  554. loadSeqSection methodsPerGenericTypeSection, m.methodsPerGenericType
  555. loadSeqSection enumToStringProcsSection, m.enumToStringProcs
  556. loadSeqSection methodsPerTypeSection, m.methodsPerType
  557. loadSeqSection dispatchersSection, m.dispatchers
  558. loadSeqSection typeInfoSection, m.emittedTypeInfo
  559. f.loadSection backendFlagsSection
  560. f.loadPrim m.backendFlags
  561. f.loadSection sideChannelSection
  562. f.load m.man
  563. close(f)
  564. result = f.err
  565. # -------------------------------------------------------------------------
  566. proc storeError(err: RodFileError; filename: AbsoluteFile) =
  567. echo "Error: ", $err, "; couldn't write to ", filename.string
  568. removeFile(filename.string)
  569. proc saveRodFile*(filename: AbsoluteFile; encoder: var PackedEncoder; m: var PackedModule) =
  570. flush encoder, m
  571. #rememberConfig(encoder, encoder.config)
  572. var f = rodfiles.create(filename.string)
  573. f.storeHeader()
  574. f.storeSection configSection
  575. f.storePrim m.definedSymbols
  576. f.storePrim m.moduleFlags
  577. f.storePrim m.cfg
  578. template storeSeqSection(section, data) {.dirty.} =
  579. f.storeSection section
  580. f.storeSeq data
  581. template storeTabSection(section, data) {.dirty.} =
  582. f.storeSection section
  583. f.store data
  584. template storeTableSection(section, data) {.dirty.} =
  585. f.storeSection section
  586. f.storeOrderedTable data
  587. storeTabSection stringsSection, m.strings
  588. storeSeqSection checkSumsSection, m.includes
  589. storeSeqSection depsSection, m.imports
  590. storeTabSection numbersSection, m.numbers
  591. storeSeqSection exportsSection, m.exports
  592. storeSeqSection hiddenSection, m.hidden
  593. storeSeqSection reexportsSection, m.reexports
  594. storeSeqSection compilerProcsSection, m.compilerProcs
  595. storeSeqSection trmacrosSection, m.trmacros
  596. storeSeqSection convertersSection, m.converters
  597. storeSeqSection methodsSection, m.methods
  598. storeSeqSection pureEnumsSection, m.pureEnums
  599. storeTabSection toReplaySection, m.toReplay
  600. storeTabSection topLevelSection, m.topLevel
  601. storeTabSection bodiesSection, m.bodies
  602. storeTableSection symsSection, m.syms
  603. storeTableSection typesSection, m.types
  604. storeSeqSection typeInstCacheSection, m.typeInstCache
  605. storeSeqSection procInstCacheSection, m.procInstCache
  606. storeSeqSection attachedOpsSection, m.attachedOps
  607. storeSeqSection methodsPerGenericTypeSection, m.methodsPerGenericType
  608. storeSeqSection enumToStringProcsSection, m.enumToStringProcs
  609. storeSeqSection methodsPerTypeSection, m.methodsPerType
  610. storeSeqSection dispatchersSection, m.dispatchers
  611. storeSeqSection typeInfoSection, m.emittedTypeInfo
  612. f.storeSection backendFlagsSection
  613. f.storePrim m.backendFlags
  614. f.storeSection sideChannelSection
  615. f.store m.man
  616. close(f)
  617. encoder.disable()
  618. if f.err != ok:
  619. storeError(f.err, filename)
  620. when false:
  621. # basic loader testing:
  622. var m2: PackedModule
  623. discard loadRodFile(filename, m2, encoder.config)
  624. echo "loaded ", filename.string
  625. # ----------------------------------------------------------------------------
  626. type
  627. PackedDecoder* = object
  628. lastModule: int
  629. lastLit: LitId
  630. lastFile: FileIndex # remember the last lookup entry.
  631. config*: ConfigRef
  632. cache*: IdentCache
  633. type
  634. ModuleStatus* = enum
  635. undefined,
  636. storing, # state is strictly for stress-testing purposes
  637. loading,
  638. loaded,
  639. outdated,
  640. stored # store is complete, no further additions possible
  641. LoadedModule* = object
  642. status*: ModuleStatus
  643. symsInit, typesInit, loadedButAliveSetChanged*: bool
  644. fromDisk*: PackedModule
  645. syms: OrderedTable[int32, PSym] # indexed by itemId
  646. types: OrderedTable[int32, PType]
  647. module*: PSym # the one true module symbol.
  648. iface, ifaceHidden: Table[PIdent, seq[PackedItemId]]
  649. # PackedItemId so that it works with reexported symbols too
  650. # ifaceHidden includes private symbols
  651. type
  652. PackedModuleGraph* = object
  653. pm*: seq[LoadedModule] # indexed by FileIndex
  654. when BenchIC:
  655. depAnalysis: MonoTime
  656. loadBody: MonoTime
  657. loadSym, loadType, loadBodies: MonoTime
  658. when BenchIC:
  659. proc echoTimes*(m: PackedModuleGraph) =
  660. echo "analysis: ", m.depAnalysis, " loadBody: ", m.loadBody, " loadSym: ",
  661. m.loadSym, " loadType: ", m.loadType, " all bodies: ", gloadBodies
  662. template `[]`*(m: PackedModuleGraph; i: int): LoadedModule = m.pm[i]
  663. template len*(m: PackedModuleGraph): int = m.pm.len
  664. proc loadType(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; t: PackedItemId): PType
  665. proc loadSym(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; s: PackedItemId): PSym
  666. proc toFileIndexCached*(c: var PackedDecoder; g: PackedModuleGraph; thisModule: int; f: LitId): FileIndex =
  667. if f == LitId(0):
  668. result = InvalidFileIdx
  669. elif c.lastLit == f and c.lastModule == thisModule:
  670. result = c.lastFile
  671. else:
  672. result = toFileIndex(f, g[thisModule].fromDisk, c.config)
  673. c.lastModule = thisModule
  674. c.lastLit = f
  675. c.lastFile = result
  676. proc translateLineInfo(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int;
  677. x: PackedLineInfo): TLineInfo =
  678. assert g[thisModule].status in {loaded, storing, stored}
  679. let (fileId, line, col) = unpack(g[thisModule].fromDisk.man, x)
  680. result = TLineInfo(line: line.uint16, col: col.int16,
  681. fileIndex: toFileIndexCached(c, g, thisModule, fileId))
  682. proc loadNodes*(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int;
  683. tree: PackedTree; n: NodePos): PNode =
  684. let k = n.kind
  685. if k == nkNilRodNode:
  686. return nil
  687. when false:
  688. echo "loading node ", c.config $ translateLineInfo(c, g, thisModule, n.info)
  689. result = newNodeIT(k, translateLineInfo(c, g, thisModule, n.info),
  690. loadType(c, g, thisModule, n.typ))
  691. result.flags = n.flags
  692. case k
  693. of nkNone, nkEmpty, nkNilLit, nkType:
  694. discard
  695. of nkIdent:
  696. result.ident = getIdent(c.cache, g[thisModule].fromDisk.strings[n.litId])
  697. of nkSym:
  698. result.sym = loadSym(c, g, thisModule, PackedItemId(module: LitId(0), item: tree[n].soperand))
  699. if result.typ == nil:
  700. result.typ = result.sym.typ
  701. of externIntLit:
  702. result.intVal = g[thisModule].fromDisk.numbers[n.litId]
  703. of nkStrLit..nkTripleStrLit:
  704. result.strVal = g[thisModule].fromDisk.strings[n.litId]
  705. of nkFloatLit..nkFloat128Lit:
  706. result.floatVal = cast[BiggestFloat](g[thisModule].fromDisk.numbers[n.litId])
  707. of nkModuleRef:
  708. let (n1, n2) = sons2(tree, n)
  709. assert n1.kind == nkNone
  710. assert n2.kind == nkNone
  711. transitionNoneToSym(result)
  712. result.sym = loadSym(c, g, thisModule, PackedItemId(module: n1.litId, item: tree[n2].soperand))
  713. if result.typ == nil:
  714. result.typ = result.sym.typ
  715. else:
  716. for n0 in sonsReadonly(tree, n):
  717. result.addAllowNil loadNodes(c, g, thisModule, tree, n0)
  718. proc initPackedDecoder*(config: ConfigRef; cache: IdentCache): PackedDecoder =
  719. result = PackedDecoder(
  720. lastModule: int32(-1),
  721. lastLit: LitId(0),
  722. lastFile: FileIndex(-1),
  723. config: config,
  724. cache: cache)
  725. proc loadProcHeader(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int;
  726. tree: PackedTree; n: NodePos): PNode =
  727. # do not load the body of the proc. This will be done later in
  728. # getProcBody, if required.
  729. let k = n.kind
  730. result = newNodeIT(k, translateLineInfo(c, g, thisModule, n.info),
  731. loadType(c, g, thisModule, n.typ))
  732. result.flags = n.flags
  733. assert k in {nkProcDef, nkMethodDef, nkIteratorDef, nkFuncDef, nkConverterDef, nkLambda}
  734. var i = 0
  735. for n0 in sonsReadonly(tree, n):
  736. if i != bodyPos:
  737. result.add loadNodes(c, g, thisModule, tree, n0)
  738. else:
  739. result.addAllowNil nil
  740. inc i
  741. proc loadProcBody(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int;
  742. tree: PackedTree; n: NodePos): PNode =
  743. result = nil
  744. var i = 0
  745. for n0 in sonsReadonly(tree, n):
  746. if i == bodyPos:
  747. result = loadNodes(c, g, thisModule, tree, n0)
  748. inc i
  749. proc moduleIndex*(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int;
  750. s: PackedItemId): int32 {.inline.} =
  751. result = if s.module == LitId(0): thisModule.int32
  752. else: toFileIndexCached(c, g, thisModule, s.module).int32
  753. proc symHeaderFromPacked(c: var PackedDecoder; g: var PackedModuleGraph;
  754. s: PackedSym; si, item: int32): PSym =
  755. result = PSym(itemId: ItemId(module: si, item: item),
  756. kind: s.kind, magic: s.magic, flags: s.flags,
  757. info: translateLineInfo(c, g, si, s.info),
  758. options: s.options,
  759. position: if s.kind in {skForVar, skVar, skLet, skTemp}: 0 else: s.position,
  760. offset: if s.kind in routineKinds: defaultOffset else: s.offset,
  761. disamb: s.disamb,
  762. name: getIdent(c.cache, g[si].fromDisk.strings[s.name])
  763. )
  764. template loadAstBody(p, field) =
  765. if p.field != emptyNodeId:
  766. result.field = loadNodes(c, g, si, g[si].fromDisk.bodies, NodePos p.field)
  767. template loadAstBodyLazy(p, field) =
  768. if p.field != emptyNodeId:
  769. result.field = loadProcHeader(c, g, si, g[si].fromDisk.bodies, NodePos p.field)
  770. proc loadLib(c: var PackedDecoder; g: var PackedModuleGraph;
  771. si, item: int32; l: PackedLib): PLib =
  772. # XXX: hack; assume a zero LitId means the PackedLib is all zero (empty)
  773. if l.name.int == 0:
  774. result = nil
  775. else:
  776. result = PLib(generated: l.generated, isOverridden: l.isOverridden,
  777. kind: l.kind, name: rope g[si].fromDisk.strings[l.name])
  778. loadAstBody(l, path)
  779. proc symBodyFromPacked(c: var PackedDecoder; g: var PackedModuleGraph;
  780. s: PackedSym; si, item: int32; result: PSym) =
  781. result.typ = loadType(c, g, si, s.typ)
  782. loadAstBody(s, constraint)
  783. if result.kind in {skProc, skFunc, skIterator, skConverter, skMethod}:
  784. loadAstBodyLazy(s, ast)
  785. else:
  786. loadAstBody(s, ast)
  787. result.annex = loadLib(c, g, si, item, s.annex)
  788. when hasFFI:
  789. result.cname = g[si].fromDisk.strings[s.cname]
  790. if s.kind in {skLet, skVar, skField, skForVar}:
  791. result.guard = loadSym(c, g, si, s.guard)
  792. result.bitsize = s.bitsize
  793. result.alignment = s.alignment
  794. result.owner = loadSym(c, g, si, s.owner)
  795. let externalName = g[si].fromDisk.strings[s.externalName]
  796. if externalName != "":
  797. result.loc.snippet = externalName
  798. result.loc.flags = s.locFlags
  799. result.instantiatedFrom = loadSym(c, g, si, s.instantiatedFrom)
  800. proc needsRecompile(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache;
  801. fileIdx: FileIndex; cachedModules: var seq[FileIndex]): bool
  802. proc loadToReplayNodes(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache;
  803. fileIdx: FileIndex; m: var LoadedModule)
  804. proc loadSym(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; s: PackedItemId): PSym =
  805. if s == nilItemId:
  806. result = nil
  807. else:
  808. let si = moduleIndex(c, g, thisModule, s)
  809. if si >= g.len:
  810. g.pm.setLen(si+1)
  811. if g[si].status == undefined and c.config.cmd == cmdM:
  812. var cachedModules: seq[FileIndex] = @[]
  813. discard needsRecompile(g, c.config, c.cache, FileIndex(si), cachedModules)
  814. for m in cachedModules:
  815. loadToReplayNodes(g, c.config, c.cache, m, g[int m])
  816. assert g[si].status in {loaded, storing, stored}
  817. #if not g[si].symsInit:
  818. # g[si].symsInit = true
  819. # setLen g[si].syms, g[si].fromDisk.syms.len
  820. if g[si].syms.getOrDefault(s.item) == nil:
  821. if g[si].fromDisk.syms[s.item].kind != skModule:
  822. result = symHeaderFromPacked(c, g, g[si].fromDisk.syms[s.item], si, s.item)
  823. # store it here early on, so that recursions work properly:
  824. g[si].syms[s.item] = result
  825. symBodyFromPacked(c, g, g[si].fromDisk.syms[s.item], si, s.item, result)
  826. else:
  827. result = g[si].module
  828. assert result != nil
  829. g[si].syms[s.item] = result
  830. else:
  831. result = g[si].syms[s.item]
  832. proc typeHeaderFromPacked(c: var PackedDecoder; g: var PackedModuleGraph;
  833. t: PackedType; si, item: int32): PType =
  834. result = PType(itemId: ItemId(module: si, item: t.nonUniqueId), kind: t.kind,
  835. flags: t.flags, size: t.size, align: t.align,
  836. paddingAtEnd: t.paddingAtEnd,
  837. uniqueId: ItemId(module: si, item: item),
  838. callConv: t.callConv)
  839. proc typeBodyFromPacked(c: var PackedDecoder; g: var PackedModuleGraph;
  840. t: PackedType; si, item: int32; result: PType) =
  841. result.sym = loadSym(c, g, si, t.sym)
  842. result.owner = loadSym(c, g, si, t.owner)
  843. when false:
  844. for op, item in pairs t.attachedOps:
  845. result.attachedOps[op] = loadSym(c, g, si, item)
  846. result.typeInst = loadType(c, g, si, t.typeInst)
  847. var sons = newSeq[PType]()
  848. for son in items t.types:
  849. sons.add loadType(c, g, si, son)
  850. result.setSons(sons)
  851. loadAstBody(t, n)
  852. when false:
  853. for gen, id in items t.methods:
  854. result.methods.add((gen, loadSym(c, g, si, id)))
  855. proc loadType(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; t: PackedItemId): PType =
  856. if t == nilItemId:
  857. result = nil
  858. else:
  859. let si = moduleIndex(c, g, thisModule, t)
  860. assert g[si].status in {loaded, storing, stored}
  861. assert t.item > 0
  862. #if not g[si].typesInit:
  863. # g[si].typesInit = true
  864. # setLen g[si].types, g[si].fromDisk.types.len
  865. if g[si].types.getOrDefault(t.item) == nil:
  866. result = typeHeaderFromPacked(c, g, g[si].fromDisk.types[t.item], si, t.item)
  867. # store it here early on, so that recursions work properly:
  868. g[si].types[t.item] = result
  869. typeBodyFromPacked(c, g, g[si].fromDisk.types[t.item], si, t.item, result)
  870. #assert result.itemId.item == t.item, $(result.itemId.item, t.item)
  871. assert result.itemId.item > 0, $(result.itemId.item, t.item)
  872. else:
  873. result = g[si].types[t.item]
  874. assert result.itemId.item > 0, "2"
  875. proc setupLookupTables(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache;
  876. fileIdx: FileIndex; m: var LoadedModule) =
  877. m.iface = initTable[PIdent, seq[PackedItemId]]()
  878. m.ifaceHidden = initTable[PIdent, seq[PackedItemId]]()
  879. template impl(iface, e) =
  880. let nameLit = e[0]
  881. let e2 =
  882. when e[1] is PackedItemId: e[1]
  883. else: PackedItemId(module: LitId(0), item: e[1])
  884. iface.mgetOrPut(cache.getIdent(m.fromDisk.strings[nameLit]), @[]).add(e2)
  885. for e in m.fromDisk.exports:
  886. m.iface.impl(e)
  887. m.ifaceHidden.impl(e)
  888. for e in m.fromDisk.reexports:
  889. m.iface.impl(e)
  890. m.ifaceHidden.impl(e)
  891. for e in m.fromDisk.hidden:
  892. m.ifaceHidden.impl(e)
  893. let filename = AbsoluteFile toFullPath(conf, fileIdx)
  894. # We cannot call ``newSym`` here, because we have to circumvent the ID
  895. # mechanism, which we do in order to assign each module a persistent ID.
  896. m.module = PSym(kind: skModule, itemId: ItemId(module: int32(fileIdx), item: 0'i32),
  897. name: getIdent(cache, splitFile(filename).name),
  898. info: newLineInfo(fileIdx, 1, 1),
  899. position: int(fileIdx))
  900. m.module.owner = getPackage(conf, cache, fileIdx)
  901. m.module.flags = m.fromDisk.moduleFlags
  902. proc loadToReplayNodes(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache;
  903. fileIdx: FileIndex; m: var LoadedModule) =
  904. m.module.ast = newNode(nkStmtList)
  905. if m.fromDisk.toReplay.len > 0:
  906. var decoder = PackedDecoder(
  907. lastModule: int32(-1),
  908. lastLit: LitId(0),
  909. lastFile: FileIndex(-1),
  910. config: conf,
  911. cache: cache)
  912. for p in allNodes(m.fromDisk.toReplay):
  913. m.module.ast.add loadNodes(decoder, g, int(fileIdx), m.fromDisk.toReplay, p)
  914. proc needsRecompile(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache;
  915. fileIdx: FileIndex; cachedModules: var seq[FileIndex]): bool =
  916. # Does the file belong to the fileIdx need to be recompiled?
  917. let m = int(fileIdx)
  918. if m >= g.len:
  919. g.pm.setLen(m+1)
  920. case g[m].status
  921. of undefined:
  922. g[m].status = loading
  923. let fullpath = msgs.toFullPath(conf, fileIdx)
  924. let rod = toRodFile(conf, AbsoluteFile fullpath)
  925. let err = loadRodFile(rod, g[m].fromDisk, conf, ignoreConfig = conf.cmd == cmdM)
  926. if err == ok:
  927. if conf.cmd == cmdM:
  928. setupLookupTables(g, conf, cache, fileIdx, g[m])
  929. cachedModules.add fileIdx
  930. g[m].status = loaded
  931. result = false
  932. else:
  933. result = optForceFullMake in conf.globalOptions
  934. # check its dependencies:
  935. let imp = g[m].fromDisk.imports
  936. for dep in imp:
  937. let fid = toFileIndex(dep, g[m].fromDisk, conf)
  938. # Warning: we need to traverse the full graph, so
  939. # do **not use break here**!
  940. if needsRecompile(g, conf, cache, fid, cachedModules):
  941. result = true
  942. if not result:
  943. setupLookupTables(g, conf, cache, fileIdx, g[m])
  944. cachedModules.add fileIdx
  945. g[m].status = loaded
  946. else:
  947. g.pm[m] = LoadedModule(status: outdated, module: g[m].module)
  948. else:
  949. loadError(err, rod, conf)
  950. g[m].status = outdated
  951. result = true
  952. when false: loadError(err, rod, conf)
  953. of loading, loaded:
  954. # For loading: Assume no recompile is required.
  955. result = false
  956. of outdated, storing, stored:
  957. result = true
  958. proc moduleFromRodFile*(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache;
  959. fileIdx: FileIndex; cachedModules: var seq[FileIndex]): PSym =
  960. ## Returns 'nil' if the module needs to be recompiled.
  961. bench g.depAnalysis:
  962. if needsRecompile(g, conf, cache, fileIdx, cachedModules):
  963. result = nil
  964. else:
  965. result = g[int fileIdx].module
  966. assert result != nil
  967. assert result.position == int(fileIdx)
  968. for m in cachedModules:
  969. loadToReplayNodes(g, conf, cache, m, g[int m])
  970. template setupDecoder() {.dirty.} =
  971. var decoder = PackedDecoder(
  972. lastModule: int32(-1),
  973. lastLit: LitId(0),
  974. lastFile: FileIndex(-1),
  975. config: config,
  976. cache: cache)
  977. proc loadProcBody*(config: ConfigRef, cache: IdentCache;
  978. g: var PackedModuleGraph; s: PSym): PNode =
  979. bench g.loadBody:
  980. let mId = s.itemId.module
  981. var decoder = PackedDecoder(
  982. lastModule: int32(-1),
  983. lastLit: LitId(0),
  984. lastFile: FileIndex(-1),
  985. config: config,
  986. cache: cache)
  987. let pos = g[mId].fromDisk.syms[s.itemId.item].ast
  988. assert pos != emptyNodeId
  989. result = loadProcBody(decoder, g, mId, g[mId].fromDisk.bodies, NodePos pos)
  990. proc loadTypeFromId*(config: ConfigRef, cache: IdentCache;
  991. g: var PackedModuleGraph; module: int; id: PackedItemId): PType =
  992. bench g.loadType:
  993. result = g[module].types.getOrDefault(id.item)
  994. if result == nil:
  995. var decoder = PackedDecoder(
  996. lastModule: int32(-1),
  997. lastLit: LitId(0),
  998. lastFile: FileIndex(-1),
  999. config: config,
  1000. cache: cache)
  1001. result = loadType(decoder, g, module, id)
  1002. proc loadSymFromId*(config: ConfigRef, cache: IdentCache;
  1003. g: var PackedModuleGraph; module: int; id: PackedItemId): PSym =
  1004. bench g.loadSym:
  1005. result = g[module].syms.getOrDefault(id.item)
  1006. if result == nil:
  1007. var decoder = PackedDecoder(
  1008. lastModule: int32(-1),
  1009. lastLit: LitId(0),
  1010. lastFile: FileIndex(-1),
  1011. config: config,
  1012. cache: cache)
  1013. result = loadSym(decoder, g, module, id)
  1014. proc translateId*(id: PackedItemId; g: PackedModuleGraph; thisModule: int; config: ConfigRef): ItemId =
  1015. if id.module == LitId(0):
  1016. ItemId(module: thisModule.int32, item: id.item)
  1017. else:
  1018. ItemId(module: toFileIndex(id.module, g[thisModule].fromDisk, config).int32, item: id.item)
  1019. proc simulateLoadedModule*(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache;
  1020. moduleSym: PSym; m: PackedModule) =
  1021. # For now only used for heavy debugging. In the future we could use this to reduce the
  1022. # compiler's memory consumption.
  1023. let idx = moduleSym.position
  1024. assert g[idx].status in {storing}
  1025. g[idx].status = loaded
  1026. assert g[idx].module == moduleSym
  1027. setupLookupTables(g, conf, cache, FileIndex(idx), g[idx])
  1028. loadToReplayNodes(g, conf, cache, FileIndex(idx), g[idx])
  1029. # ---------------- symbol table handling ----------------
  1030. type
  1031. RodIter* = object
  1032. decoder: PackedDecoder
  1033. values: seq[PackedItemId]
  1034. i, module: int
  1035. template interfSelect(a: LoadedModule, importHidden: bool): auto =
  1036. var ret = a.iface.addr
  1037. if importHidden: ret = a.ifaceHidden.addr
  1038. ret[]
  1039. proc initRodIter*(it: var RodIter; config: ConfigRef, cache: IdentCache;
  1040. g: var PackedModuleGraph; module: FileIndex;
  1041. name: PIdent, importHidden: bool): PSym =
  1042. it.decoder = PackedDecoder(
  1043. lastModule: int32(-1),
  1044. lastLit: LitId(0),
  1045. lastFile: FileIndex(-1),
  1046. config: config,
  1047. cache: cache)
  1048. it.values = g[int module].interfSelect(importHidden).getOrDefault(name)
  1049. it.i = 0
  1050. it.module = int(module)
  1051. if it.i < it.values.len:
  1052. result = loadSym(it.decoder, g, int(module), it.values[it.i])
  1053. inc it.i
  1054. else:
  1055. result = nil
  1056. proc initRodIterAllSyms*(it: var RodIter; config: ConfigRef, cache: IdentCache;
  1057. g: var PackedModuleGraph; module: FileIndex; importHidden: bool): PSym =
  1058. it.decoder = PackedDecoder(
  1059. lastModule: int32(-1),
  1060. lastLit: LitId(0),
  1061. lastFile: FileIndex(-1),
  1062. config: config,
  1063. cache: cache)
  1064. it.values = @[]
  1065. it.module = int(module)
  1066. for v in g[int module].interfSelect(importHidden).values:
  1067. it.values.add v
  1068. it.i = 0
  1069. if it.i < it.values.len:
  1070. result = loadSym(it.decoder, g, int(module), it.values[it.i])
  1071. inc it.i
  1072. else:
  1073. result = nil
  1074. proc nextRodIter*(it: var RodIter; g: var PackedModuleGraph): PSym =
  1075. if it.i < it.values.len:
  1076. result = loadSym(it.decoder, g, it.module, it.values[it.i])
  1077. inc it.i
  1078. else:
  1079. result = nil
  1080. iterator interfaceSymbols*(config: ConfigRef, cache: IdentCache;
  1081. g: var PackedModuleGraph; module: FileIndex;
  1082. name: PIdent, importHidden: bool): PSym =
  1083. setupDecoder()
  1084. let values = g[int module].interfSelect(importHidden).getOrDefault(name)
  1085. for pid in values:
  1086. let s = loadSym(decoder, g, int(module), pid)
  1087. assert s != nil
  1088. yield s
  1089. proc interfaceSymbol*(config: ConfigRef, cache: IdentCache;
  1090. g: var PackedModuleGraph; module: FileIndex;
  1091. name: PIdent, importHidden: bool): PSym =
  1092. setupDecoder()
  1093. let values = g[int module].interfSelect(importHidden).getOrDefault(name)
  1094. result = loadSym(decoder, g, int(module), values[0])
  1095. proc idgenFromLoadedModule*(m: LoadedModule): IdGenerator =
  1096. IdGenerator(module: m.module.itemId.module, symId: int32 m.fromDisk.syms.len,
  1097. typeId: int32 m.fromDisk.types.len)
  1098. proc searchForCompilerproc*(m: LoadedModule; name: string): int32 =
  1099. # slow, linear search, but the results are cached:
  1100. for it in items(m.fromDisk.compilerProcs):
  1101. if m.fromDisk.strings[it[0]] == name:
  1102. return it[1]
  1103. return -1
  1104. # ------------------------- .rod file viewer ---------------------------------
  1105. proc rodViewer*(rodfile: AbsoluteFile; config: ConfigRef, cache: IdentCache) =
  1106. var m: PackedModule = PackedModule()
  1107. let err = loadRodFile(rodfile, m, config, ignoreConfig=true)
  1108. if err != ok:
  1109. config.quitOrRaise "Error: could not load: " & $rodfile.string & " reason: " & $err
  1110. when false:
  1111. echo "exports:"
  1112. for ex in m.exports:
  1113. echo " ", m.strings[ex[0]], " local ID: ", ex[1]
  1114. assert ex[0] == m.syms[ex[1]].name
  1115. # ex[1] int32
  1116. echo "reexports:"
  1117. for ex in m.reexports:
  1118. echo " ", m.strings[ex[0]]
  1119. # reexports*: seq[(LitId, PackedItemId)]
  1120. echo "hidden: " & $m.hidden.len
  1121. for ex in m.hidden:
  1122. echo " ", m.strings[ex[0]], " local ID: ", ex[1]
  1123. when false:
  1124. echo "all symbols"
  1125. for i in 0..high(m.syms):
  1126. if m.syms[i].name != LitId(0):
  1127. echo " ", m.strings[m.syms[i].name], " local ID: ", i, " kind ", m.syms[i].kind
  1128. else:
  1129. echo " <anon symbol?> local ID: ", i, " kind ", m.syms[i].kind
  1130. echo "symbols: ", m.syms.len, " types: ", m.types.len,
  1131. " top level nodes: ", m.topLevel.len, " other nodes: ", m.bodies.len,
  1132. " strings: ", m.strings.len, " numbers: ", m.numbers.len
  1133. echo "SIZES:"
  1134. echo "symbols: ", m.syms.len * sizeof(PackedSym), " types: ", m.types.len * sizeof(PackedType),
  1135. " top level nodes: ", m.topLevel.len * sizeof(PackedNode),
  1136. " other nodes: ", m.bodies.len * sizeof(PackedNode),
  1137. " strings: ", sizeOnDisc(m.strings)
  1138. when false:
  1139. var tt = 0
  1140. var fc = 0
  1141. for x in m.topLevel:
  1142. if x.kind == nkSym or x.typeId == nilItemId: inc tt
  1143. if x.flags == {}: inc fc
  1144. for x in m.bodies:
  1145. if x.kind == nkSym or x.typeId == nilItemId: inc tt
  1146. if x.flags == {}: inc fc
  1147. let total = float(m.topLevel.len + m.bodies.len)
  1148. echo "nodes with nil type: ", tt, " in % ", tt.float / total
  1149. echo "nodes with empty flags: ", fc.float / total