cgen.nim 59 KB

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