ic.nim 44 KB

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