ic.nim 44 KB

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