ic.nim 44 KB

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