ic.nim 48 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355
  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. 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*: seq[PackedSym]
  53. types*: seq[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(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(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.r, 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 loadTabSection(section, data) {.dirty.} =
  526. f.loadSection section
  527. f.load data
  528. loadTabSection stringsSection, m.strings
  529. loadSeqSection checkSumsSection, m.includes
  530. if config.cmd != cmdM and not includesIdentical(m, config):
  531. f.err = includeFileChanged
  532. loadSeqSection depsSection, m.imports
  533. bench gloadBodies:
  534. loadTabSection numbersSection, m.numbers
  535. loadSeqSection exportsSection, m.exports
  536. loadSeqSection hiddenSection, m.hidden
  537. loadSeqSection reexportsSection, m.reexports
  538. loadSeqSection compilerProcsSection, m.compilerProcs
  539. loadSeqSection trmacrosSection, m.trmacros
  540. loadSeqSection convertersSection, m.converters
  541. loadSeqSection methodsSection, m.methods
  542. loadSeqSection pureEnumsSection, m.pureEnums
  543. loadTabSection toReplaySection, m.toReplay
  544. loadTabSection topLevelSection, m.topLevel
  545. loadTabSection bodiesSection, m.bodies
  546. loadSeqSection symsSection, m.syms
  547. loadSeqSection typesSection, m.types
  548. loadSeqSection typeInstCacheSection, m.typeInstCache
  549. loadSeqSection procInstCacheSection, m.procInstCache
  550. loadSeqSection attachedOpsSection, m.attachedOps
  551. loadSeqSection methodsPerGenericTypeSection, m.methodsPerGenericType
  552. loadSeqSection enumToStringProcsSection, m.enumToStringProcs
  553. loadSeqSection methodsPerTypeSection, m.methodsPerType
  554. loadSeqSection dispatchersSection, m.dispatchers
  555. loadSeqSection typeInfoSection, m.emittedTypeInfo
  556. f.loadSection backendFlagsSection
  557. f.loadPrim m.backendFlags
  558. f.loadSection sideChannelSection
  559. f.load m.man
  560. close(f)
  561. result = f.err
  562. # -------------------------------------------------------------------------
  563. proc storeError(err: RodFileError; filename: AbsoluteFile) =
  564. echo "Error: ", $err, "; couldn't write to ", filename.string
  565. removeFile(filename.string)
  566. proc saveRodFile*(filename: AbsoluteFile; encoder: var PackedEncoder; m: var PackedModule) =
  567. flush encoder, m
  568. #rememberConfig(encoder, encoder.config)
  569. var f = rodfiles.create(filename.string)
  570. f.storeHeader()
  571. f.storeSection configSection
  572. f.storePrim m.definedSymbols
  573. f.storePrim m.moduleFlags
  574. f.storePrim m.cfg
  575. template storeSeqSection(section, data) {.dirty.} =
  576. f.storeSection section
  577. f.storeSeq data
  578. template storeTabSection(section, data) {.dirty.} =
  579. f.storeSection section
  580. f.store data
  581. storeTabSection stringsSection, m.strings
  582. storeSeqSection checkSumsSection, m.includes
  583. storeSeqSection depsSection, m.imports
  584. storeTabSection numbersSection, m.numbers
  585. storeSeqSection exportsSection, m.exports
  586. storeSeqSection hiddenSection, m.hidden
  587. storeSeqSection reexportsSection, m.reexports
  588. storeSeqSection compilerProcsSection, m.compilerProcs
  589. storeSeqSection trmacrosSection, m.trmacros
  590. storeSeqSection convertersSection, m.converters
  591. storeSeqSection methodsSection, m.methods
  592. storeSeqSection pureEnumsSection, m.pureEnums
  593. storeTabSection toReplaySection, m.toReplay
  594. storeTabSection topLevelSection, m.topLevel
  595. storeTabSection bodiesSection, m.bodies
  596. storeSeqSection symsSection, m.syms
  597. storeSeqSection typesSection, m.types
  598. storeSeqSection typeInstCacheSection, m.typeInstCache
  599. storeSeqSection procInstCacheSection, m.procInstCache
  600. storeSeqSection attachedOpsSection, m.attachedOps
  601. storeSeqSection methodsPerGenericTypeSection, m.methodsPerGenericType
  602. storeSeqSection enumToStringProcsSection, m.enumToStringProcs
  603. storeSeqSection methodsPerTypeSection, m.methodsPerType
  604. storeSeqSection dispatchersSection, m.dispatchers
  605. storeSeqSection typeInfoSection, m.emittedTypeInfo
  606. f.storeSection backendFlagsSection
  607. f.storePrim m.backendFlags
  608. f.storeSection sideChannelSection
  609. f.store m.man
  610. close(f)
  611. encoder.disable()
  612. if f.err != ok:
  613. storeError(f.err, filename)
  614. when false:
  615. # basic loader testing:
  616. var m2: PackedModule
  617. discard loadRodFile(filename, m2, encoder.config)
  618. echo "loaded ", filename.string
  619. # ----------------------------------------------------------------------------
  620. type
  621. PackedDecoder* = object
  622. lastModule: int
  623. lastLit: LitId
  624. lastFile: FileIndex # remember the last lookup entry.
  625. config*: ConfigRef
  626. cache*: IdentCache
  627. type
  628. ModuleStatus* = enum
  629. undefined,
  630. storing, # state is strictly for stress-testing purposes
  631. loading,
  632. loaded,
  633. outdated,
  634. stored # store is complete, no further additions possible
  635. LoadedModule* = object
  636. status*: ModuleStatus
  637. symsInit, typesInit, loadedButAliveSetChanged*: bool
  638. fromDisk*: PackedModule
  639. syms: seq[PSym] # indexed by itemId
  640. types: seq[PType]
  641. module*: PSym # the one true module symbol.
  642. iface, ifaceHidden: Table[PIdent, seq[PackedItemId]]
  643. # PackedItemId so that it works with reexported symbols too
  644. # ifaceHidden includes private symbols
  645. type
  646. PackedModuleGraph* = object
  647. pm*: seq[LoadedModule] # indexed by FileIndex
  648. when BenchIC:
  649. depAnalysis: MonoTime
  650. loadBody: MonoTime
  651. loadSym, loadType, loadBodies: MonoTime
  652. when BenchIC:
  653. proc echoTimes*(m: PackedModuleGraph) =
  654. echo "analysis: ", m.depAnalysis, " loadBody: ", m.loadBody, " loadSym: ",
  655. m.loadSym, " loadType: ", m.loadType, " all bodies: ", gloadBodies
  656. template `[]`*(m: PackedModuleGraph; i: int): LoadedModule = m.pm[i]
  657. template len*(m: PackedModuleGraph): int = m.pm.len
  658. proc loadType(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; t: PackedItemId): PType
  659. proc loadSym(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; s: PackedItemId): PSym
  660. proc toFileIndexCached*(c: var PackedDecoder; g: PackedModuleGraph; thisModule: int; f: LitId): FileIndex =
  661. if f == LitId(0):
  662. result = InvalidFileIdx
  663. elif c.lastLit == f and c.lastModule == thisModule:
  664. result = c.lastFile
  665. else:
  666. result = toFileIndex(f, g[thisModule].fromDisk, c.config)
  667. c.lastModule = thisModule
  668. c.lastLit = f
  669. c.lastFile = result
  670. proc translateLineInfo(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int;
  671. x: PackedLineInfo): TLineInfo =
  672. assert g[thisModule].status in {loaded, storing, stored}
  673. let (fileId, line, col) = unpack(g[thisModule].fromDisk.man, x)
  674. result = TLineInfo(line: line.uint16, col: col.int16,
  675. fileIndex: toFileIndexCached(c, g, thisModule, fileId))
  676. proc loadNodes*(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int;
  677. tree: PackedTree; n: NodePos): PNode =
  678. let k = n.kind
  679. if k == nkNilRodNode:
  680. return nil
  681. when false:
  682. echo "loading node ", c.config $ translateLineInfo(c, g, thisModule, n.info)
  683. result = newNodeIT(k, translateLineInfo(c, g, thisModule, n.info),
  684. loadType(c, g, thisModule, n.typ))
  685. result.flags = n.flags
  686. case k
  687. of nkNone, nkEmpty, nkNilLit, nkType:
  688. discard
  689. of nkIdent:
  690. result.ident = getIdent(c.cache, g[thisModule].fromDisk.strings[n.litId])
  691. of nkSym:
  692. result.sym = loadSym(c, g, thisModule, PackedItemId(module: LitId(0), item: tree[n].soperand))
  693. if result.typ == nil and nfOpenSym notin result.flags:
  694. result.typ = result.sym.typ
  695. of externIntLit:
  696. result.intVal = g[thisModule].fromDisk.numbers[n.litId]
  697. of nkStrLit..nkTripleStrLit:
  698. result.strVal = g[thisModule].fromDisk.strings[n.litId]
  699. of nkFloatLit..nkFloat128Lit:
  700. result.floatVal = cast[BiggestFloat](g[thisModule].fromDisk.numbers[n.litId])
  701. of nkModuleRef:
  702. let (n1, n2) = sons2(tree, n)
  703. assert n1.kind == nkNone
  704. assert n2.kind == nkNone
  705. transitionNoneToSym(result)
  706. result.sym = loadSym(c, g, thisModule, PackedItemId(module: n1.litId, item: tree[n2].soperand))
  707. if result.typ == nil and nfOpenSym notin result.flags:
  708. result.typ = result.sym.typ
  709. else:
  710. for n0 in sonsReadonly(tree, n):
  711. result.addAllowNil loadNodes(c, g, thisModule, tree, n0)
  712. proc initPackedDecoder*(config: ConfigRef; cache: IdentCache): PackedDecoder =
  713. result = PackedDecoder(
  714. lastModule: int32(-1),
  715. lastLit: LitId(0),
  716. lastFile: FileIndex(-1),
  717. config: config,
  718. cache: cache)
  719. proc loadProcHeader(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int;
  720. tree: PackedTree; n: NodePos): PNode =
  721. # do not load the body of the proc. This will be done later in
  722. # getProcBody, if required.
  723. let k = n.kind
  724. result = newNodeIT(k, translateLineInfo(c, g, thisModule, n.info),
  725. loadType(c, g, thisModule, n.typ))
  726. result.flags = n.flags
  727. assert k in {nkProcDef, nkMethodDef, nkIteratorDef, nkFuncDef, nkConverterDef, nkLambda}
  728. var i = 0
  729. for n0 in sonsReadonly(tree, n):
  730. if i != bodyPos:
  731. result.add loadNodes(c, g, thisModule, tree, n0)
  732. else:
  733. result.addAllowNil nil
  734. inc i
  735. proc loadProcBody(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int;
  736. tree: PackedTree; n: NodePos): PNode =
  737. result = nil
  738. var i = 0
  739. for n0 in sonsReadonly(tree, n):
  740. if i == bodyPos:
  741. result = loadNodes(c, g, thisModule, tree, n0)
  742. inc i
  743. proc moduleIndex*(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int;
  744. s: PackedItemId): int32 {.inline.} =
  745. result = if s.module == LitId(0): thisModule.int32
  746. else: toFileIndexCached(c, g, thisModule, s.module).int32
  747. proc symHeaderFromPacked(c: var PackedDecoder; g: var PackedModuleGraph;
  748. s: PackedSym; si, item: int32): PSym =
  749. result = PSym(itemId: ItemId(module: si, item: item),
  750. kind: s.kind, magic: s.magic, flags: s.flags,
  751. info: translateLineInfo(c, g, si, s.info),
  752. options: s.options,
  753. position: if s.kind in {skForVar, skVar, skLet, skTemp}: 0 else: s.position,
  754. offset: if s.kind in routineKinds: defaultOffset else: s.offset,
  755. disamb: s.disamb,
  756. name: getIdent(c.cache, g[si].fromDisk.strings[s.name])
  757. )
  758. template loadAstBody(p, field) =
  759. if p.field != emptyNodeId:
  760. result.field = loadNodes(c, g, si, g[si].fromDisk.bodies, NodePos p.field)
  761. template loadAstBodyLazy(p, field) =
  762. if p.field != emptyNodeId:
  763. result.field = loadProcHeader(c, g, si, g[si].fromDisk.bodies, NodePos p.field)
  764. proc loadLib(c: var PackedDecoder; g: var PackedModuleGraph;
  765. si, item: int32; l: PackedLib): PLib =
  766. # XXX: hack; assume a zero LitId means the PackedLib is all zero (empty)
  767. if l.name.int == 0:
  768. result = nil
  769. else:
  770. result = PLib(generated: l.generated, isOverridden: l.isOverridden,
  771. kind: l.kind, name: rope g[si].fromDisk.strings[l.name])
  772. loadAstBody(l, path)
  773. proc symBodyFromPacked(c: var PackedDecoder; g: var PackedModuleGraph;
  774. s: PackedSym; si, item: int32; result: PSym) =
  775. result.typ = loadType(c, g, si, s.typ)
  776. loadAstBody(s, constraint)
  777. if result.kind in {skProc, skFunc, skIterator, skConverter, skMethod}:
  778. loadAstBodyLazy(s, ast)
  779. else:
  780. loadAstBody(s, ast)
  781. result.annex = loadLib(c, g, si, item, s.annex)
  782. when hasFFI:
  783. result.cname = g[si].fromDisk.strings[s.cname]
  784. if s.kind in {skLet, skVar, skField, skForVar}:
  785. result.guard = loadSym(c, g, si, s.guard)
  786. result.bitsize = s.bitsize
  787. result.alignment = s.alignment
  788. result.owner = loadSym(c, g, si, s.owner)
  789. let externalName = g[si].fromDisk.strings[s.externalName]
  790. if externalName != "":
  791. result.loc.r = rope externalName
  792. result.loc.flags = s.locFlags
  793. result.instantiatedFrom = loadSym(c, g, si, s.instantiatedFrom)
  794. proc needsRecompile(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache;
  795. fileIdx: FileIndex; cachedModules: var seq[FileIndex]): bool
  796. proc loadToReplayNodes(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache;
  797. fileIdx: FileIndex; m: var LoadedModule)
  798. proc loadSym(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; s: PackedItemId): PSym =
  799. if s == nilItemId:
  800. result = nil
  801. else:
  802. let si = moduleIndex(c, g, thisModule, s)
  803. if si >= g.len:
  804. g.pm.setLen(si+1)
  805. if g[si].status == undefined and c.config.cmd == cmdM:
  806. var cachedModules: seq[FileIndex] = @[]
  807. discard needsRecompile(g, c.config, c.cache, FileIndex(si), cachedModules)
  808. for m in cachedModules:
  809. loadToReplayNodes(g, c.config, c.cache, m, g[int m])
  810. assert g[si].status in {loaded, storing, stored}
  811. if not g[si].symsInit:
  812. g[si].symsInit = true
  813. setLen g[si].syms, g[si].fromDisk.syms.len
  814. if g[si].syms[s.item] == nil:
  815. if g[si].fromDisk.syms[s.item].kind != skModule:
  816. result = symHeaderFromPacked(c, g, g[si].fromDisk.syms[s.item], si, s.item)
  817. # store it here early on, so that recursions work properly:
  818. g[si].syms[s.item] = result
  819. symBodyFromPacked(c, g, g[si].fromDisk.syms[s.item], si, s.item, result)
  820. else:
  821. result = g[si].module
  822. assert result != nil
  823. g[si].syms[s.item] = result
  824. else:
  825. result = g[si].syms[s.item]
  826. proc typeHeaderFromPacked(c: var PackedDecoder; g: var PackedModuleGraph;
  827. t: PackedType; si, item: int32): PType =
  828. result = PType(itemId: ItemId(module: si, item: t.nonUniqueId), kind: t.kind,
  829. flags: t.flags, size: t.size, align: t.align,
  830. paddingAtEnd: t.paddingAtEnd,
  831. uniqueId: ItemId(module: si, item: item),
  832. callConv: t.callConv)
  833. proc typeBodyFromPacked(c: var PackedDecoder; g: var PackedModuleGraph;
  834. t: PackedType; si, item: int32; result: PType) =
  835. result.sym = loadSym(c, g, si, t.sym)
  836. result.owner = loadSym(c, g, si, t.owner)
  837. when false:
  838. for op, item in pairs t.attachedOps:
  839. result.attachedOps[op] = loadSym(c, g, si, item)
  840. result.typeInst = loadType(c, g, si, t.typeInst)
  841. var sons = newSeq[PType]()
  842. for son in items t.types:
  843. sons.add loadType(c, g, si, son)
  844. result.setSons(sons)
  845. loadAstBody(t, n)
  846. when false:
  847. for gen, id in items t.methods:
  848. result.methods.add((gen, loadSym(c, g, si, id)))
  849. proc loadType(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; t: PackedItemId): PType =
  850. if t == nilItemId:
  851. result = nil
  852. else:
  853. let si = moduleIndex(c, g, thisModule, t)
  854. assert g[si].status in {loaded, storing, stored}
  855. assert t.item > 0
  856. if not g[si].typesInit:
  857. g[si].typesInit = true
  858. setLen g[si].types, g[si].fromDisk.types.len
  859. if g[si].types[t.item] == nil:
  860. result = typeHeaderFromPacked(c, g, g[si].fromDisk.types[t.item], si, t.item)
  861. # store it here early on, so that recursions work properly:
  862. g[si].types[t.item] = result
  863. typeBodyFromPacked(c, g, g[si].fromDisk.types[t.item], si, t.item, result)
  864. #assert result.itemId.item == t.item, $(result.itemId.item, t.item)
  865. assert result.itemId.item > 0, $(result.itemId.item, t.item)
  866. else:
  867. result = g[si].types[t.item]
  868. assert result.itemId.item > 0, "2"
  869. proc setupLookupTables(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache;
  870. fileIdx: FileIndex; m: var LoadedModule) =
  871. m.iface = initTable[PIdent, seq[PackedItemId]]()
  872. m.ifaceHidden = initTable[PIdent, seq[PackedItemId]]()
  873. template impl(iface, e) =
  874. let nameLit = e[0]
  875. let e2 =
  876. when e[1] is PackedItemId: e[1]
  877. else: PackedItemId(module: LitId(0), item: e[1])
  878. iface.mgetOrPut(cache.getIdent(m.fromDisk.strings[nameLit]), @[]).add(e2)
  879. for e in m.fromDisk.exports:
  880. m.iface.impl(e)
  881. m.ifaceHidden.impl(e)
  882. for e in m.fromDisk.reexports:
  883. m.iface.impl(e)
  884. m.ifaceHidden.impl(e)
  885. for e in m.fromDisk.hidden:
  886. m.ifaceHidden.impl(e)
  887. let filename = AbsoluteFile toFullPath(conf, fileIdx)
  888. # We cannot call ``newSym`` here, because we have to circumvent the ID
  889. # mechanism, which we do in order to assign each module a persistent ID.
  890. m.module = PSym(kind: skModule, itemId: ItemId(module: int32(fileIdx), item: 0'i32),
  891. name: getIdent(cache, splitFile(filename).name),
  892. info: newLineInfo(fileIdx, 1, 1),
  893. position: int(fileIdx))
  894. m.module.owner = getPackage(conf, cache, fileIdx)
  895. m.module.flags = m.fromDisk.moduleFlags
  896. proc loadToReplayNodes(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache;
  897. fileIdx: FileIndex; m: var LoadedModule) =
  898. m.module.ast = newNode(nkStmtList)
  899. if m.fromDisk.toReplay.len > 0:
  900. var decoder = PackedDecoder(
  901. lastModule: int32(-1),
  902. lastLit: LitId(0),
  903. lastFile: FileIndex(-1),
  904. config: conf,
  905. cache: cache)
  906. for p in allNodes(m.fromDisk.toReplay):
  907. m.module.ast.add loadNodes(decoder, g, int(fileIdx), m.fromDisk.toReplay, p)
  908. proc needsRecompile(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache;
  909. fileIdx: FileIndex; cachedModules: var seq[FileIndex]): bool =
  910. # Does the file belong to the fileIdx need to be recompiled?
  911. let m = int(fileIdx)
  912. if m >= g.len:
  913. g.pm.setLen(m+1)
  914. case g[m].status
  915. of undefined:
  916. g[m].status = loading
  917. let fullpath = msgs.toFullPath(conf, fileIdx)
  918. let rod = toRodFile(conf, AbsoluteFile fullpath)
  919. let err = loadRodFile(rod, g[m].fromDisk, conf, ignoreConfig = conf.cmd == cmdM)
  920. if err == ok:
  921. if conf.cmd == cmdM:
  922. setupLookupTables(g, conf, cache, fileIdx, g[m])
  923. cachedModules.add fileIdx
  924. g[m].status = loaded
  925. result = false
  926. else:
  927. result = optForceFullMake in conf.globalOptions
  928. # check its dependencies:
  929. let imp = g[m].fromDisk.imports
  930. for dep in imp:
  931. let fid = toFileIndex(dep, g[m].fromDisk, conf)
  932. # Warning: we need to traverse the full graph, so
  933. # do **not use break here**!
  934. if needsRecompile(g, conf, cache, fid, cachedModules):
  935. result = true
  936. if not result:
  937. setupLookupTables(g, conf, cache, fileIdx, g[m])
  938. cachedModules.add fileIdx
  939. g[m].status = loaded
  940. else:
  941. g.pm[m] = LoadedModule(status: outdated, module: g[m].module)
  942. else:
  943. loadError(err, rod, conf)
  944. g[m].status = outdated
  945. result = true
  946. when false: loadError(err, rod, conf)
  947. of loading, loaded:
  948. # For loading: Assume no recompile is required.
  949. result = false
  950. of outdated, storing, stored:
  951. result = true
  952. proc moduleFromRodFile*(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache;
  953. fileIdx: FileIndex; cachedModules: var seq[FileIndex]): PSym =
  954. ## Returns 'nil' if the module needs to be recompiled.
  955. bench g.depAnalysis:
  956. if needsRecompile(g, conf, cache, fileIdx, cachedModules):
  957. result = nil
  958. else:
  959. result = g[int fileIdx].module
  960. assert result != nil
  961. assert result.position == int(fileIdx)
  962. for m in cachedModules:
  963. loadToReplayNodes(g, conf, cache, m, g[int m])
  964. template setupDecoder() {.dirty.} =
  965. var decoder = PackedDecoder(
  966. lastModule: int32(-1),
  967. lastLit: LitId(0),
  968. lastFile: FileIndex(-1),
  969. config: config,
  970. cache: cache)
  971. proc loadProcBody*(config: ConfigRef, cache: IdentCache;
  972. g: var PackedModuleGraph; s: PSym): PNode =
  973. bench g.loadBody:
  974. let mId = s.itemId.module
  975. var decoder = PackedDecoder(
  976. lastModule: int32(-1),
  977. lastLit: LitId(0),
  978. lastFile: FileIndex(-1),
  979. config: config,
  980. cache: cache)
  981. let pos = g[mId].fromDisk.syms[s.itemId.item].ast
  982. assert pos != emptyNodeId
  983. result = loadProcBody(decoder, g, mId, g[mId].fromDisk.bodies, NodePos pos)
  984. proc loadTypeFromId*(config: ConfigRef, cache: IdentCache;
  985. g: var PackedModuleGraph; module: int; id: PackedItemId): PType =
  986. bench g.loadType:
  987. if id.item < g[module].types.len:
  988. result = g[module].types[id.item]
  989. else:
  990. result = nil
  991. if result == nil:
  992. var decoder = PackedDecoder(
  993. lastModule: int32(-1),
  994. lastLit: LitId(0),
  995. lastFile: FileIndex(-1),
  996. config: config,
  997. cache: cache)
  998. result = loadType(decoder, g, module, id)
  999. proc loadSymFromId*(config: ConfigRef, cache: IdentCache;
  1000. g: var PackedModuleGraph; module: int; id: PackedItemId): PSym =
  1001. bench g.loadSym:
  1002. if id.item < g[module].syms.len:
  1003. result = g[module].syms[id.item]
  1004. else:
  1005. result = nil
  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 checkForHoles(m: PackedModule; config: ConfigRef; moduleId: int) =
  1020. var bugs = 0
  1021. for i in 1 .. high(m.syms):
  1022. if m.syms[i].kind == skUnknown:
  1023. echo "EMPTY ID ", i, " module ", moduleId, " ", toFullPath(config, FileIndex(moduleId))
  1024. inc bugs
  1025. assert bugs == 0
  1026. when false:
  1027. var nones = 0
  1028. for i in 1 .. high(m.types):
  1029. inc nones, m.types[i].kind == tyNone
  1030. assert nones < 1
  1031. proc simulateLoadedModule*(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache;
  1032. moduleSym: PSym; m: PackedModule) =
  1033. # For now only used for heavy debugging. In the future we could use this to reduce the
  1034. # compiler's memory consumption.
  1035. let idx = moduleSym.position
  1036. assert g[idx].status in {storing}
  1037. g[idx].status = loaded
  1038. assert g[idx].module == moduleSym
  1039. setupLookupTables(g, conf, cache, FileIndex(idx), g[idx])
  1040. loadToReplayNodes(g, conf, cache, FileIndex(idx), g[idx])
  1041. # ---------------- symbol table handling ----------------
  1042. type
  1043. RodIter* = object
  1044. decoder: PackedDecoder
  1045. values: seq[PackedItemId]
  1046. i, module: int
  1047. template interfSelect(a: LoadedModule, importHidden: bool): auto =
  1048. var ret = a.iface.addr
  1049. if importHidden: ret = a.ifaceHidden.addr
  1050. ret[]
  1051. proc initRodIter*(it: var RodIter; config: ConfigRef, cache: IdentCache;
  1052. g: var PackedModuleGraph; module: FileIndex;
  1053. name: PIdent, importHidden: bool): PSym =
  1054. it.decoder = PackedDecoder(
  1055. lastModule: int32(-1),
  1056. lastLit: LitId(0),
  1057. lastFile: FileIndex(-1),
  1058. config: config,
  1059. cache: cache)
  1060. it.values = g[int module].interfSelect(importHidden).getOrDefault(name)
  1061. it.i = 0
  1062. it.module = int(module)
  1063. if it.i < it.values.len:
  1064. result = loadSym(it.decoder, g, int(module), it.values[it.i])
  1065. inc it.i
  1066. else:
  1067. result = nil
  1068. proc initRodIterAllSyms*(it: var RodIter; config: ConfigRef, cache: IdentCache;
  1069. g: var PackedModuleGraph; module: FileIndex; importHidden: bool): PSym =
  1070. it.decoder = PackedDecoder(
  1071. lastModule: int32(-1),
  1072. lastLit: LitId(0),
  1073. lastFile: FileIndex(-1),
  1074. config: config,
  1075. cache: cache)
  1076. it.values = @[]
  1077. it.module = int(module)
  1078. for v in g[int module].interfSelect(importHidden).values:
  1079. it.values.add v
  1080. it.i = 0
  1081. if it.i < it.values.len:
  1082. result = loadSym(it.decoder, g, int(module), it.values[it.i])
  1083. inc it.i
  1084. else:
  1085. result = nil
  1086. proc nextRodIter*(it: var RodIter; g: var PackedModuleGraph): PSym =
  1087. if it.i < it.values.len:
  1088. result = loadSym(it.decoder, g, it.module, it.values[it.i])
  1089. inc it.i
  1090. else:
  1091. result = nil
  1092. iterator interfaceSymbols*(config: ConfigRef, cache: IdentCache;
  1093. g: var PackedModuleGraph; module: FileIndex;
  1094. name: PIdent, importHidden: bool): PSym =
  1095. setupDecoder()
  1096. let values = g[int module].interfSelect(importHidden).getOrDefault(name)
  1097. for pid in values:
  1098. let s = loadSym(decoder, g, int(module), pid)
  1099. assert s != nil
  1100. yield s
  1101. proc interfaceSymbol*(config: ConfigRef, cache: IdentCache;
  1102. g: var PackedModuleGraph; module: FileIndex;
  1103. name: PIdent, importHidden: bool): PSym =
  1104. setupDecoder()
  1105. let values = g[int module].interfSelect(importHidden).getOrDefault(name)
  1106. result = loadSym(decoder, g, int(module), values[0])
  1107. proc idgenFromLoadedModule*(m: LoadedModule): IdGenerator =
  1108. IdGenerator(module: m.module.itemId.module, symId: int32 m.fromDisk.syms.len,
  1109. typeId: int32 m.fromDisk.types.len)
  1110. proc searchForCompilerproc*(m: LoadedModule; name: string): int32 =
  1111. # slow, linear search, but the results are cached:
  1112. for it in items(m.fromDisk.compilerProcs):
  1113. if m.fromDisk.strings[it[0]] == name:
  1114. return it[1]
  1115. return -1
  1116. # ------------------------- .rod file viewer ---------------------------------
  1117. proc rodViewer*(rodfile: AbsoluteFile; config: ConfigRef, cache: IdentCache) =
  1118. var m: PackedModule = PackedModule()
  1119. let err = loadRodFile(rodfile, m, config, ignoreConfig=true)
  1120. if err != ok:
  1121. config.quitOrRaise "Error: could not load: " & $rodfile.string & " reason: " & $err
  1122. when false:
  1123. echo "exports:"
  1124. for ex in m.exports:
  1125. echo " ", m.strings[ex[0]], " local ID: ", ex[1]
  1126. assert ex[0] == m.syms[ex[1]].name
  1127. # ex[1] int32
  1128. echo "reexports:"
  1129. for ex in m.reexports:
  1130. echo " ", m.strings[ex[0]]
  1131. # reexports*: seq[(LitId, PackedItemId)]
  1132. echo "hidden: " & $m.hidden.len
  1133. for ex in m.hidden:
  1134. echo " ", m.strings[ex[0]], " local ID: ", ex[1]
  1135. when false:
  1136. echo "all symbols"
  1137. for i in 0..high(m.syms):
  1138. if m.syms[i].name != LitId(0):
  1139. echo " ", m.strings[m.syms[i].name], " local ID: ", i, " kind ", m.syms[i].kind
  1140. else:
  1141. echo " <anon symbol?> local ID: ", i, " kind ", m.syms[i].kind
  1142. echo "symbols: ", m.syms.len, " types: ", m.types.len,
  1143. " top level nodes: ", m.topLevel.len, " other nodes: ", m.bodies.len,
  1144. " strings: ", m.strings.len, " numbers: ", m.numbers.len
  1145. echo "SIZES:"
  1146. echo "symbols: ", m.syms.len * sizeof(PackedSym), " types: ", m.types.len * sizeof(PackedType),
  1147. " top level nodes: ", m.topLevel.len * sizeof(PackedNode),
  1148. " other nodes: ", m.bodies.len * sizeof(PackedNode),
  1149. " strings: ", sizeOnDisc(m.strings)
  1150. when false:
  1151. var tt = 0
  1152. var fc = 0
  1153. for x in m.topLevel:
  1154. if x.kind == nkSym or x.typeId == nilItemId: inc tt
  1155. if x.flags == {}: inc fc
  1156. for x in m.bodies:
  1157. if x.kind == nkSym or x.typeId == nilItemId: inc tt
  1158. if x.flags == {}: inc fc
  1159. let total = float(m.topLevel.len + m.bodies.len)
  1160. echo "nodes with nil type: ", tt, " in % ", tt.float / total
  1161. echo "nodes with empty flags: ", fc.float / total