cgen.nim 59 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2015 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ## This module implements the C code generator.
  10. import
  11. ast, astalgo, hashes, trees, platform, magicsys, extccomp, options, intsets,
  12. nversion, nimsets, msgs, std / sha1, bitsets, idents, types,
  13. ccgutils, os, ropes, math, passes, wordrecg, treetab, cgmeth,
  14. condsyms, rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases,
  15. lowerings, semparallel, tables, sets, ndi, lineinfos, pathutils, transf
  16. import strutils except `%` # collides with ropes.`%`
  17. from modulegraphs import ModuleGraph, PPassContext
  18. from lineinfos import
  19. warnGcMem, errXMustBeCompileTime, hintDependency, errGenerated, errCannotOpenFile
  20. import dynlib
  21. when not declared(dynlib.libCandidates):
  22. proc libCandidates(s: string, dest: var seq[string]) =
  23. ## given a library name pattern `s` write possible library names to `dest`.
  24. var le = strutils.find(s, '(')
  25. var ri = strutils.find(s, ')', le+1)
  26. if le >= 0 and ri > le:
  27. var prefix = substr(s, 0, le - 1)
  28. var suffix = substr(s, ri + 1)
  29. for middle in split(substr(s, le + 1, ri - 1), '|'):
  30. libCandidates(prefix & middle & suffix, dest)
  31. else:
  32. add(dest, s)
  33. when options.hasTinyCBackend:
  34. import tccgen
  35. # implementation
  36. proc addForwardedProc(m: BModule, prc: PSym) =
  37. m.forwardedProcs.add(prc)
  38. inc(m.g.forwardedProcsCounter)
  39. proc findPendingModule(m: BModule, s: PSym): BModule =
  40. var ms = getModule(s)
  41. result = m.g.modules[ms.position]
  42. proc initLoc(result: var TLoc, k: TLocKind, lode: PNode, s: TStorageLoc) =
  43. result.k = k
  44. result.storage = s
  45. result.lode = lode
  46. result.r = nil
  47. result.flags = {}
  48. proc fillLoc(a: var TLoc, k: TLocKind, lode: PNode, r: Rope, s: TStorageLoc) =
  49. # fills the loc if it is not already initialized
  50. if a.k == locNone:
  51. a.k = k
  52. a.lode = lode
  53. a.storage = s
  54. if a.r == nil: a.r = r
  55. proc t(a: TLoc): PType {.inline.} =
  56. if a.lode.kind == nkSym:
  57. result = a.lode.sym.typ
  58. else:
  59. result = a.lode.typ
  60. proc lodeTyp(t: PType): PNode =
  61. result = newNode(nkEmpty)
  62. result.typ = t
  63. proc isSimpleConst(typ: PType): bool =
  64. let t = skipTypes(typ, abstractVar)
  65. result = t.kind notin
  66. {tyTuple, tyObject, tyArray, tySet, tySequence} and not
  67. (t.kind == tyProc and t.callConv == ccClosure)
  68. proc useHeader(m: BModule, sym: PSym) =
  69. if lfHeader in sym.loc.flags:
  70. assert(sym.annex != nil)
  71. let str = getStr(sym.annex.path)
  72. m.includeHeader(str)
  73. proc cgsym(m: BModule, name: string): Rope
  74. proc ropecg(m: BModule, frmt: FormatStr, args: varargs[Rope]): Rope =
  75. assert m != nil
  76. var i = 0
  77. var length = len(frmt)
  78. result = nil
  79. var num = 0
  80. while i < length:
  81. if frmt[i] == '$':
  82. inc(i) # skip '$'
  83. case frmt[i]
  84. of '$':
  85. add(result, "$")
  86. inc(i)
  87. of '#':
  88. inc(i)
  89. add(result, args[num])
  90. inc(num)
  91. of '0'..'9':
  92. var j = 0
  93. while true:
  94. j = (j * 10) + ord(frmt[i]) - ord('0')
  95. inc(i)
  96. if i >= length or not (frmt[i] in {'0'..'9'}): break
  97. num = j
  98. if j > high(args) + 1:
  99. internalError(m.config, "ropes: invalid format string $" & $j)
  100. add(result, args[j-1])
  101. of 'n':
  102. if optLineDir notin m.config.options: add(result, "\L")
  103. inc(i)
  104. of 'N':
  105. add(result, "\L")
  106. inc(i)
  107. else: internalError(m.config, "ropes: invalid format string $" & frmt[i])
  108. elif frmt[i] == '#' and frmt[i+1] in IdentStartChars:
  109. inc(i)
  110. var j = i
  111. while frmt[j] in IdentChars: inc(j)
  112. var ident = substr(frmt, i, j-1)
  113. i = j
  114. add(result, cgsym(m, ident))
  115. elif frmt[i] == '#' and frmt[i+1] == '$':
  116. inc(i, 2)
  117. var j = 0
  118. while frmt[i] in Digits:
  119. j = (j * 10) + ord(frmt[i]) - ord('0')
  120. inc(i)
  121. add(result, cgsym(m, $args[j-1]))
  122. var start = i
  123. while i < length:
  124. if frmt[i] != '$' and frmt[i] != '#': inc(i)
  125. else: break
  126. if i - 1 >= start:
  127. add(result, substr(frmt, start, i - 1))
  128. proc indentLine(p: BProc, r: Rope): Rope =
  129. result = r
  130. for i in countup(0, p.blocks.len-1):
  131. prepend(result, "\t".rope)
  132. proc appcg(m: BModule, c: var Rope, frmt: FormatStr,
  133. args: varargs[Rope]) =
  134. add(c, ropecg(m, frmt, args))
  135. proc appcg(m: BModule, s: TCFileSection, frmt: FormatStr,
  136. args: varargs[Rope]) =
  137. add(m.s[s], ropecg(m, frmt, args))
  138. proc appcg(p: BProc, s: TCProcSection, frmt: FormatStr,
  139. args: varargs[Rope]) =
  140. add(p.s(s), ropecg(p.module, frmt, args))
  141. proc line(p: BProc, s: TCProcSection, r: Rope) =
  142. add(p.s(s), indentLine(p, r))
  143. proc line(p: BProc, s: TCProcSection, r: string) =
  144. add(p.s(s), indentLine(p, r.rope))
  145. proc lineF(p: BProc, s: TCProcSection, frmt: FormatStr,
  146. args: openarray[Rope]) =
  147. add(p.s(s), indentLine(p, frmt % args))
  148. proc lineCg(p: BProc, s: TCProcSection, frmt: FormatStr,
  149. args: varargs[Rope]) =
  150. add(p.s(s), indentLine(p, ropecg(p.module, frmt, args)))
  151. proc linefmt(p: BProc, s: TCProcSection, frmt: FormatStr,
  152. args: varargs[Rope]) =
  153. add(p.s(s), indentLine(p, ropecg(p.module, frmt, args)))
  154. proc safeLineNm(info: TLineInfo): int =
  155. result = toLinenumber(info)
  156. if result < 0: result = 0 # negative numbers are not allowed in #line
  157. proc genCLineDir(r: var Rope, filename: string, line: int; conf: ConfigRef) =
  158. assert line >= 0
  159. if optLineDir in conf.options:
  160. addf(r, "$N#line $2 $1$N",
  161. [rope(makeSingleLineCString(filename)), rope(line)])
  162. proc genCLineDir(r: var Rope, info: TLineInfo; conf: ConfigRef) =
  163. genCLineDir(r, toFullPath(conf, info), info.safeLineNm, conf)
  164. proc freshLineInfo(p: BProc; info: TLineInfo): bool =
  165. if p.lastLineInfo.line != info.line or
  166. p.lastLineInfo.fileIndex != info.fileIndex:
  167. p.lastLineInfo.line = info.line
  168. p.lastLineInfo.fileIndex = info.fileIndex
  169. result = true
  170. proc genLineDir(p: BProc, t: PNode) =
  171. let line = t.info.safeLineNm
  172. if optEmbedOrigSrc in p.config.globalOptions:
  173. add(p.s(cpsStmts), ~"//" & sourceLine(p.config, t.info) & "\L")
  174. genCLineDir(p.s(cpsStmts), toFullPath(p.config, t.info), line, p.config)
  175. if ({optStackTrace, optEndb} * p.options == {optStackTrace, optEndb}) and
  176. (p.prc == nil or sfPure notin p.prc.flags):
  177. if freshLineInfo(p, t.info):
  178. linefmt(p, cpsStmts, "#endb($1, $2);$N",
  179. line.rope, makeCString(toFilename(p.config, t.info)))
  180. elif ({optLineTrace, optStackTrace} * p.options ==
  181. {optLineTrace, optStackTrace}) and
  182. (p.prc == nil or sfPure notin p.prc.flags) and t.info.fileIndex != InvalidFileIDX:
  183. if freshLineInfo(p, t.info):
  184. linefmt(p, cpsStmts, "nimln_($1, $2);$n",
  185. line.rope, quotedFilename(p.config, t.info))
  186. proc postStmtActions(p: BProc) {.inline.} =
  187. add(p.s(cpsStmts), p.module.injectStmt)
  188. proc accessThreadLocalVar(p: BProc, s: PSym)
  189. proc emulatedThreadVars(conf: ConfigRef): bool {.inline.}
  190. proc genProc(m: BModule, prc: PSym)
  191. template compileToCpp(m: BModule): untyped =
  192. m.config.cmd == cmdCompileToCpp or sfCompileToCpp in m.module.flags
  193. proc getTempName(m: BModule): Rope =
  194. result = m.tmpBase & rope(m.labels)
  195. inc m.labels
  196. proc rdLoc(a: TLoc): Rope =
  197. # 'read' location (deref if indirect)
  198. result = a.r
  199. if lfIndirect in a.flags: result = "(*$1)" % [result]
  200. proc lenField(p: BProc): Rope =
  201. result = rope(if p.module.compileToCpp: "len" else: "Sup.len")
  202. proc lenExpr(p: BProc; a: TLoc): Rope =
  203. if p.config.selectedGc == gcDestructors:
  204. result = rdLoc(a) & ".len"
  205. else:
  206. result = "($1 ? $1->$2 : 0)" % [rdLoc(a), lenField(p)]
  207. proc dataField(p: BProc): Rope =
  208. if p.config.selectedGc == gcDestructors:
  209. result = rope".p->data"
  210. else:
  211. result = rope"->data"
  212. include ccgliterals
  213. include ccgtypes
  214. include ccg_precise_stacks
  215. # ------------------------------ Manager of temporaries ------------------
  216. proc addrLoc(conf: ConfigRef; a: TLoc): Rope =
  217. result = a.r
  218. if lfIndirect notin a.flags and mapType(conf, a.t) != ctArray:
  219. result = "(&" & result & ")"
  220. proc rdCharLoc(a: TLoc): Rope =
  221. # read a location that may need a char-cast:
  222. result = rdLoc(a)
  223. if skipTypes(a.t, abstractRange).kind == tyChar:
  224. result = "((NU8)($1))" % [result]
  225. proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc,
  226. takeAddr: bool) =
  227. if p.module.compileToCpp and t.isException and not isDefined(p.config, "noCppExceptions"):
  228. # init vtable in Exception object for polymorphic exceptions
  229. includeHeader(p.module, "<new>")
  230. linefmt(p, section, "new ($1) $2;$n", rdLoc(a), getTypeDesc(p.module, t))
  231. case analyseObjectWithTypeField(t)
  232. of frNone:
  233. discard
  234. of frHeader:
  235. var r = rdLoc(a)
  236. if not takeAddr: r = "(*$1)" % [r]
  237. var s = skipTypes(t, abstractInst)
  238. if not p.module.compileToCpp:
  239. while (s.kind == tyObject) and (s.sons[0] != nil):
  240. add(r, ".Sup")
  241. s = skipTypes(s.sons[0], skipPtrs)
  242. linefmt(p, section, "$1.m_type = $2;$n", r, genTypeInfo(p.module, t, a.lode.info))
  243. of frEmbedded:
  244. # worst case for performance:
  245. var r = if takeAddr: addrLoc(p.config, a) else: rdLoc(a)
  246. linefmt(p, section, "#objectInit($1, $2);$n", r, genTypeInfo(p.module, t, a.lode.info))
  247. type
  248. TAssignmentFlag = enum
  249. needToCopy, afDestIsNil, afDestIsNotNil, afSrcIsNil, afSrcIsNotNil
  250. TAssignmentFlags = set[TAssignmentFlag]
  251. proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags)
  252. proc isComplexValueType(t: PType): bool {.inline.} =
  253. let t = t.skipTypes(abstractInst + tyUserTypeClasses)
  254. result = t.kind in {tyArray, tySet, tyTuple, tyObject} or
  255. (t.kind == tyProc and t.callConv == ccClosure)
  256. proc resetLoc(p: BProc, loc: var TLoc) =
  257. let containsGcRef = containsGarbageCollectedRef(loc.t)
  258. let typ = skipTypes(loc.t, abstractVarRange)
  259. if isImportedCppType(typ): return
  260. if not isComplexValueType(typ):
  261. if containsGcRef:
  262. var nilLoc: TLoc
  263. initLoc(nilLoc, locTemp, loc.lode, OnStack)
  264. nilLoc.r = rope("NIM_NIL")
  265. genRefAssign(p, loc, nilLoc, {afSrcIsNil})
  266. else:
  267. linefmt(p, cpsStmts, "$1 = 0;$n", rdLoc(loc))
  268. else:
  269. if optNilCheck in p.options:
  270. linefmt(p, cpsStmts, "#chckNil((void*)$1);$n", addrLoc(p.config, loc))
  271. if loc.storage != OnStack:
  272. linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
  273. addrLoc(p.config, loc), genTypeInfo(p.module, loc.t, loc.lode.info))
  274. # XXX: generated reset procs should not touch the m_type
  275. # field, so disabling this should be safe:
  276. genObjectInit(p, cpsStmts, loc.t, loc, true)
  277. else:
  278. # array passed as argument decayed into pointer, bug #7332
  279. # so we use getTypeDesc here rather than rdLoc(loc)
  280. linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));$n",
  281. addrLoc(p.config, loc), getTypeDesc(p.module, loc.t))
  282. # XXX: We can be extra clever here and call memset only
  283. # on the bytes following the m_type field?
  284. genObjectInit(p, cpsStmts, loc.t, loc, true)
  285. proc constructLoc(p: BProc, loc: TLoc, isTemp = false) =
  286. let typ = loc.t
  287. if p.config.selectedGc == gcDestructors and skipTypes(typ, abstractInst).kind in {tyString, tySequence}:
  288. linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", rdLoc(loc))
  289. elif not isComplexValueType(typ):
  290. linefmt(p, cpsStmts, "$1 = ($2)0;$n", rdLoc(loc),
  291. getTypeDesc(p.module, typ))
  292. else:
  293. if not isTemp or containsGarbageCollectedRef(loc.t):
  294. # don't use nimZeroMem for temporary values for performance if we can
  295. # avoid it:
  296. if not isImportedCppType(typ):
  297. linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));$n",
  298. addrLoc(p.config, loc), getTypeDesc(p.module, typ))
  299. genObjectInit(p, cpsStmts, loc.t, loc, true)
  300. proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
  301. if sfNoInit notin v.flags:
  302. # we know it is a local variable and thus on the stack!
  303. # If ``not immediateAsgn`` it is not initialized in a binding like
  304. # ``var v = X`` and thus we need to init it.
  305. # If ``v`` contains a GC-ref we may pass it to ``unsureAsgnRef`` somehow
  306. # which requires initialization. However this can really only happen if
  307. # ``var v = X()`` gets transformed into ``X(&v)``.
  308. # Nowadays the logic in ccgcalls deals with this case however.
  309. if not immediateAsgn:
  310. constructLoc(p, v.loc)
  311. proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) =
  312. inc(p.labels)
  313. result.r = "T" & rope(p.labels) & "_"
  314. if preciseStackRoots(p.module) > 0 and containsGarbageCollectedRef(t):
  315. declarePreciseStackRoot(p, t, result.r)
  316. else:
  317. linefmt(p, cpsLocals, "$1 $2;$n", getTypeDesc(p.module, t), result.r)
  318. result.k = locTemp
  319. result.lode = lodeTyp t
  320. result.storage = OnStack
  321. result.flags = {}
  322. constructLoc(p, result, not needsInit)
  323. proc getIntTemp(p: BProc, result: var TLoc) =
  324. inc(p.labels)
  325. result.r = "T" & rope(p.labels) & "_"
  326. linefmt(p, cpsLocals, "NI $1;$n", result.r)
  327. result.k = locTemp
  328. result.storage = OnStack
  329. result.lode = lodeTyp getSysType(p.module.g.graph, unknownLineInfo(), tyInt)
  330. result.flags = {}
  331. proc localDebugInfo(p: BProc, s: PSym) =
  332. if {optStackTrace, optEndb} * p.options != {optStackTrace, optEndb}: return
  333. # XXX work around a bug: No type information for open arrays possible:
  334. if skipTypes(s.typ, abstractVar).kind in {tyOpenArray, tyVarargs}: return
  335. var a = "&" & s.loc.r
  336. if s.kind == skParam and ccgIntroducedPtr(p.config, s): a = s.loc.r
  337. lineF(p, cpsInit,
  338. "FR_.s[$1].address = (void*)$3; FR_.s[$1].typ = $4; FR_.s[$1].name = $2;$n",
  339. [p.maxFrameLen.rope, makeCString(normalize(s.name.s)), a,
  340. genTypeInfo(p.module, s.loc.t, s.info)])
  341. inc(p.maxFrameLen)
  342. inc p.blocks[p.blocks.len-1].frameLen
  343. proc localVarDecl(p: BProc; n: PNode): Rope =
  344. let s = n.sym
  345. if s.loc.k == locNone:
  346. fillLoc(s.loc, locLocalVar, n, mangleLocalName(p, s), OnStack)
  347. if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy)
  348. result = getTypeDesc(p.module, s.typ)
  349. if s.constraint.isNil:
  350. if sfRegister in s.flags: add(result, " register")
  351. #elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds:
  352. # add(decl, " GC_GUARD")
  353. if sfVolatile in s.flags: add(result, " volatile")
  354. add(result, " ")
  355. add(result, s.loc.r)
  356. else:
  357. result = s.cgDeclFrmt % [result, s.loc.r]
  358. proc assignLocalVar(p: BProc, n: PNode) =
  359. #assert(s.loc.k == locNone) # not yet assigned
  360. # this need not be fulfilled for inline procs; they are regenerated
  361. # for each module that uses them!
  362. let nl = if optLineDir in p.config.options: "" else: "\L"
  363. let decl = localVarDecl(p, n) & ";" & nl
  364. line(p, cpsLocals, decl)
  365. localDebugInfo(p, n.sym)
  366. include ccgthreadvars
  367. proc varInDynamicLib(m: BModule, sym: PSym)
  368. proc mangleDynLibProc(sym: PSym): Rope
  369. proc assignGlobalVar(p: BProc, n: PNode) =
  370. let s = n.sym
  371. if s.loc.k == locNone:
  372. fillLoc(s.loc, locGlobalVar, n, mangleName(p.module, s), OnHeap)
  373. if lfDynamicLib in s.loc.flags:
  374. var q = findPendingModule(p.module, s)
  375. if q != nil and not containsOrIncl(q.declaredThings, s.id):
  376. varInDynamicLib(q, s)
  377. else:
  378. s.loc.r = mangleDynLibProc(s)
  379. return
  380. useHeader(p.module, s)
  381. if lfNoDecl in s.loc.flags: return
  382. if sfThread in s.flags:
  383. declareThreadVar(p.module, s, sfImportc in s.flags)
  384. else:
  385. var decl: Rope = nil
  386. var td = getTypeDesc(p.module, s.loc.t)
  387. if s.constraint.isNil:
  388. if sfImportc in s.flags: add(decl, "extern ")
  389. add(decl, td)
  390. if sfRegister in s.flags: add(decl, " register")
  391. if sfVolatile in s.flags: add(decl, " volatile")
  392. addf(decl, " $1;$n", [s.loc.r])
  393. else:
  394. decl = (s.cgDeclFrmt & ";$n") % [td, s.loc.r]
  395. add(p.module.s[cfsVars], decl)
  396. if p.withinLoop > 0:
  397. # fixes tests/run/tzeroarray:
  398. resetLoc(p, s.loc)
  399. if p.module.module.options * {optStackTrace, optEndb} ==
  400. {optStackTrace, optEndb}:
  401. appcg(p.module, p.module.s[cfsDebugInit],
  402. "#dbgRegisterGlobal($1, &$2, $3);$n",
  403. [makeCString(normalize(s.owner.name.s & '.' & s.name.s)),
  404. s.loc.r, genTypeInfo(p.module, s.typ, n.info)])
  405. proc assignParam(p: BProc, s: PSym) =
  406. assert(s.loc.r != nil)
  407. scopeMangledParam(p, s)
  408. localDebugInfo(p, s)
  409. proc fillProcLoc(m: BModule; n: PNode) =
  410. let sym = n.sym
  411. if sym.loc.k == locNone:
  412. fillLoc(sym.loc, locProc, n, mangleName(m, sym), OnStack)
  413. proc getLabel(p: BProc): TLabel =
  414. inc(p.labels)
  415. result = "LA" & rope(p.labels) & "_"
  416. proc fixLabel(p: BProc, labl: TLabel) =
  417. lineF(p, cpsStmts, "$1: ;$n", [labl])
  418. proc genVarPrototype(m: BModule, n: PNode)
  419. proc requestConstImpl(p: BProc, sym: PSym)
  420. proc genStmts(p: BProc, t: PNode)
  421. proc expr(p: BProc, n: PNode, d: var TLoc)
  422. proc genProcPrototype(m: BModule, sym: PSym)
  423. proc putLocIntoDest(p: BProc, d: var TLoc, s: TLoc)
  424. proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags)
  425. proc intLiteral(i: BiggestInt): Rope
  426. proc genLiteral(p: BProc, n: PNode): Rope
  427. proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType): Rope
  428. proc initLocExpr(p: BProc, e: PNode, result: var TLoc) =
  429. initLoc(result, locNone, e, OnUnknown)
  430. expr(p, e, result)
  431. proc initLocExprSingleUse(p: BProc, e: PNode, result: var TLoc) =
  432. initLoc(result, locNone, e, OnUnknown)
  433. result.flags.incl lfSingleUse
  434. expr(p, e, result)
  435. include ccgcalls, "ccgstmts.nim"
  436. proc initFrame(p: BProc, procname, filename: Rope): Rope =
  437. discard cgsym(p.module, "nimFrame")
  438. if p.maxFrameLen > 0:
  439. discard cgsym(p.module, "VarSlot")
  440. result = ropecg(p.module, "\tnimfrs_($1, $2, $3, $4);$n",
  441. procname, filename, p.maxFrameLen.rope,
  442. p.blocks[0].frameLen.rope)
  443. else:
  444. result = ropecg(p.module, "\tnimfr_($1, $2);$n", procname, filename)
  445. proc initFrameNoDebug(p: BProc; frame, procname, filename: Rope; line: int): Rope =
  446. discard cgsym(p.module, "nimFrame")
  447. addf(p.blocks[0].sections[cpsLocals], "TFrame $1;$n", [frame])
  448. result = ropecg(p.module, "\t$1.procname = $2; $1.filename = $3; " &
  449. " $1.line = $4; $1.len = -1; nimFrame(&$1);$n",
  450. frame, procname, filename, rope(line))
  451. proc deinitFrameNoDebug(p: BProc; frame: Rope): Rope =
  452. result = ropecg(p.module, "\t#popFrameOfAddr(&$1);$n", frame)
  453. proc deinitFrame(p: BProc): Rope =
  454. result = ropecg(p.module, "\t#popFrame();$n")
  455. include ccgexprs
  456. # ----------------------------- dynamic library handling -----------------
  457. # We don't finalize dynamic libs as the OS does this for us.
  458. proc isGetProcAddr(lib: PLib): bool =
  459. let n = lib.path
  460. result = n.kind in nkCallKinds and n.typ != nil and
  461. n.typ.kind in {tyPointer, tyProc}
  462. proc loadDynamicLib(m: BModule, lib: PLib) =
  463. assert(lib != nil)
  464. if not lib.generated:
  465. lib.generated = true
  466. var tmp = getTempName(m)
  467. assert(lib.name == nil)
  468. lib.name = tmp # BUGFIX: cgsym has awful side-effects
  469. addf(m.s[cfsVars], "static void* $1;$n", [tmp])
  470. if lib.path.kind in {nkStrLit..nkTripleStrLit}:
  471. var s: TStringSeq = @[]
  472. libCandidates(lib.path.strVal, s)
  473. rawMessage(m.config, hintDependency, lib.path.strVal)
  474. var loadlib: Rope = nil
  475. for i in countup(0, high(s)):
  476. inc(m.labels)
  477. if i > 0: add(loadlib, "||")
  478. let n = newStrNode(nkStrLit, s[i])
  479. n.info = lib.path.info
  480. appcg(m, loadlib, "($1 = #nimLoadLibrary($2))$n",
  481. [tmp, genStringLiteral(m, n)])
  482. appcg(m, m.s[cfsDynLibInit],
  483. "if (!($1)) #nimLoadLibraryError($2);$n",
  484. [loadlib, genStringLiteral(m, lib.path)])
  485. else:
  486. var p = newProc(nil, m)
  487. p.options = p.options - {optStackTrace, optEndb}
  488. var dest: TLoc
  489. initLoc(dest, locTemp, lib.path, OnStack)
  490. dest.r = getTempName(m)
  491. appcg(m, m.s[cfsDynLibInit],"$1 $2;$n",
  492. [getTypeDesc(m, lib.path.typ), rdLoc(dest)])
  493. expr(p, lib.path, dest)
  494. add(m.s[cfsVars], p.s(cpsLocals))
  495. add(m.s[cfsDynLibInit], p.s(cpsInit))
  496. add(m.s[cfsDynLibInit], p.s(cpsStmts))
  497. appcg(m, m.s[cfsDynLibInit],
  498. "if (!($1 = #nimLoadLibrary($2))) #nimLoadLibraryError($2);$n",
  499. [tmp, rdLoc(dest)])
  500. if lib.name == nil: internalError(m.config, "loadDynamicLib")
  501. proc mangleDynLibProc(sym: PSym): Rope =
  502. # we have to build this as a single rope in order not to trip the
  503. # optimization in genInfixCall
  504. if sfCompilerProc in sym.flags:
  505. # NOTE: sym.loc.r is the external name!
  506. result = rope(sym.name.s)
  507. else:
  508. result = rope(strutils.`%`("Dl_$1_", $sym.id))
  509. proc symInDynamicLib(m: BModule, sym: PSym) =
  510. var lib = sym.annex
  511. let isCall = isGetProcAddr(lib)
  512. var extname = sym.loc.r
  513. if not isCall: loadDynamicLib(m, lib)
  514. var tmp = mangleDynLibProc(sym)
  515. sym.loc.r = tmp # from now on we only need the internal name
  516. sym.typ.sym = nil # generate a new name
  517. inc(m.labels, 2)
  518. if isCall:
  519. let n = lib.path
  520. var a: TLoc
  521. initLocExpr(m.initProc, n[0], a)
  522. var params = rdLoc(a) & "("
  523. for i in 1 .. n.len-2:
  524. initLocExpr(m.initProc, n[i], a)
  525. params.add(rdLoc(a))
  526. params.add(", ")
  527. let load = "\t$1 = ($2) ($3$4));$n" %
  528. [tmp, getTypeDesc(m, sym.typ), params, makeCString($extname)]
  529. var last = lastSon(n)
  530. if last.kind == nkHiddenStdConv: last = last.sons[1]
  531. internalAssert(m.config, last.kind == nkStrLit)
  532. let idx = last.strVal
  533. if idx.len == 0:
  534. add(m.initProc.s(cpsStmts), load)
  535. elif idx.len == 1 and idx[0] in {'0'..'9'}:
  536. add(m.extensionLoaders[idx[0]], load)
  537. else:
  538. internalError(m.config, sym.info, "wrong index: " & idx)
  539. else:
  540. appcg(m, m.s[cfsDynLibInit],
  541. "\t$1 = ($2) #nimGetProcAddr($3, $4);$n",
  542. [tmp, getTypeDesc(m, sym.typ), lib.name, makeCString($extname)])
  543. addf(m.s[cfsVars], "$2 $1;$n", [sym.loc.r, getTypeDesc(m, sym.loc.t)])
  544. proc varInDynamicLib(m: BModule, sym: PSym) =
  545. var lib = sym.annex
  546. var extname = sym.loc.r
  547. loadDynamicLib(m, lib)
  548. incl(sym.loc.flags, lfIndirect)
  549. var tmp = mangleDynLibProc(sym)
  550. sym.loc.r = tmp # from now on we only need the internal name
  551. inc(m.labels, 2)
  552. appcg(m, m.s[cfsDynLibInit],
  553. "$1 = ($2*) #nimGetProcAddr($3, $4);$n",
  554. [tmp, getTypeDesc(m, sym.typ), lib.name, makeCString($extname)])
  555. addf(m.s[cfsVars], "$2* $1;$n",
  556. [sym.loc.r, getTypeDesc(m, sym.loc.t)])
  557. proc symInDynamicLibPartial(m: BModule, sym: PSym) =
  558. sym.loc.r = mangleDynLibProc(sym)
  559. sym.typ.sym = nil # generate a new name
  560. proc cgsym(m: BModule, name: string): Rope =
  561. let sym = magicsys.getCompilerProc(m.g.graph, name)
  562. if sym != nil:
  563. case sym.kind
  564. of skProc, skFunc, skMethod, skConverter, skIterator: genProc(m, sym)
  565. of skVar, skResult, skLet: genVarPrototype(m, newSymNode sym)
  566. of skType: discard getTypeDesc(m, sym.typ)
  567. else: internalError(m.config, "cgsym: " & name & ": " & $sym.kind)
  568. else:
  569. # we used to exclude the system module from this check, but for DLL
  570. # generation support this sloppyness leads to hard to detect bugs, so
  571. # we're picky here for the system module too:
  572. rawMessage(m.config, errGenerated, "system module needs: " & name)
  573. result = sym.loc.r
  574. proc generateHeaders(m: BModule) =
  575. add(m.s[cfsHeaders], "\L#include \"nimbase.h\"\L")
  576. for it in m.headerFiles:
  577. if it[0] == '#':
  578. add(m.s[cfsHeaders], rope(it.replace('`', '"') & "\L"))
  579. elif it[0] notin {'\"', '<'}:
  580. addf(m.s[cfsHeaders], "#include \"$1\"$N", [rope(it)])
  581. else:
  582. addf(m.s[cfsHeaders], "#include $1$N", [rope(it)])
  583. add(m.s[cfsHeaders], "#undef LANGUAGE_C\L")
  584. add(m.s[cfsHeaders], "#undef MIPSEB\L")
  585. add(m.s[cfsHeaders], "#undef MIPSEL\L")
  586. add(m.s[cfsHeaders], "#undef PPC\L")
  587. add(m.s[cfsHeaders], "#undef R3000\L")
  588. add(m.s[cfsHeaders], "#undef R4000\L")
  589. add(m.s[cfsHeaders], "#undef i386\L")
  590. add(m.s[cfsHeaders], "#undef linux\L")
  591. add(m.s[cfsHeaders], "#undef mips\L")
  592. add(m.s[cfsHeaders], "#undef near\L")
  593. add(m.s[cfsHeaders], "#undef far\L")
  594. add(m.s[cfsHeaders], "#undef powerpc\L")
  595. add(m.s[cfsHeaders], "#undef unix\L")
  596. proc openNamespaceNim(namespace: string): Rope =
  597. result.add("namespace ")
  598. result.add(namespace)
  599. result.add(" {\L")
  600. proc closeNamespaceNim(): Rope =
  601. result.add("}\L")
  602. proc closureSetup(p: BProc, prc: PSym) =
  603. if tfCapturesEnv notin prc.typ.flags: return
  604. # prc.ast[paramsPos].last contains the type we're after:
  605. var ls = lastSon(prc.ast[paramsPos])
  606. if ls.kind != nkSym:
  607. internalError(p.config, prc.info, "closure generation failed")
  608. var env = ls.sym
  609. #echo "created environment: ", env.id, " for ", prc.name.s
  610. assignLocalVar(p, ls)
  611. # generate cast assignment:
  612. if p.config.selectedGC == gcGo:
  613. linefmt(p, cpsStmts, "#unsureAsgnRef((void**) $1, ($2) ClE_0);$n",
  614. addrLoc(p.config, env.loc), getTypeDesc(p.module, env.typ))
  615. else:
  616. linefmt(p, cpsStmts, "$1 = ($2) ClE_0;$n",
  617. rdLoc(env.loc), getTypeDesc(p.module, env.typ))
  618. proc containsResult(n: PNode): bool =
  619. if n.kind == nkSym and n.sym.kind == skResult:
  620. result = true
  621. else:
  622. for i in 0..<n.safeLen:
  623. if containsResult(n[i]): return true
  624. const harmless = {nkConstSection, nkTypeSection, nkEmpty, nkCommentStmt, nkTemplateDef, nkMacroDef} +
  625. declarativeDefs
  626. proc easyResultAsgn(n: PNode): PNode =
  627. case n.kind
  628. of nkStmtList, nkStmtListExpr:
  629. var i = 0
  630. while i < n.len and n[i].kind in harmless: inc i
  631. if i < n.len: result = easyResultAsgn(n[i])
  632. of nkAsgn, nkFastAsgn:
  633. if n[0].kind == nkSym and n[0].sym.kind == skResult and not containsResult(n[1]):
  634. incl n.flags, nfPreventCg
  635. return n[1]
  636. of nkReturnStmt:
  637. if n.len > 0:
  638. result = easyResultAsgn(n[0])
  639. if result != nil: incl n.flags, nfPreventCg
  640. else: discard
  641. type
  642. InitResultEnum = enum Unknown, InitSkippable, InitRequired
  643. proc allPathsAsgnResult(n: PNode): InitResultEnum =
  644. # Exceptions coming from calls don't have not be considered here:
  645. #
  646. # proc bar(): string = raise newException(...)
  647. #
  648. # proc foo(): string =
  649. # # optimized out: 'reset(result)'
  650. # result = bar()
  651. #
  652. # try:
  653. # a = foo()
  654. # except:
  655. # echo "a was not written to"
  656. #
  657. template allPathsInBranch(it) =
  658. let a = allPathsAsgnResult(it)
  659. case a
  660. of InitRequired: return InitRequired
  661. of InitSkippable: discard
  662. of Unknown:
  663. # sticky, but can be overwritten by InitRequired:
  664. result = Unknown
  665. result = Unknown
  666. case n.kind
  667. of nkStmtList, nkStmtListExpr:
  668. for it in n:
  669. result = allPathsAsgnResult(it)
  670. if result != Unknown: return result
  671. of nkAsgn, nkFastAsgn:
  672. if n[0].kind == nkSym and n[0].sym.kind == skResult:
  673. if not containsResult(n[1]): result = InitSkippable
  674. else: result = InitRequired
  675. elif containsResult(n):
  676. result = InitRequired
  677. of nkReturnStmt:
  678. if n.len > 0:
  679. if n[0].kind == nkEmpty and result != InitSkippable:
  680. # This is a bare `return` statement, if `result` was not initialized
  681. # anywhere else (or if we're not sure about this) let's require it to be
  682. # initialized. This avoids cases like #9286 where this heuristic lead to
  683. # wrong code being generated.
  684. result = InitRequired
  685. else: result = allPathsAsgnResult(n[0])
  686. of nkIfStmt, nkIfExpr:
  687. var exhaustive = false
  688. result = InitSkippable
  689. for it in n:
  690. # Every condition must not use 'result':
  691. if it.len == 2 and containsResult(it[0]):
  692. return InitRequired
  693. if it.len == 1: exhaustive = true
  694. allPathsInBranch(it.lastSon)
  695. # if the 'if' statement is not exhaustive and yet it touched 'result'
  696. # in some way, say Unknown.
  697. if not exhaustive: result = Unknown
  698. of nkCaseStmt:
  699. if containsResult(n[0]): return InitRequired
  700. result = InitSkippable
  701. var exhaustive = skipTypes(n[0].typ,
  702. abstractVarRange-{tyTypeDesc}).kind notin {tyFloat..tyFloat128, tyString}
  703. for i in 1..<n.len:
  704. let it = n[i]
  705. allPathsInBranch(it.lastSon)
  706. if it.kind == nkElse: exhaustive = true
  707. if not exhaustive: result = Unknown
  708. of nkWhileStmt:
  709. # some dubious code can assign the result in the 'while'
  710. # condition and that would be fine. Everything else isn't:
  711. result = allPathsAsgnResult(n[0])
  712. if result == Unknown:
  713. result = allPathsAsgnResult(n[1])
  714. # we cannot assume that the 'while' loop is really executed at least once:
  715. if result == InitSkippable: result = Unknown
  716. of harmless:
  717. result = Unknown
  718. of nkGotoState, nkBreakState:
  719. # give up for now.
  720. result = InitRequired
  721. of nkSym:
  722. # some path reads from 'result' before it was written to!
  723. if n.sym.kind == skResult: result = InitRequired
  724. of nkTryStmt:
  725. # We need to watch out for the following problem:
  726. # try:
  727. # result = stuffThatRaises()
  728. # except:
  729. # discard "result was not set"
  730. #
  731. # So ... even if the assignment to 'result' is the very first
  732. # assignment this is not good enough! The only pattern we allow for
  733. # is 'finally: result = x'
  734. result = InitSkippable
  735. for it in n:
  736. if it.kind == nkFinally:
  737. result = allPathsAsgnResult(it.lastSon)
  738. else:
  739. allPathsInBranch(it.lastSon)
  740. else:
  741. for i in 0..<safeLen(n):
  742. allPathsInBranch(n[i])
  743. proc genProcAux(m: BModule, prc: PSym) =
  744. var p = newProc(prc, m)
  745. var header = genProcHeader(m, prc)
  746. var returnStmt: Rope = nil
  747. assert(prc.ast != nil)
  748. let procBody = transformBody(m.g.graph, prc, cache = false)
  749. if sfPure notin prc.flags and prc.typ.sons[0] != nil:
  750. if resultPos >= prc.ast.len:
  751. internalError(m.config, prc.info, "proc has no result symbol")
  752. let resNode = prc.ast.sons[resultPos]
  753. let res = resNode.sym # get result symbol
  754. if not isInvalidReturnType(m.config, prc.typ.sons[0]):
  755. if sfNoInit in prc.flags: incl(res.flags, sfNoInit)
  756. if sfNoInit in prc.flags and p.module.compileToCpp and (let val = easyResultAsgn(procBody); val != nil):
  757. var decl = localVarDecl(p, resNode)
  758. var a: TLoc
  759. initLocExprSingleUse(p, val, a)
  760. linefmt(p, cpsStmts, "$1 = $2;$n", decl, rdLoc(a))
  761. else:
  762. # declare the result symbol:
  763. assignLocalVar(p, resNode)
  764. assert(res.loc.r != nil)
  765. initLocalVar(p, res, immediateAsgn=false)
  766. returnStmt = ropecg(p.module, "\treturn $1;$n", rdLoc(res.loc))
  767. else:
  768. fillResult(p.config, resNode)
  769. assignParam(p, res)
  770. # We simplify 'unsureAsgn(result, nil); unsureAsgn(result, x)'
  771. # to 'unsureAsgn(result, x)'
  772. # Sketch why this is correct: If 'result' points to a stack location
  773. # the 'unsureAsgn' is a nop. If it points to a global variable the
  774. # global is either 'nil' or points to valid memory and so the RC operation
  775. # succeeds without touching not-initialized memory.
  776. if sfNoInit in prc.flags: discard
  777. elif allPathsAsgnResult(procBody) == InitSkippable: discard
  778. else:
  779. resetLoc(p, res.loc)
  780. if skipTypes(res.typ, abstractInst).kind == tyArray:
  781. #incl(res.loc.flags, lfIndirect)
  782. res.loc.storage = OnUnknown
  783. for i in countup(1, sonsLen(prc.typ.n) - 1):
  784. let param = prc.typ.n.sons[i].sym
  785. if param.typ.isCompileTimeOnly: continue
  786. assignParam(p, param)
  787. closureSetup(p, prc)
  788. genStmts(p, procBody) # modifies p.locals, p.init, etc.
  789. var generatedProc: Rope
  790. if sfNoReturn in prc.flags:
  791. if hasDeclspec in extccomp.CC[p.config.cCompiler].props:
  792. header = "__declspec(noreturn) " & header
  793. if sfPure in prc.flags:
  794. if hasDeclspec in extccomp.CC[p.config.cCompiler].props:
  795. header = "__declspec(naked) " & header
  796. generatedProc = ropecg(p.module, "$N$1 {$n$2$3$4}$N$N",
  797. header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts))
  798. else:
  799. generatedProc = ropecg(p.module, "$N$1 {$N", header)
  800. add(generatedProc, initGCFrame(p))
  801. if optStackTrace in prc.options:
  802. add(generatedProc, p.s(cpsLocals))
  803. var procname = makeCString(prc.name.s)
  804. add(generatedProc, initFrame(p, procname, quotedFilename(p.config, prc.info)))
  805. else:
  806. add(generatedProc, p.s(cpsLocals))
  807. if optProfiler in prc.options:
  808. # invoke at proc entry for recursion:
  809. appcg(p, cpsInit, "\t#nimProfile();$n", [])
  810. if p.beforeRetNeeded: add(generatedProc, "{")
  811. add(generatedProc, p.s(cpsInit))
  812. add(generatedProc, p.s(cpsStmts))
  813. if p.beforeRetNeeded: add(generatedProc, ~"\t}BeforeRet_: ;$n")
  814. add(generatedProc, deinitGCFrame(p))
  815. if optStackTrace in prc.options: add(generatedProc, deinitFrame(p))
  816. add(generatedProc, returnStmt)
  817. add(generatedProc, ~"}$N")
  818. add(m.s[cfsProcs], generatedProc)
  819. proc requiresExternC(m: BModule; sym: PSym): bool {.inline.} =
  820. result = (sfCompileToCpp in m.module.flags and
  821. sfCompileToCpp notin sym.getModule().flags and
  822. m.config.cmd != cmdCompileToCpp) or (
  823. sym.flags * {sfImportc, sfInfixCall, sfCompilerProc} == {sfImportc} and
  824. sym.magic == mNone and
  825. m.config.cmd == cmdCompileToCpp)
  826. proc genProcPrototype(m: BModule, sym: PSym) =
  827. useHeader(m, sym)
  828. if lfNoDecl in sym.loc.flags: return
  829. if lfDynamicLib in sym.loc.flags:
  830. if getModule(sym).id != m.module.id and
  831. not containsOrIncl(m.declaredThings, sym.id):
  832. add(m.s[cfsVars], ropecg(m, "extern $1 $2;$n",
  833. getTypeDesc(m, sym.loc.t), mangleDynLibProc(sym)))
  834. elif not containsOrIncl(m.declaredProtos, sym.id):
  835. var header = genProcHeader(m, sym)
  836. if sfNoReturn in sym.flags and hasDeclspec in extccomp.CC[m.config.cCompiler].props:
  837. header = "__declspec(noreturn) " & header
  838. if sym.typ.callConv != ccInline and requiresExternC(m, sym):
  839. header = "extern \"C\" " & header
  840. if sfPure in sym.flags and hasAttribute in CC[m.config.cCompiler].props:
  841. header.add(" __attribute__((naked))")
  842. if sfNoReturn in sym.flags and hasAttribute in CC[m.config.cCompiler].props:
  843. header.add(" __attribute__((noreturn))")
  844. add(m.s[cfsProcHeaders], ropecg(m, "$1;$n", header))
  845. proc genProcNoForward(m: BModule, prc: PSym) =
  846. if lfImportCompilerProc in prc.loc.flags:
  847. fillProcLoc(m, prc.ast[namePos])
  848. useHeader(m, prc)
  849. # dependency to a compilerproc:
  850. discard cgsym(m, prc.name.s)
  851. return
  852. if lfNoDecl in prc.loc.flags:
  853. fillProcLoc(m, prc.ast[namePos])
  854. useHeader(m, prc)
  855. genProcPrototype(m, prc)
  856. elif prc.typ.callConv == ccInline:
  857. # We add inline procs to the calling module to enable C based inlining.
  858. # This also means that a check with ``q.declaredThings`` is wrong, we need
  859. # a check for ``m.declaredThings``.
  860. if not containsOrIncl(m.declaredThings, prc.id):
  861. #if prc.loc.k == locNone:
  862. fillProcLoc(m, prc.ast[namePos])
  863. #elif {sfExportc, sfImportc} * prc.flags == {}:
  864. # # reset name to restore consistency in case of hashing collisions:
  865. # echo "resetting ", prc.id, " by ", m.module.name.s
  866. # prc.loc.r = nil
  867. # prc.loc.r = mangleName(m, prc)
  868. useHeader(m, prc)
  869. genProcPrototype(m, prc)
  870. genProcAux(m, prc)
  871. elif lfDynamicLib in prc.loc.flags:
  872. var q = findPendingModule(m, prc)
  873. fillProcLoc(q, prc.ast[namePos])
  874. useHeader(m, prc)
  875. genProcPrototype(m, prc)
  876. if q != nil and not containsOrIncl(q.declaredThings, prc.id):
  877. symInDynamicLib(q, prc)
  878. else:
  879. symInDynamicLibPartial(m, prc)
  880. elif sfImportc notin prc.flags:
  881. var q = findPendingModule(m, prc)
  882. fillProcLoc(q, prc.ast[namePos])
  883. useHeader(m, prc)
  884. genProcPrototype(m, prc)
  885. if q != nil and not containsOrIncl(q.declaredThings, prc.id):
  886. genProcAux(q, prc)
  887. else:
  888. fillProcLoc(m, prc.ast[namePos])
  889. useHeader(m, prc)
  890. if sfInfixCall notin prc.flags: genProcPrototype(m, prc)
  891. proc requestConstImpl(p: BProc, sym: PSym) =
  892. var m = p.module
  893. useHeader(m, sym)
  894. if sym.loc.k == locNone:
  895. fillLoc(sym.loc, locData, sym.ast, mangleName(p.module, sym), OnStatic)
  896. if lfNoDecl in sym.loc.flags: return
  897. # declare implementation:
  898. var q = findPendingModule(m, sym)
  899. if q != nil and not containsOrIncl(q.declaredThings, sym.id):
  900. assert q.initProc.module == q
  901. addf(q.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
  902. [getTypeDesc(q, sym.typ), sym.loc.r, genConstExpr(q.initProc, sym.ast)])
  903. # declare header:
  904. if q != m and not containsOrIncl(m.declaredThings, sym.id):
  905. assert(sym.loc.r != nil)
  906. let headerDecl = "extern NIM_CONST $1 $2;$n" %
  907. [getTypeDesc(m, sym.loc.t), sym.loc.r]
  908. add(m.s[cfsData], headerDecl)
  909. if sfExportc in sym.flags and p.module.g.generatedHeader != nil:
  910. add(p.module.g.generatedHeader.s[cfsData], headerDecl)
  911. proc isActivated(prc: PSym): bool = prc.typ != nil
  912. proc genProc(m: BModule, prc: PSym) =
  913. if sfBorrow in prc.flags or not isActivated(prc): return
  914. if sfForward in prc.flags:
  915. addForwardedProc(m, prc)
  916. fillProcLoc(m, prc.ast[namePos])
  917. else:
  918. genProcNoForward(m, prc)
  919. if {sfExportc, sfCompilerProc} * prc.flags == {sfExportc} and
  920. m.g.generatedHeader != nil and lfNoDecl notin prc.loc.flags:
  921. genProcPrototype(m.g.generatedHeader, prc)
  922. if prc.typ.callConv == ccInline:
  923. if not containsOrIncl(m.g.generatedHeader.declaredThings, prc.id):
  924. genProcAux(m.g.generatedHeader, prc)
  925. proc genVarPrototype(m: BModule, n: PNode) =
  926. #assert(sfGlobal in sym.flags)
  927. let sym = n.sym
  928. useHeader(m, sym)
  929. fillLoc(sym.loc, locGlobalVar, n, mangleName(m, sym), OnHeap)
  930. if (lfNoDecl in sym.loc.flags) or containsOrIncl(m.declaredThings, sym.id):
  931. return
  932. if sym.owner.id != m.module.id:
  933. # else we already have the symbol generated!
  934. assert(sym.loc.r != nil)
  935. if sfThread in sym.flags:
  936. declareThreadVar(m, sym, true)
  937. else:
  938. add(m.s[cfsVars], "extern ")
  939. add(m.s[cfsVars], getTypeDesc(m, sym.loc.t))
  940. if lfDynamicLib in sym.loc.flags: add(m.s[cfsVars], "*")
  941. if sfRegister in sym.flags: add(m.s[cfsVars], " register")
  942. if sfVolatile in sym.flags: add(m.s[cfsVars], " volatile")
  943. addf(m.s[cfsVars], " $1;$n", [sym.loc.r])
  944. proc addIntTypes(result: var Rope; conf: ConfigRef) {.inline.} =
  945. addf(result, "#define NIM_NEW_MANGLING_RULES\L" &
  946. "#define NIM_INTBITS $1\L", [
  947. platform.CPU[conf.target.targetCPU].intSize.rope])
  948. if conf.cppCustomNamespace.len > 0:
  949. result.add("#define USE_NIM_NAMESPACE ")
  950. result.add(conf.cppCustomNamespace)
  951. result.add("\L")
  952. proc getCopyright(conf: ConfigRef; cfile: Cfile): Rope =
  953. if optCompileOnly in conf.globalOptions:
  954. result = ("/* Generated by Nim Compiler v$1 */$N" &
  955. "/* (c) " & copyrightYear & " Andreas Rumpf */$N" &
  956. "/* The generated code is subject to the original license. */$N") %
  957. [rope(VersionAsString)]
  958. else:
  959. result = ("/* Generated by Nim Compiler v$1 */$N" &
  960. "/* (c) " & copyrightYear & " Andreas Rumpf */$N" &
  961. "/* The generated code is subject to the original license. */$N" &
  962. "/* Compiled for: $2, $3, $4 */$N" &
  963. "/* Command for C compiler:$n $5 */$N") %
  964. [rope(VersionAsString),
  965. rope(platform.OS[conf.target.targetOS].name),
  966. rope(platform.CPU[conf.target.targetCPU].name),
  967. rope(extccomp.CC[conf.cCompiler].name),
  968. rope(getCompileCFileCmd(conf, cfile))]
  969. proc getFileHeader(conf: ConfigRef; cfile: Cfile): Rope =
  970. result = getCopyright(conf, cfile)
  971. addIntTypes(result, conf)
  972. proc genFilenames(m: BModule): Rope =
  973. discard cgsym(m, "dbgRegisterFilename")
  974. result = nil
  975. for i in 0..<m.config.m.fileInfos.len:
  976. result.addf("dbgRegisterFilename($1);$N",
  977. [m.config.m.fileInfos[i].projPath.string.makeCString])
  978. proc genMainProc(m: BModule) =
  979. const
  980. # The use of a volatile function pointer to call Pre/NimMainInner
  981. # prevents inlining of the NimMainInner function and dependent
  982. # functions, which might otherwise merge their stack frames.
  983. PreMainBody =
  984. "void PreMainInner(void) {$N" &
  985. "\tsystemInit000();$N" &
  986. "$1" &
  987. "$2" &
  988. "$3" &
  989. "}$N$N" &
  990. "void PreMain(void) {$N" &
  991. "\tvoid (*volatile inner)(void);$N" &
  992. "\tsystemDatInit000();$N" &
  993. "\tinner = PreMainInner;$N" &
  994. "$4$5" &
  995. "\t(*inner)();$N" &
  996. "}$N$N"
  997. MainProcs =
  998. "\tNimMain();$N"
  999. MainProcsWithResult =
  1000. MainProcs & "\treturn nim_program_result;$N"
  1001. NimMainInner = "N_CDECL(void, NimMainInner)(void) {$N" &
  1002. "$1" &
  1003. "}$N$N"
  1004. NimMainProc =
  1005. "N_CDECL(void, NimMain)(void) {$N" &
  1006. "\tvoid (*volatile inner)(void);$N" &
  1007. "\tPreMain();$N" &
  1008. "\tinner = NimMainInner;$N" &
  1009. "$2" &
  1010. "\t(*inner)();$N" &
  1011. "}$N$N"
  1012. NimMainBody = NimMainInner & NimMainProc
  1013. PosixNimMain =
  1014. "int cmdCount;$N" &
  1015. "char** cmdLine;$N" &
  1016. "char** gEnv;$N" &
  1017. NimMainBody
  1018. PosixCMain =
  1019. "int main(int argc, char** args, char** env) {$N" &
  1020. "\tcmdLine = args;$N" &
  1021. "\tcmdCount = argc;$N" &
  1022. "\tgEnv = env;$N" &
  1023. MainProcsWithResult &
  1024. "}$N$N"
  1025. StandaloneCMain =
  1026. "int main(void) {$N" &
  1027. MainProcs &
  1028. "\treturn 0;$N" &
  1029. "}$N$N"
  1030. WinNimMain = NimMainBody
  1031. WinCMain = "N_STDCALL(int, WinMain)(HINSTANCE hCurInstance, $N" &
  1032. " HINSTANCE hPrevInstance, $N" &
  1033. " LPSTR lpCmdLine, int nCmdShow) {$N" &
  1034. MainProcsWithResult & "}$N$N"
  1035. WinNimDllMain = NimMainInner & "N_LIB_EXPORT " & NimMainProc
  1036. WinCDllMain =
  1037. "BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fwdreason, $N" &
  1038. " LPVOID lpvReserved) {$N" &
  1039. "\tif(fwdreason == DLL_PROCESS_ATTACH) {$N" & MainProcs & "}$N" &
  1040. "\treturn 1;$N}$N$N"
  1041. PosixNimDllMain = WinNimDllMain
  1042. PosixCDllMain =
  1043. "void NIM_POSIX_INIT NimMainInit(void) {$N" &
  1044. MainProcs &
  1045. "}$N$N"
  1046. GenodeNimMain =
  1047. "extern Genode::Env *nim_runtime_env;$N" &
  1048. "extern void nim_component_construct(Genode::Env*);$N$N" &
  1049. NimMainBody
  1050. ComponentConstruct =
  1051. "void Libc::Component::construct(Libc::Env &env) {$N" &
  1052. "\t// Set Env used during runtime initialization$N" &
  1053. "\tnim_runtime_env = &env;$N" &
  1054. "\tLibc::with_libc([&] () {$N\t" &
  1055. "\t// Initialize runtime and globals$N" &
  1056. MainProcs &
  1057. "\t// Call application construct$N" &
  1058. "\t\tnim_component_construct(&env);$N" &
  1059. "\t});$N" &
  1060. "}$N$N"
  1061. var nimMain, otherMain: FormatStr
  1062. if m.config.target.targetOS == osWindows and
  1063. m.config.globalOptions * {optGenGuiApp, optGenDynLib} != {}:
  1064. if optGenGuiApp in m.config.globalOptions:
  1065. nimMain = WinNimMain
  1066. otherMain = WinCMain
  1067. else:
  1068. nimMain = WinNimDllMain
  1069. otherMain = WinCDllMain
  1070. m.includeHeader("<windows.h>")
  1071. elif m.config.target.targetOS == osGenode:
  1072. nimMain = GenodeNimMain
  1073. otherMain = ComponentConstruct
  1074. m.includeHeader("<libc/component.h>")
  1075. elif optGenDynLib in m.config.globalOptions:
  1076. nimMain = PosixNimDllMain
  1077. otherMain = PosixCDllMain
  1078. elif m.config.target.targetOS == osStandalone:
  1079. nimMain = PosixNimMain
  1080. otherMain = StandaloneCMain
  1081. else:
  1082. nimMain = PosixNimMain
  1083. otherMain = PosixCMain
  1084. if m.g.breakpoints != nil: discard cgsym(m, "dbgRegisterBreakpoint")
  1085. if optEndb in m.config.options:
  1086. m.g.breakpoints.add(m.genFilenames)
  1087. let initStackBottomCall =
  1088. if m.config.target.targetOS == osStandalone or m.config.selectedGC == gcNone: "".rope
  1089. else: ropecg(m, "\t#initStackBottomWith((void *)&inner);$N")
  1090. inc(m.labels)
  1091. appcg(m, m.s[cfsProcs], PreMainBody, [
  1092. m.g.mainDatInit, m.g.breakpoints, m.g.otherModsInit,
  1093. if emulatedThreadVars(m.config) and m.config.target.targetOS != osStandalone:
  1094. ropecg(m, "\t#initThreadVarsEmulation();$N")
  1095. else:
  1096. "".rope,
  1097. initStackBottomCall])
  1098. appcg(m, m.s[cfsProcs], nimMain,
  1099. [m.g.mainModInit, initStackBottomCall, rope(m.labels)])
  1100. if optNoMain notin m.config.globalOptions:
  1101. if m.config.cppCustomNamespace.len > 0:
  1102. m.s[cfsProcs].add closeNamespaceNim() & "using namespace " & m.config.cppCustomNamespace & ";\L"
  1103. appcg(m, m.s[cfsProcs], otherMain, [])
  1104. if m.config.cppCustomNamespace.len > 0: m.s[cfsProcs].add openNamespaceNim(m.config.cppCustomNamespace)
  1105. proc getSomeInitName(m: PSym, suffix: string): Rope =
  1106. assert m.kind == skModule
  1107. assert m.owner.kind == skPackage
  1108. if {sfSystemModule, sfMainModule} * m.flags == {}:
  1109. result = m.owner.name.s.mangle.rope
  1110. result.add "_"
  1111. result.add m.name.s.mangle
  1112. result.add suffix
  1113. proc getInitName(m: PSym): Rope =
  1114. if sfMainModule in m.flags:
  1115. # generate constant name for main module, for "easy" debugging.
  1116. result = rope"NimMainModule"
  1117. else:
  1118. result = getSomeInitName(m, "Init000")
  1119. proc getDatInitName(m: PSym): Rope = getSomeInitName(m, "DatInit000")
  1120. proc registerModuleToMain(g: BModuleList; m: PSym) =
  1121. var
  1122. init = m.getInitName
  1123. datInit = m.getDatInitName
  1124. addf(g.mainModProcs, "N_LIB_PRIVATE N_NIMCALL(void, $1)(void);$N", [init])
  1125. addf(g.mainModProcs, "N_LIB_PRIVATE N_NIMCALL(void, $1)(void);$N", [datInit])
  1126. if sfSystemModule notin m.flags:
  1127. addf(g.mainDatInit, "\t$1();$N", [datInit])
  1128. let initCall = "\t$1();$N" % [init]
  1129. if sfMainModule in m.flags:
  1130. add(g.mainModInit, initCall)
  1131. else:
  1132. add(g.otherModsInit, initCall)
  1133. proc genInitCode(m: BModule) =
  1134. var initname = getInitName(m.module)
  1135. var prc = "N_LIB_PRIVATE N_NIMCALL(void, $1)(void) {$N" % [initname]
  1136. if m.typeNodes > 0:
  1137. appcg(m, m.s[cfsTypeInit1], "static #TNimNode $1[$2];$n",
  1138. [m.typeNodesName, rope(m.typeNodes)])
  1139. if m.nimTypes > 0:
  1140. appcg(m, m.s[cfsTypeInit1], "static #TNimType $1[$2];$n",
  1141. [m.nimTypesName, rope(m.nimTypes)])
  1142. # Give this small function its own scope
  1143. addf(prc, "{$N", [])
  1144. block:
  1145. # Keep a bogus frame in case the code needs one
  1146. add(prc, ~"\tTFrame FR_; FR_.len = 0;$N")
  1147. add(prc, genSectionStart(cpsLocals, m.config))
  1148. add(prc, m.preInitProc.s(cpsLocals))
  1149. add(prc, genSectionEnd(cpsLocals, m.config))
  1150. add(prc, genSectionStart(cpsInit, m.config))
  1151. add(prc, m.preInitProc.s(cpsInit))
  1152. add(prc, genSectionEnd(cpsInit, m.config))
  1153. add(prc, genSectionStart(cpsStmts, m.config))
  1154. add(prc, m.preInitProc.s(cpsStmts))
  1155. add(prc, genSectionEnd(cpsStmts, m.config))
  1156. addf(prc, "}$N", [])
  1157. add(prc, initGCFrame(m.initProc))
  1158. add(prc, genSectionStart(cpsLocals, m.config))
  1159. add(prc, m.initProc.s(cpsLocals))
  1160. add(prc, genSectionEnd(cpsLocals, m.config))
  1161. if optStackTrace in m.initProc.options and frameDeclared notin m.flags:
  1162. # BUT: the generated init code might depend on a current frame, so
  1163. # declare it nevertheless:
  1164. incl m.flags, frameDeclared
  1165. if preventStackTrace notin m.flags:
  1166. var procname = makeCString(m.module.name.s)
  1167. add(prc, initFrame(m.initProc, procname, quotedFilename(m.config, m.module.info)))
  1168. else:
  1169. add(prc, ~"\tTFrame FR_; FR_.len = 0;$N")
  1170. add(prc, genSectionStart(cpsInit, m.config))
  1171. add(prc, m.initProc.s(cpsInit))
  1172. add(prc, genSectionEnd(cpsInit, m.config))
  1173. add(prc, genSectionStart(cpsStmts, m.config))
  1174. add(prc, m.initProc.s(cpsStmts))
  1175. add(prc, genSectionEnd(cpsStmts, m.config))
  1176. if optStackTrace in m.initProc.options and preventStackTrace notin m.flags:
  1177. add(prc, deinitFrame(m.initProc))
  1178. add(prc, deinitGCFrame(m.initProc))
  1179. addf(prc, "}$N$N", [])
  1180. prc.addf("N_LIB_PRIVATE N_NIMCALL(void, $1)(void) {$N",
  1181. [getDatInitName(m.module)])
  1182. for i in cfsTypeInit1..cfsDynLibInit:
  1183. add(prc, genSectionStart(i, m.config))
  1184. add(prc, m.s[i])
  1185. add(prc, genSectionEnd(i, m.config))
  1186. addf(prc, "}$N$N", [])
  1187. # we cannot simply add the init proc to ``m.s[cfsProcs]`` anymore because
  1188. # that would lead to a *nesting* of merge sections which the merger does
  1189. # not support. So we add it to another special section: ``cfsInitProc``
  1190. add(m.s[cfsInitProc], prc)
  1191. for i, el in pairs(m.extensionLoaders):
  1192. if el != nil:
  1193. let ex = "NIM_EXTERNC N_NIMCALL(void, nimLoadProcs$1)(void) {$2}$N$N" %
  1194. [(i.ord - '0'.ord).rope, el]
  1195. add(m.s[cfsInitProc], ex)
  1196. proc genModule(m: BModule, cfile: Cfile): Rope =
  1197. result = getFileHeader(m.config, cfile)
  1198. result.add(genMergeInfo(m))
  1199. generateThreadLocalStorage(m)
  1200. generateHeaders(m)
  1201. for i in countup(cfsHeaders, cfsProcs):
  1202. add(result, genSectionStart(i, m.config))
  1203. add(result, m.s[i])
  1204. add(result, genSectionEnd(i, m.config))
  1205. if m.config.cppCustomNamespace.len > 0 and i == cfsHeaders:
  1206. result.add openNamespaceNim(m.config.cppCustomNamespace)
  1207. add(result, m.s[cfsInitProc])
  1208. if m.config.cppCustomNamespace.len > 0: result.add closeNamespaceNim()
  1209. proc newPreInitProc(m: BModule): BProc =
  1210. result = newProc(nil, m)
  1211. # little hack so that unique temporaries are generated:
  1212. result.labels = 100_000
  1213. proc initProcOptions(m: BModule): TOptions =
  1214. let opts = m.config.options
  1215. if sfSystemModule in m.module.flags: opts-{optStackTrace} else: opts
  1216. proc rawNewModule(g: BModuleList; module: PSym, filename: AbsoluteFile): BModule =
  1217. new(result)
  1218. result.g = g
  1219. result.tmpBase = rope("TM" & $hashOwner(module) & "_")
  1220. result.headerFiles = @[]
  1221. result.declaredThings = initIntSet()
  1222. result.declaredProtos = initIntSet()
  1223. result.cfilename = filename
  1224. result.filename = filename
  1225. result.typeCache = initTable[SigHash, Rope]()
  1226. result.forwTypeCache = initTable[SigHash, Rope]()
  1227. result.module = module
  1228. result.typeInfoMarker = initTable[SigHash, Rope]()
  1229. result.sigConflicts = initCountTable[SigHash]()
  1230. result.initProc = newProc(nil, result)
  1231. result.initProc.options = initProcOptions(result)
  1232. result.preInitProc = newPreInitProc(result)
  1233. initNodeTable(result.dataCache)
  1234. result.typeStack = @[]
  1235. result.forwardedProcs = @[]
  1236. result.typeNodesName = getTempName(result)
  1237. result.nimTypesName = getTempName(result)
  1238. # no line tracing for the init sections of the system module so that we
  1239. # don't generate a TFrame which can confuse the stack botton initialization:
  1240. if sfSystemModule in module.flags:
  1241. incl result.flags, preventStackTrace
  1242. excl(result.preInitProc.options, optStackTrace)
  1243. let ndiName = if optCDebug in g.config.globalOptions: changeFileExt(completeCFilePath(g.config, filename), "ndi")
  1244. else: AbsoluteFile""
  1245. open(result.ndi, ndiName, g.config)
  1246. proc nullify[T](arr: var T) =
  1247. for i in low(arr)..high(arr):
  1248. arr[i] = Rope(nil)
  1249. proc resetModule*(m: BModule) =
  1250. # between two compilations in CAAS mode, we can throw
  1251. # away all the data that was written to disk
  1252. m.headerFiles = @[]
  1253. m.declaredProtos = initIntSet()
  1254. m.forwTypeCache = initTable[SigHash, Rope]()
  1255. m.initProc = newProc(nil, m)
  1256. m.initProc.options = initProcOptions(m)
  1257. m.preInitProc = newPreInitProc(m)
  1258. initNodeTable(m.dataCache)
  1259. m.typeStack = @[]
  1260. m.forwardedProcs = @[]
  1261. m.typeNodesName = getTempName(m)
  1262. m.nimTypesName = getTempName(m)
  1263. if sfSystemModule in m.module.flags:
  1264. incl m.flags, preventStackTrace
  1265. else:
  1266. excl m.flags, preventStackTrace
  1267. nullify m.s
  1268. m.typeNodes = 0
  1269. m.nimTypes = 0
  1270. nullify m.extensionLoaders
  1271. # indicate that this is now cached module
  1272. # the cache will be invalidated by nullifying gModules
  1273. #m.fromCache = true
  1274. m.g = nil
  1275. # we keep only the "merge info" information for the module
  1276. # and the properties that can't change:
  1277. # m.filename
  1278. # m.cfilename
  1279. # m.isHeaderFile
  1280. # m.module ?
  1281. # m.typeCache
  1282. # m.declaredThings
  1283. # m.typeInfoMarker
  1284. # m.labels
  1285. # m.FrameDeclared
  1286. proc resetCgenModules*(g: BModuleList) =
  1287. for m in cgenModules(g): resetModule(m)
  1288. proc rawNewModule(g: BModuleList; module: PSym; conf: ConfigRef): BModule =
  1289. result = rawNewModule(g, module, AbsoluteFile toFullPath(conf, module.position.FileIndex))
  1290. proc newModule(g: BModuleList; module: PSym; conf: ConfigRef): BModule =
  1291. # we should create only one cgen module for each module sym
  1292. result = rawNewModule(g, module, conf)
  1293. if module.position >= g.modules.len:
  1294. setLen(g.modules, module.position + 1)
  1295. #growCache g.modules, module.position
  1296. g.modules[module.position] = result
  1297. template injectG() {.dirty.} =
  1298. if graph.backend == nil:
  1299. graph.backend = newModuleList(graph)
  1300. let g = BModuleList(graph.backend)
  1301. proc myOpen(graph: ModuleGraph; module: PSym): PPassContext =
  1302. injectG()
  1303. result = newModule(g, module, graph.config)
  1304. if optGenIndex in graph.config.globalOptions and g.generatedHeader == nil:
  1305. let f = if graph.config.headerFile.len > 0: AbsoluteFile graph.config.headerFile
  1306. else: graph.config.projectFull
  1307. g.generatedHeader = rawNewModule(g, module,
  1308. changeFileExt(completeCFilePath(graph.config, f), hExt))
  1309. incl g.generatedHeader.flags, isHeaderFile
  1310. proc writeHeader(m: BModule) =
  1311. var result = ("/* Generated by Nim Compiler v$1 */$N" &
  1312. "/* (c) 2017 Andreas Rumpf */$N" &
  1313. "/* The generated code is subject to the original license. */$N") %
  1314. [rope(VersionAsString)]
  1315. var guard = "__$1__" % [m.filename.splitFile.name.rope]
  1316. result.addf("#ifndef $1$n#define $1$n", [guard])
  1317. addIntTypes(result, m.config)
  1318. generateHeaders(m)
  1319. generateThreadLocalStorage(m)
  1320. for i in countup(cfsHeaders, cfsProcs):
  1321. add(result, genSectionStart(i, m.config))
  1322. add(result, m.s[i])
  1323. add(result, genSectionEnd(i, m.config))
  1324. if m.config.cppCustomNamespace.len > 0 and i == cfsHeaders: result.add openNamespaceNim(m.config.cppCustomNamespace)
  1325. add(result, m.s[cfsInitProc])
  1326. if optGenDynLib in m.config.globalOptions:
  1327. result.add("N_LIB_IMPORT ")
  1328. result.addf("N_CDECL(void, NimMain)(void);$n", [])
  1329. if m.config.cppCustomNamespace.len > 0: result.add closeNamespaceNim()
  1330. result.addf("#endif /* $1 */$n", [guard])
  1331. if not writeRope(result, m.filename):
  1332. rawMessage(m.config, errCannotOpenFile, m.filename.string)
  1333. proc getCFile(m: BModule): AbsoluteFile =
  1334. let ext =
  1335. if m.compileToCpp: ".cpp"
  1336. elif m.config.cmd == cmdCompileToOC or sfCompileToObjC in m.module.flags: ".m"
  1337. else: ".c"
  1338. result = changeFileExt(completeCFilePath(m.config, withPackageName(m.config, m.cfilename)), ext)
  1339. when false:
  1340. proc myOpenCached(graph: ModuleGraph; module: PSym, rd: PRodReader): PPassContext =
  1341. injectG()
  1342. var m = newModule(g, module, graph.config)
  1343. readMergeInfo(getCFile(m), m)
  1344. result = m
  1345. proc myProcess(b: PPassContext, n: PNode): PNode =
  1346. result = n
  1347. if b == nil: return
  1348. var m = BModule(b)
  1349. if passes.skipCodegen(m.config, n): return
  1350. m.initProc.options = initProcOptions(m)
  1351. #softRnl = if optLineDir in m.config.options: noRnl else: rnl
  1352. # XXX replicate this logic!
  1353. let tranformed_n = transformStmt(m.g.graph, m.module, n)
  1354. genStmts(m.initProc, tranformed_n)
  1355. proc finishModule(m: BModule) =
  1356. var i = 0
  1357. while i <= high(m.forwardedProcs):
  1358. # Note: ``genProc`` may add to ``m.forwardedProcs``, so we cannot use
  1359. # a ``for`` loop here
  1360. var prc = m.forwardedProcs[i]
  1361. if sfForward in prc.flags:
  1362. internalError(m.config, prc.info, "still forwarded: " & prc.name.s)
  1363. genProcNoForward(m, prc)
  1364. inc(i)
  1365. assert(m.g.forwardedProcsCounter >= i)
  1366. dec(m.g.forwardedProcsCounter, i)
  1367. setLen(m.forwardedProcs, 0)
  1368. proc shouldRecompile(m: BModule; code: Rope, cfile: Cfile): bool =
  1369. result = true
  1370. if optForceFullMake notin m.config.globalOptions:
  1371. if not equalsFile(code, cfile.cname):
  1372. if isDefined(m.config, "nimdiff"):
  1373. if fileExists(cfile.cname):
  1374. copyFile(cfile.cname.string, cfile.cname.string & ".backup")
  1375. echo "diff ", cfile.cname.string, ".backup ", cfile.cname.string
  1376. else:
  1377. echo "new file ", cfile.cname.string
  1378. if not writeRope(code, cfile.cname):
  1379. rawMessage(m.config, errCannotOpenFile, cfile.cname.string)
  1380. return
  1381. if fileExists(cfile.obj) and os.fileNewer(cfile.obj.string, cfile.cname.string):
  1382. result = false
  1383. else:
  1384. if not writeRope(code, cfile.cname):
  1385. rawMessage(m.config, errCannotOpenFile, cfile.cname.string)
  1386. # We need 2 different logics here: pending modules (including
  1387. # 'nim__dat') may require file merging for the combination of dead code
  1388. # elimination and incremental compilation! Non pending modules need no
  1389. # such logic and in fact the logic hurts for the main module at least;
  1390. # it would generate multiple 'main' procs, for instance.
  1391. proc writeModule(m: BModule, pending: bool) =
  1392. # generate code for the init statements of the module:
  1393. let cfile = getCFile(m)
  1394. if true or optForceFullMake in m.config.globalOptions:
  1395. genInitCode(m)
  1396. finishTypeDescriptions(m)
  1397. if sfMainModule in m.module.flags:
  1398. # generate main file:
  1399. add(m.s[cfsProcHeaders], m.g.mainModProcs)
  1400. generateThreadVarsSize(m)
  1401. var cf = Cfile(cname: cfile, obj: completeCFilePath(m.config, toObjFile(m.config, cfile)), flags: {})
  1402. var code = genModule(m, cf)
  1403. when hasTinyCBackend:
  1404. if conf.cmd == cmdRun:
  1405. tccgen.compileCCode($code)
  1406. return
  1407. if not shouldRecompile(m, code, cf): cf.flags = {CfileFlag.Cached}
  1408. addFileToCompile(m.config, cf)
  1409. elif pending and mergeRequired(m) and sfMainModule notin m.module.flags:
  1410. let cf = Cfile(cname: cfile, obj: completeCFilePath(m.config, toObjFile(m.config, cfile)), flags: {})
  1411. mergeFiles(cfile, m)
  1412. genInitCode(m)
  1413. finishTypeDescriptions(m)
  1414. var code = genModule(m, cf)
  1415. if not writeRope(code, cfile):
  1416. rawMessage(m.config, errCannotOpenFile, cfile.string)
  1417. addFileToCompile(m.config, cf)
  1418. else:
  1419. # Consider: first compilation compiles ``system.nim`` and produces
  1420. # ``system.c`` but then compilation fails due to an error. This means
  1421. # that ``system.o`` is missing, so we need to call the C compiler for it:
  1422. var cf = Cfile(cname: cfile, obj: completeCFilePath(m.config, toObjFile(m.config, cfile)), flags: {})
  1423. if not fileExists(cf.obj): cf.flags = {CfileFlag.Cached}
  1424. addFileToCompile(m.config, cf)
  1425. close(m.ndi)
  1426. proc updateCachedModule(m: BModule) =
  1427. let cfile = getCFile(m)
  1428. var cf = Cfile(cname: cfile, obj: completeCFilePath(m.config, toObjFile(m.config, cfile)), flags: {})
  1429. if mergeRequired(m) and sfMainModule notin m.module.flags:
  1430. mergeFiles(cfile, m)
  1431. genInitCode(m)
  1432. finishTypeDescriptions(m)
  1433. var code = genModule(m, cf)
  1434. if not writeRope(code, cfile):
  1435. rawMessage(m.config, errCannotOpenFile, cfile.string)
  1436. else:
  1437. cf.flags = {CfileFlag.Cached}
  1438. addFileToCompile(m.config, cf)
  1439. proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode =
  1440. result = n
  1441. if b == nil: return
  1442. var m = BModule(b)
  1443. if passes.skipCodegen(m.config, n): return
  1444. # if the module is cached, we don't regenerate the main proc
  1445. # nor the dispatchers? But if the dispatchers changed?
  1446. # XXX emit the dispatchers into its own .c file?
  1447. if n != nil:
  1448. m.initProc.options = initProcOptions(m)
  1449. genStmts(m.initProc, n)
  1450. # cached modules need to registered too:
  1451. registerModuleToMain(m.g, m.module)
  1452. if sfMainModule in m.module.flags:
  1453. if m.g.forwardedProcsCounter == 0:
  1454. incl m.flags, objHasKidsValid
  1455. let disp = generateMethodDispatchers(graph)
  1456. for x in disp: genProcAux(m, x.sym)
  1457. genMainProc(m)
  1458. proc cgenWriteModules*(backend: RootRef, config: ConfigRef) =
  1459. let g = BModuleList(backend)
  1460. # we need to process the transitive closure because recursive module
  1461. # deps are allowed (and the system module is processed in the wrong
  1462. # order anyway)
  1463. g.config = config
  1464. let (outDir, _, _) = splitFile(config.outfile)
  1465. if not outDir.isEmpty:
  1466. createDir(outDir)
  1467. if g.generatedHeader != nil: finishModule(g.generatedHeader)
  1468. while g.forwardedProcsCounter > 0:
  1469. for m in cgenModules(g):
  1470. finishModule(m)
  1471. for m in cgenModules(g):
  1472. m.writeModule(pending=true)
  1473. writeMapping(config, g.mapping)
  1474. if g.generatedHeader != nil: writeHeader(g.generatedHeader)
  1475. const cgenPass* = makePass(myOpen, myProcess, myClose)