ic.nim 48 KB

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