ic.nim 45 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235
  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
  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. import ../../dist/checksums/src/checksums/sha1
  16. when defined(nimPreviewSlimSystem):
  17. import std/[syncio, assertions, formatfloat]
  18. type
  19. PackedConfig* = object
  20. backend: TBackend
  21. selectedGC: TGCMode
  22. cCompiler: TSystemCC
  23. options: TOptions
  24. globalOptions: TGlobalOptions
  25. ModuleBackendFlag* = enum
  26. HasDatInitProc
  27. HasModuleInitProc
  28. PackedModule* = object ## the parts of a PackedEncoder that are part of the .rod file
  29. definedSymbols: string
  30. moduleFlags: TSymFlags
  31. includes*: seq[(LitId, string)] # first entry is the module filename itself
  32. imports: seq[LitId] # the modules this module depends on
  33. toReplay*: PackedTree # pragmas and VM specific state to replay.
  34. topLevel*: PackedTree # top level statements
  35. bodies*: PackedTree # other trees. Referenced from typ.n and sym.ast by their position.
  36. #producedGenerics*: Table[GenericKey, SymId]
  37. exports*: seq[(LitId, int32)]
  38. hidden*: seq[(LitId, int32)]
  39. reexports*: seq[(LitId, PackedItemId)]
  40. compilerProcs*: seq[(LitId, int32)]
  41. converters*, methods*, trmacros*, pureEnums*: seq[int32]
  42. typeInstCache*: seq[(PackedItemId, PackedItemId)]
  43. procInstCache*: seq[PackedInstantiation]
  44. attachedOps*: seq[(PackedItemId, TTypeAttachedOp, 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)
  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.isOverridden = l.isOverridden
  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, disamb: s.disamb, 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(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 storeAttachedProcDef*(t: PType; op: TTypeAttachedOp; s: PSym,
  457. encoder: var PackedEncoder; m: var PackedModule) =
  458. assert s.kind in routineKinds
  459. assert isActive(encoder)
  460. let tid = storeTypeLater(t, encoder, m)
  461. let sid = storeSymLater(s, encoder, m)
  462. m.attachedOps.add (tid, op, sid)
  463. toPackedGeneratedProcDef(s, encoder, m)
  464. proc storeInstantiation*(c: var PackedEncoder; m: var PackedModule; s: PSym; i: PInstantiation) =
  465. var t = newSeq[PackedItemId](i.concreteTypes.len)
  466. for j in 0..high(i.concreteTypes):
  467. t[j] = storeTypeLater(i.concreteTypes[j], c, m)
  468. m.procInstCache.add PackedInstantiation(key: storeSymLater(s, c, m),
  469. sym: storeSymLater(i.sym, c, m),
  470. concreteTypes: t)
  471. toPackedGeneratedProcDef(i.sym, c, m)
  472. proc storeExpansion*(c: var PackedEncoder; m: var PackedModule; info: TLineInfo; s: PSym) =
  473. toPackedNode(newSymNode(s, info), m.bodies, c, m)
  474. proc loadError(err: RodFileError; filename: AbsoluteFile; config: ConfigRef;) =
  475. case err
  476. of cannotOpen:
  477. rawMessage(config, warnCannotOpenFile, filename.string)
  478. of includeFileChanged:
  479. rawMessage(config, warnFileChanged, filename.string)
  480. else:
  481. rawMessage(config, warnCannotOpenFile, filename.string & " reason: " & $err)
  482. #echo "Error: ", $err, " loading file: ", filename.string
  483. proc toRodFile*(conf: ConfigRef; f: AbsoluteFile; ext = RodExt): AbsoluteFile =
  484. result = changeFileExt(completeGeneratedFilePath(conf,
  485. mangleModuleName(conf, f).AbsoluteFile), ext)
  486. proc loadRodFile*(filename: AbsoluteFile; m: var PackedModule; config: ConfigRef;
  487. ignoreConfig = false): RodFileError =
  488. var f = rodfiles.open(filename.string)
  489. f.loadHeader()
  490. f.loadSection configSection
  491. f.loadPrim m.definedSymbols
  492. f.loadPrim m.moduleFlags
  493. f.loadPrim m.cfg
  494. if f.err == ok and not configIdentical(m, config) and not ignoreConfig:
  495. f.err = configMismatch
  496. template loadSeqSection(section, data) {.dirty.} =
  497. f.loadSection section
  498. f.loadSeq data
  499. template loadTabSection(section, data) {.dirty.} =
  500. f.loadSection section
  501. f.load data
  502. loadTabSection stringsSection, m.strings
  503. loadSeqSection checkSumsSection, m.includes
  504. if not includesIdentical(m, config):
  505. f.err = includeFileChanged
  506. loadSeqSection depsSection, m.imports
  507. loadTabSection numbersSection, m.numbers
  508. loadSeqSection exportsSection, m.exports
  509. loadSeqSection hiddenSection, m.hidden
  510. loadSeqSection reexportsSection, m.reexports
  511. loadSeqSection compilerProcsSection, m.compilerProcs
  512. loadSeqSection trmacrosSection, m.trmacros
  513. loadSeqSection convertersSection, m.converters
  514. loadSeqSection methodsSection, m.methods
  515. loadSeqSection pureEnumsSection, m.pureEnums
  516. loadSeqSection toReplaySection, m.toReplay.nodes
  517. loadSeqSection topLevelSection, m.topLevel.nodes
  518. loadSeqSection bodiesSection, m.bodies.nodes
  519. loadSeqSection symsSection, m.syms
  520. loadSeqSection typesSection, m.types
  521. loadSeqSection typeInstCacheSection, m.typeInstCache
  522. loadSeqSection procInstCacheSection, m.procInstCache
  523. loadSeqSection attachedOpsSection, m.attachedOps
  524. loadSeqSection methodsPerTypeSection, m.methodsPerType
  525. loadSeqSection enumToStringProcsSection, m.enumToStringProcs
  526. loadSeqSection typeInfoSection, m.emittedTypeInfo
  527. f.loadSection backendFlagsSection
  528. f.loadPrim m.backendFlags
  529. close(f)
  530. result = f.err
  531. # -------------------------------------------------------------------------
  532. proc storeError(err: RodFileError; filename: AbsoluteFile) =
  533. echo "Error: ", $err, "; couldn't write to ", filename.string
  534. removeFile(filename.string)
  535. proc saveRodFile*(filename: AbsoluteFile; encoder: var PackedEncoder; m: var PackedModule) =
  536. flush encoder, m
  537. #rememberConfig(encoder, encoder.config)
  538. var f = rodfiles.create(filename.string)
  539. f.storeHeader()
  540. f.storeSection configSection
  541. f.storePrim m.definedSymbols
  542. f.storePrim m.moduleFlags
  543. f.storePrim m.cfg
  544. template storeSeqSection(section, data) {.dirty.} =
  545. f.storeSection section
  546. f.storeSeq data
  547. template storeTabSection(section, data) {.dirty.} =
  548. f.storeSection section
  549. f.store data
  550. storeTabSection stringsSection, m.strings
  551. storeSeqSection checkSumsSection, m.includes
  552. storeSeqSection depsSection, m.imports
  553. storeTabSection numbersSection, m.numbers
  554. storeSeqSection exportsSection, m.exports
  555. storeSeqSection hiddenSection, m.hidden
  556. storeSeqSection reexportsSection, m.reexports
  557. storeSeqSection compilerProcsSection, m.compilerProcs
  558. storeSeqSection trmacrosSection, m.trmacros
  559. storeSeqSection convertersSection, m.converters
  560. storeSeqSection methodsSection, m.methods
  561. storeSeqSection pureEnumsSection, m.pureEnums
  562. storeSeqSection toReplaySection, m.toReplay.nodes
  563. storeSeqSection topLevelSection, m.topLevel.nodes
  564. storeSeqSection bodiesSection, m.bodies.nodes
  565. storeSeqSection symsSection, m.syms
  566. storeSeqSection typesSection, m.types
  567. storeSeqSection typeInstCacheSection, m.typeInstCache
  568. storeSeqSection procInstCacheSection, m.procInstCache
  569. storeSeqSection attachedOpsSection, m.attachedOps
  570. storeSeqSection methodsPerTypeSection, m.methodsPerType
  571. storeSeqSection enumToStringProcsSection, m.enumToStringProcs
  572. storeSeqSection typeInfoSection, m.emittedTypeInfo
  573. f.storeSection backendFlagsSection
  574. f.storePrim m.backendFlags
  575. close(f)
  576. encoder.disable()
  577. if f.err != ok:
  578. storeError(f.err, filename)
  579. when false:
  580. # basic loader testing:
  581. var m2: PackedModule
  582. discard loadRodFile(filename, m2, encoder.config)
  583. echo "loaded ", filename.string
  584. # ----------------------------------------------------------------------------
  585. type
  586. PackedDecoder* = object
  587. lastModule: int
  588. lastLit: LitId
  589. lastFile: FileIndex # remember the last lookup entry.
  590. config*: ConfigRef
  591. cache*: IdentCache
  592. type
  593. ModuleStatus* = enum
  594. undefined,
  595. storing, # state is strictly for stress-testing purposes
  596. loading,
  597. loaded,
  598. outdated,
  599. stored # store is complete, no further additions possible
  600. LoadedModule* = object
  601. status*: ModuleStatus
  602. symsInit, typesInit, loadedButAliveSetChanged*: bool
  603. fromDisk*: PackedModule
  604. syms: seq[PSym] # indexed by itemId
  605. types: seq[PType]
  606. module*: PSym # the one true module symbol.
  607. iface, ifaceHidden: Table[PIdent, seq[PackedItemId]]
  608. # PackedItemId so that it works with reexported symbols too
  609. # ifaceHidden includes private symbols
  610. PackedModuleGraph* = seq[LoadedModule] # indexed by FileIndex
  611. proc loadType(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; t: PackedItemId): PType
  612. proc loadSym(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; s: PackedItemId): PSym
  613. proc toFileIndexCached*(c: var PackedDecoder; g: PackedModuleGraph; thisModule: int; f: LitId): FileIndex =
  614. if c.lastLit == f and c.lastModule == thisModule:
  615. result = c.lastFile
  616. else:
  617. result = toFileIndex(f, g[thisModule].fromDisk, c.config)
  618. c.lastModule = thisModule
  619. c.lastLit = f
  620. c.lastFile = result
  621. proc translateLineInfo(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int;
  622. x: PackedLineInfo): TLineInfo =
  623. assert g[thisModule].status in {loaded, storing, stored}
  624. result = TLineInfo(line: x.line, col: x.col,
  625. fileIndex: toFileIndexCached(c, g, thisModule, x.file))
  626. proc loadNodes*(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int;
  627. tree: PackedTree; n: NodePos): PNode =
  628. let k = n.kind
  629. if k == nkNilRodNode:
  630. return nil
  631. when false:
  632. echo "loading node ", c.config $ translateLineInfo(c, g, thisModule, n.info)
  633. result = newNodeIT(k, translateLineInfo(c, g, thisModule, n.info),
  634. loadType(c, g, thisModule, n.typ))
  635. result.flags = n.flags
  636. case k
  637. of nkEmpty, nkNilLit, nkType:
  638. discard
  639. of nkIdent:
  640. result.ident = getIdent(c.cache, g[thisModule].fromDisk.strings[n.litId])
  641. of nkSym:
  642. result.sym = loadSym(c, g, thisModule, PackedItemId(module: LitId(0), item: tree.nodes[n.int].operand))
  643. of directIntLit:
  644. result.intVal = tree.nodes[n.int].operand
  645. of externIntLit:
  646. result.intVal = g[thisModule].fromDisk.numbers[n.litId]
  647. of nkStrLit..nkTripleStrLit:
  648. result.strVal = g[thisModule].fromDisk.strings[n.litId]
  649. of nkFloatLit..nkFloat128Lit:
  650. result.floatVal = cast[BiggestFloat](g[thisModule].fromDisk.numbers[n.litId])
  651. of nkModuleRef:
  652. let (n1, n2) = sons2(tree, n)
  653. assert n1.kind == nkInt32Lit
  654. assert n2.kind == nkInt32Lit
  655. transitionNoneToSym(result)
  656. result.sym = loadSym(c, g, thisModule, PackedItemId(module: n1.litId, item: tree.nodes[n2.int].operand))
  657. else:
  658. for n0 in sonsReadonly(tree, n):
  659. result.addAllowNil loadNodes(c, g, thisModule, tree, n0)
  660. proc initPackedDecoder*(config: ConfigRef; cache: IdentCache): PackedDecoder =
  661. result = PackedDecoder(
  662. lastModule: int32(-1),
  663. lastLit: LitId(0),
  664. lastFile: FileIndex(-1),
  665. config: config,
  666. cache: cache)
  667. proc loadProcHeader(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int;
  668. tree: PackedTree; n: NodePos): PNode =
  669. # do not load the body of the proc. This will be done later in
  670. # getProcBody, if required.
  671. let k = n.kind
  672. result = newNodeIT(k, translateLineInfo(c, g, thisModule, n.info),
  673. loadType(c, g, thisModule, n.typ))
  674. result.flags = n.flags
  675. assert k in {nkProcDef, nkMethodDef, nkIteratorDef, nkFuncDef, nkConverterDef, nkLambda}
  676. var i = 0
  677. for n0 in sonsReadonly(tree, n):
  678. if i != bodyPos:
  679. result.add loadNodes(c, g, thisModule, tree, n0)
  680. else:
  681. result.addAllowNil nil
  682. inc i
  683. proc loadProcBody(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int;
  684. tree: PackedTree; n: NodePos): PNode =
  685. var i = 0
  686. for n0 in sonsReadonly(tree, n):
  687. if i == bodyPos:
  688. result = loadNodes(c, g, thisModule, tree, n0)
  689. inc i
  690. proc moduleIndex*(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int;
  691. s: PackedItemId): int32 {.inline.} =
  692. result = if s.module == LitId(0): thisModule.int32
  693. else: toFileIndexCached(c, g, thisModule, s.module).int32
  694. proc symHeaderFromPacked(c: var PackedDecoder; g: var PackedModuleGraph;
  695. s: PackedSym; si, item: int32): PSym =
  696. result = PSym(itemId: ItemId(module: si, item: item),
  697. kind: s.kind, magic: s.magic, flags: s.flags,
  698. info: translateLineInfo(c, g, si, s.info),
  699. options: s.options,
  700. position: if s.kind in {skForVar, skVar, skLet, skTemp}: 0 else: s.position,
  701. offset: if s.kind in routineKinds: defaultOffset else: s.offset,
  702. disamb: s.disamb,
  703. name: getIdent(c.cache, g[si].fromDisk.strings[s.name])
  704. )
  705. template loadAstBody(p, field) =
  706. if p.field != emptyNodeId:
  707. result.field = loadNodes(c, g, si, g[si].fromDisk.bodies, NodePos p.field)
  708. template loadAstBodyLazy(p, field) =
  709. if p.field != emptyNodeId:
  710. result.field = loadProcHeader(c, g, si, g[si].fromDisk.bodies, NodePos p.field)
  711. proc loadLib(c: var PackedDecoder; g: var PackedModuleGraph;
  712. si, item: int32; l: PackedLib): PLib =
  713. # XXX: hack; assume a zero LitId means the PackedLib is all zero (empty)
  714. if l.name.int == 0:
  715. result = nil
  716. else:
  717. result = PLib(generated: l.generated, isOverridden: l.isOverridden,
  718. kind: l.kind, name: rope g[si].fromDisk.strings[l.name])
  719. loadAstBody(l, path)
  720. proc symBodyFromPacked(c: var PackedDecoder; g: var PackedModuleGraph;
  721. s: PackedSym; si, item: int32; result: PSym) =
  722. result.typ = loadType(c, g, si, s.typ)
  723. loadAstBody(s, constraint)
  724. if result.kind in {skProc, skFunc, skIterator, skConverter, skMethod}:
  725. loadAstBodyLazy(s, ast)
  726. else:
  727. loadAstBody(s, ast)
  728. result.annex = loadLib(c, g, si, item, s.annex)
  729. when hasFFI:
  730. result.cname = g[si].fromDisk.strings[s.cname]
  731. if s.kind in {skLet, skVar, skField, skForVar}:
  732. result.guard = loadSym(c, g, si, s.guard)
  733. result.bitsize = s.bitsize
  734. result.alignment = s.alignment
  735. result.owner = loadSym(c, g, si, s.owner)
  736. let externalName = g[si].fromDisk.strings[s.externalName]
  737. if externalName != "":
  738. result.loc.r = rope externalName
  739. result.loc.flags = s.locFlags
  740. proc loadSym(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; s: PackedItemId): PSym =
  741. if s == nilItemId:
  742. result = nil
  743. else:
  744. let si = moduleIndex(c, g, thisModule, s)
  745. assert g[si].status in {loaded, storing, stored}
  746. if not g[si].symsInit:
  747. g[si].symsInit = true
  748. setLen g[si].syms, g[si].fromDisk.syms.len
  749. if g[si].syms[s.item] == nil:
  750. if g[si].fromDisk.syms[s.item].kind != skModule:
  751. result = symHeaderFromPacked(c, g, g[si].fromDisk.syms[s.item], si, s.item)
  752. # store it here early on, so that recursions work properly:
  753. g[si].syms[s.item] = result
  754. symBodyFromPacked(c, g, g[si].fromDisk.syms[s.item], si, s.item, result)
  755. else:
  756. result = g[si].module
  757. assert result != nil
  758. else:
  759. result = g[si].syms[s.item]
  760. proc typeHeaderFromPacked(c: var PackedDecoder; g: var PackedModuleGraph;
  761. t: PackedType; si, item: int32): PType =
  762. result = PType(itemId: ItemId(module: si, item: t.nonUniqueId), kind: t.kind,
  763. flags: t.flags, size: t.size, align: t.align,
  764. paddingAtEnd: t.paddingAtEnd,
  765. uniqueId: ItemId(module: si, item: item),
  766. callConv: t.callConv)
  767. proc typeBodyFromPacked(c: var PackedDecoder; g: var PackedModuleGraph;
  768. t: PackedType; si, item: int32; result: PType) =
  769. result.sym = loadSym(c, g, si, t.sym)
  770. result.owner = loadSym(c, g, si, t.owner)
  771. when false:
  772. for op, item in pairs t.attachedOps:
  773. result.attachedOps[op] = loadSym(c, g, si, item)
  774. result.typeInst = loadType(c, g, si, t.typeInst)
  775. for son in items t.types:
  776. result.sons.add loadType(c, g, si, son)
  777. loadAstBody(t, n)
  778. when false:
  779. for gen, id in items t.methods:
  780. result.methods.add((gen, loadSym(c, g, si, id)))
  781. proc loadType(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; t: PackedItemId): PType =
  782. if t == nilItemId:
  783. result = nil
  784. else:
  785. let si = moduleIndex(c, g, thisModule, t)
  786. assert g[si].status in {loaded, storing, stored}
  787. assert t.item > 0
  788. if not g[si].typesInit:
  789. g[si].typesInit = true
  790. setLen g[si].types, g[si].fromDisk.types.len
  791. if g[si].types[t.item] == nil:
  792. result = typeHeaderFromPacked(c, g, g[si].fromDisk.types[t.item], si, t.item)
  793. # store it here early on, so that recursions work properly:
  794. g[si].types[t.item] = result
  795. typeBodyFromPacked(c, g, g[si].fromDisk.types[t.item], si, t.item, result)
  796. else:
  797. result = g[si].types[t.item]
  798. assert result.itemId.item > 0
  799. proc setupLookupTables(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache;
  800. fileIdx: FileIndex; m: var LoadedModule) =
  801. m.iface = initTable[PIdent, seq[PackedItemId]]()
  802. m.ifaceHidden = initTable[PIdent, seq[PackedItemId]]()
  803. template impl(iface, e) =
  804. let nameLit = e[0]
  805. let e2 =
  806. when e[1] is PackedItemId: e[1]
  807. else: PackedItemId(module: LitId(0), item: e[1])
  808. iface.mgetOrPut(cache.getIdent(m.fromDisk.strings[nameLit]), @[]).add(e2)
  809. for e in m.fromDisk.exports:
  810. m.iface.impl(e)
  811. m.ifaceHidden.impl(e)
  812. for e in m.fromDisk.reexports:
  813. m.iface.impl(e)
  814. m.ifaceHidden.impl(e)
  815. for e in m.fromDisk.hidden:
  816. m.ifaceHidden.impl(e)
  817. let filename = AbsoluteFile toFullPath(conf, fileIdx)
  818. # We cannot call ``newSym`` here, because we have to circumvent the ID
  819. # mechanism, which we do in order to assign each module a persistent ID.
  820. m.module = PSym(kind: skModule, itemId: ItemId(module: int32(fileIdx), item: 0'i32),
  821. name: getIdent(cache, splitFile(filename).name),
  822. info: newLineInfo(fileIdx, 1, 1),
  823. position: int(fileIdx))
  824. m.module.owner = getPackage(conf, cache, fileIdx)
  825. m.module.flags = m.fromDisk.moduleFlags
  826. proc loadToReplayNodes(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache;
  827. fileIdx: FileIndex; m: var LoadedModule) =
  828. m.module.ast = newNode(nkStmtList)
  829. if m.fromDisk.toReplay.len > 0:
  830. var decoder = PackedDecoder(
  831. lastModule: int32(-1),
  832. lastLit: LitId(0),
  833. lastFile: FileIndex(-1),
  834. config: conf,
  835. cache: cache)
  836. for p in allNodes(m.fromDisk.toReplay):
  837. m.module.ast.add loadNodes(decoder, g, int(fileIdx), m.fromDisk.toReplay, p)
  838. proc needsRecompile(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache;
  839. fileIdx: FileIndex; cachedModules: var seq[FileIndex]): bool =
  840. # Does the file belong to the fileIdx need to be recompiled?
  841. let m = int(fileIdx)
  842. if m >= g.len:
  843. g.setLen(m+1)
  844. case g[m].status
  845. of undefined:
  846. g[m].status = loading
  847. let fullpath = msgs.toFullPath(conf, fileIdx)
  848. let rod = toRodFile(conf, AbsoluteFile fullpath)
  849. let err = loadRodFile(rod, g[m].fromDisk, conf)
  850. if err == ok:
  851. result = optForceFullMake in conf.globalOptions
  852. # check its dependencies:
  853. for dep in g[m].fromDisk.imports:
  854. let fid = toFileIndex(dep, g[m].fromDisk, conf)
  855. # Warning: we need to traverse the full graph, so
  856. # do **not use break here**!
  857. if needsRecompile(g, conf, cache, fid, cachedModules):
  858. result = true
  859. if not result:
  860. setupLookupTables(g, conf, cache, fileIdx, g[m])
  861. cachedModules.add fileIdx
  862. g[m].status = loaded
  863. else:
  864. g[m] = LoadedModule(status: outdated, module: g[m].module)
  865. else:
  866. loadError(err, rod, conf)
  867. g[m].status = outdated
  868. result = true
  869. when false: loadError(err, rod, conf)
  870. of loading, loaded:
  871. # For loading: Assume no recompile is required.
  872. result = false
  873. of outdated, storing, stored:
  874. result = true
  875. proc moduleFromRodFile*(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache;
  876. fileIdx: FileIndex; cachedModules: var seq[FileIndex]): PSym =
  877. ## Returns 'nil' if the module needs to be recompiled.
  878. if needsRecompile(g, conf, cache, fileIdx, cachedModules):
  879. result = nil
  880. else:
  881. result = g[int fileIdx].module
  882. assert result != nil
  883. assert result.position == int(fileIdx)
  884. for m in cachedModules:
  885. loadToReplayNodes(g, conf, cache, m, g[int m])
  886. template setupDecoder() {.dirty.} =
  887. var decoder = PackedDecoder(
  888. lastModule: int32(-1),
  889. lastLit: LitId(0),
  890. lastFile: FileIndex(-1),
  891. config: config,
  892. cache: cache)
  893. proc loadProcBody*(config: ConfigRef, cache: IdentCache;
  894. g: var PackedModuleGraph; s: PSym): PNode =
  895. let mId = s.itemId.module
  896. var decoder = PackedDecoder(
  897. lastModule: int32(-1),
  898. lastLit: LitId(0),
  899. lastFile: FileIndex(-1),
  900. config: config,
  901. cache: cache)
  902. let pos = g[mId].fromDisk.syms[s.itemId.item].ast
  903. assert pos != emptyNodeId
  904. result = loadProcBody(decoder, g, mId, g[mId].fromDisk.bodies, NodePos pos)
  905. proc loadTypeFromId*(config: ConfigRef, cache: IdentCache;
  906. g: var PackedModuleGraph; module: int; id: PackedItemId): PType =
  907. if id.item < g[module].types.len:
  908. result = g[module].types[id.item]
  909. else:
  910. result = nil
  911. if result == nil:
  912. var decoder = PackedDecoder(
  913. lastModule: int32(-1),
  914. lastLit: LitId(0),
  915. lastFile: FileIndex(-1),
  916. config: config,
  917. cache: cache)
  918. result = loadType(decoder, g, module, id)
  919. proc loadSymFromId*(config: ConfigRef, cache: IdentCache;
  920. g: var PackedModuleGraph; module: int; id: PackedItemId): PSym =
  921. if id.item < g[module].syms.len:
  922. result = g[module].syms[id.item]
  923. else:
  924. result = nil
  925. if result == nil:
  926. var decoder = PackedDecoder(
  927. lastModule: int32(-1),
  928. lastLit: LitId(0),
  929. lastFile: FileIndex(-1),
  930. config: config,
  931. cache: cache)
  932. result = loadSym(decoder, g, module, id)
  933. proc translateId*(id: PackedItemId; g: PackedModuleGraph; thisModule: int; config: ConfigRef): ItemId =
  934. if id.module == LitId(0):
  935. ItemId(module: thisModule.int32, item: id.item)
  936. else:
  937. ItemId(module: toFileIndex(id.module, g[thisModule].fromDisk, config).int32, item: id.item)
  938. proc checkForHoles(m: PackedModule; config: ConfigRef; moduleId: int) =
  939. var bugs = 0
  940. for i in 1 .. high(m.syms):
  941. if m.syms[i].kind == skUnknown:
  942. echo "EMPTY ID ", i, " module ", moduleId, " ", toFullPath(config, FileIndex(moduleId))
  943. inc bugs
  944. assert bugs == 0
  945. when false:
  946. var nones = 0
  947. for i in 1 .. high(m.types):
  948. inc nones, m.types[i].kind == tyNone
  949. assert nones < 1
  950. proc simulateLoadedModule*(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache;
  951. moduleSym: PSym; m: PackedModule) =
  952. # For now only used for heavy debugging. In the future we could use this to reduce the
  953. # compiler's memory consumption.
  954. let idx = moduleSym.position
  955. assert g[idx].status in {storing}
  956. g[idx].status = loaded
  957. assert g[idx].module == moduleSym
  958. setupLookupTables(g, conf, cache, FileIndex(idx), g[idx])
  959. loadToReplayNodes(g, conf, cache, FileIndex(idx), g[idx])
  960. # ---------------- symbol table handling ----------------
  961. type
  962. RodIter* = object
  963. decoder: PackedDecoder
  964. values: seq[PackedItemId]
  965. i, module: int
  966. template interfSelect(a: LoadedModule, importHidden: bool): auto =
  967. var ret = a.iface.addr
  968. if importHidden: ret = a.ifaceHidden.addr
  969. ret[]
  970. proc initRodIter*(it: var RodIter; config: ConfigRef, cache: IdentCache;
  971. g: var PackedModuleGraph; module: FileIndex;
  972. name: PIdent, importHidden: bool): PSym =
  973. it.decoder = PackedDecoder(
  974. lastModule: int32(-1),
  975. lastLit: LitId(0),
  976. lastFile: FileIndex(-1),
  977. config: config,
  978. cache: cache)
  979. it.values = g[int module].interfSelect(importHidden).getOrDefault(name)
  980. it.i = 0
  981. it.module = int(module)
  982. if it.i < it.values.len:
  983. result = loadSym(it.decoder, g, int(module), it.values[it.i])
  984. inc it.i
  985. proc initRodIterAllSyms*(it: var RodIter; config: ConfigRef, cache: IdentCache;
  986. g: var PackedModuleGraph; module: FileIndex, importHidden: bool): PSym =
  987. it.decoder = PackedDecoder(
  988. lastModule: int32(-1),
  989. lastLit: LitId(0),
  990. lastFile: FileIndex(-1),
  991. config: config,
  992. cache: cache)
  993. it.values = @[]
  994. it.module = int(module)
  995. for v in g[int module].interfSelect(importHidden).values:
  996. it.values.add v
  997. it.i = 0
  998. if it.i < it.values.len:
  999. result = loadSym(it.decoder, g, int(module), it.values[it.i])
  1000. inc it.i
  1001. proc nextRodIter*(it: var RodIter; g: var PackedModuleGraph): PSym =
  1002. if it.i < it.values.len:
  1003. result = loadSym(it.decoder, g, it.module, it.values[it.i])
  1004. inc it.i
  1005. iterator interfaceSymbols*(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. for pid in values:
  1011. let s = loadSym(decoder, g, int(module), pid)
  1012. assert s != nil
  1013. yield s
  1014. proc interfaceSymbol*(config: ConfigRef, cache: IdentCache;
  1015. g: var PackedModuleGraph; module: FileIndex;
  1016. name: PIdent, importHidden: bool): PSym =
  1017. setupDecoder()
  1018. let values = g[int module].interfSelect(importHidden).getOrDefault(name)
  1019. result = loadSym(decoder, g, int(module), values[0])
  1020. proc idgenFromLoadedModule*(m: LoadedModule): IdGenerator =
  1021. IdGenerator(module: m.module.itemId.module, symId: int32 m.fromDisk.syms.len,
  1022. typeId: int32 m.fromDisk.types.len)
  1023. proc searchForCompilerproc*(m: LoadedModule; name: string): int32 =
  1024. # slow, linear search, but the results are cached:
  1025. for it in items(m.fromDisk.compilerProcs):
  1026. if m.fromDisk.strings[it[0]] == name:
  1027. return it[1]
  1028. return -1
  1029. # ------------------------- .rod file viewer ---------------------------------
  1030. proc rodViewer*(rodfile: AbsoluteFile; config: ConfigRef, cache: IdentCache) =
  1031. var m: PackedModule
  1032. let err = loadRodFile(rodfile, m, config, ignoreConfig=true)
  1033. if err != ok:
  1034. config.quitOrRaise "Error: could not load: " & $rodfile.string & " reason: " & $err
  1035. when true:
  1036. echo "exports:"
  1037. for ex in m.exports:
  1038. echo " ", m.strings[ex[0]], " local ID: ", ex[1]
  1039. assert ex[0] == m.syms[ex[1]].name
  1040. # ex[1] int32
  1041. echo "reexports:"
  1042. for ex in m.reexports:
  1043. echo " ", m.strings[ex[0]]
  1044. # reexports*: seq[(LitId, PackedItemId)]
  1045. echo "hidden: " & $m.hidden.len
  1046. for ex in m.hidden:
  1047. echo " ", m.strings[ex[0]], " local ID: ", ex[1]
  1048. echo "all symbols"
  1049. for i in 0..high(m.syms):
  1050. if m.syms[i].name != LitId(0):
  1051. echo " ", m.strings[m.syms[i].name], " local ID: ", i, " kind ", m.syms[i].kind
  1052. else:
  1053. echo " <anon symbol?> local ID: ", i, " kind ", m.syms[i].kind
  1054. echo "symbols: ", m.syms.len, " types: ", m.types.len,
  1055. " top level nodes: ", m.topLevel.nodes.len, " other nodes: ", m.bodies.nodes.len,
  1056. " strings: ", m.strings.len, " numbers: ", m.numbers.len