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 10## This module implements the C code generator. 11 12import 13 ast, astalgo, hashes, trees, platform, magicsys, extccomp, options, intsets, 14 nversion, nimsets, msgs, bitsets, idents, types, 15 ccgutils, os, ropes, math, passes, wordrecg, treetab, cgmeth, 16 rodutils, renderer, cgendata, aliases, 17 lowerings, tables, sets, ndi, lineinfos, pathutils, transf, 18 injectdestructors, astmsgs 19 20when not defined(leanCompiler): 21 import spawn, semparallel 22 23import strutils except `%` # collides with ropes.`%` 24 25from ic / ic import ModuleBackendFlag 26import dynlib 27 28when not declared(dynlib.libCandidates): 29 proc libCandidates(s: string, dest: var seq[string]) = 30 ## given a library name pattern `s` write possible library names to `dest`. 31 var le = strutils.find(s, '(') 32 var ri = strutils.find(s, ')', le+1) 33 if le >= 0 and ri > le: 34 var prefix = substr(s, 0, le - 1) 35 var suffix = substr(s, ri + 1) 36 for middle in split(substr(s, le + 1, ri - 1), '|'): 37 libCandidates(prefix & middle & suffix, dest) 38 else: 39 dest.add(s) 40 41when options.hasTinyCBackend: 42 import tccgen 43 44proc hcrOn(m: BModule): bool = m.config.hcrOn 45proc hcrOn(p: BProc): bool = p.module.config.hcrOn 46 47proc addForwardedProc(m: BModule, prc: PSym) = 48 m.g.forwardedProcs.add(prc) 49 50proc findPendingModule(m: BModule, s: PSym): BModule = 51 let ms = s.itemId.module #getModule(s) 52 result = m.g.modules[ms] 53 54proc initLoc(result: var TLoc, k: TLocKind, lode: PNode, s: TStorageLoc) = 55 result.k = k 56 result.storage = s 57 result.lode = lode 58 result.r = nil 59 result.flags = {} 60 61proc fillLoc(a: var TLoc, k: TLocKind, lode: PNode, r: Rope, s: TStorageLoc) = 62 # fills the loc if it is not already initialized 63 if a.k == locNone: 64 a.k = k 65 a.lode = lode 66 a.storage = s 67 if a.r == nil: a.r = r 68 69proc t(a: TLoc): PType {.inline.} = 70 if a.lode.kind == nkSym: 71 result = a.lode.sym.typ 72 else: 73 result = a.lode.typ 74 75proc lodeTyp(t: PType): PNode = 76 result = newNode(nkEmpty) 77 result.typ = t 78 79proc isSimpleConst(typ: PType): bool = 80 let t = skipTypes(typ, abstractVar) 81 result = t.kind notin 82 {tyTuple, tyObject, tyArray, tySet, tySequence} and not 83 (t.kind == tyProc and t.callConv == ccClosure) 84 85proc useHeader(m: BModule, sym: PSym) = 86 if lfHeader in sym.loc.flags: 87 assert(sym.annex != nil) 88 let str = getStr(sym.annex.path) 89 m.includeHeader(str) 90 91proc cgsym(m: BModule, name: string): Rope 92 93proc getCFile(m: BModule): AbsoluteFile 94 95proc getModuleDllPath(m: BModule): Rope = 96 let (dir, name, ext) = splitFile(getCFile(m)) 97 let filename = strutils.`%`(platform.OS[m.g.config.target.targetOS].dllFrmt, [name & ext]) 98 result = makeCString(dir.string & "/" & filename) 99 100proc getModuleDllPath(m: BModule, module: int): Rope = 101 result = getModuleDllPath(m.g.modules[module]) 102 103proc getModuleDllPath(m: BModule, s: PSym): Rope = 104 result = getModuleDllPath(m.g.modules[s.itemId.module]) 105 106import macros 107 108proc cgFormatValue(result: var string; value: Rope) = 109 for str in leaves(value): 110 result.add str 111 112proc cgFormatValue(result: var string; value: string) = 113 result.add value 114 115proc cgFormatValue(result: var string; value: BiggestInt) = 116 result.addInt value 117 118proc cgFormatValue(result: var string; value: Int128) = 119 result.addInt128 value 120 121# TODO: please document 122macro ropecg(m: BModule, frmt: static[FormatStr], args: untyped): Rope = 123 args.expectKind nnkBracket 124 # echo "ropecg ", newLit(frmt).repr, ", ", args.repr 125 var i = 0 126 result = nnkStmtListExpr.newTree() 127 128 result.add quote do: 129 assert `m` != nil 130 131 let resVar = genSym(nskVar, "res") 132 # during `koch boot` the median of all generates strings from this 133 # macro is around 40 bytes in length. 134 result.add newVarStmt(resVar, newCall(bindSym"newStringOfCap", newLit(80))) 135 let formatValue = bindSym"cgFormatValue" 136 137 var num = 0 138 var strLit = "" 139 140 template flushStrLit() = 141 if strLit != "": 142 result.add newCall(ident "add", resVar, newLit(strLit)) 143 strLit.setLen 0 144 145 while i < frmt.len: 146 if frmt[i] == '$': 147 inc(i) # skip '$' 148 case frmt[i] 149 of '$': 150 strLit.add '$' 151 inc(i) 152 of '#': 153 flushStrLit() 154 inc(i) 155 result.add newCall(formatValue, resVar, args[num]) 156 inc(num) 157 of '^': 158 flushStrLit() 159 inc(i) 160 result.add newCall(formatValue, resVar, args[^1]) 161 inc(num) 162 of '0'..'9': 163 var j = 0 164 while true: 165 j = (j * 10) + ord(frmt[i]) - ord('0') 166 inc(i) 167 if i >= frmt.len or not (frmt[i] in {'0'..'9'}): break 168 num = j 169 if j > args.len: 170 error("ropes: invalid format string " & newLit(frmt).repr & " args.len: " & $args.len) 171 172 flushStrLit() 173 result.add newCall(formatValue, resVar, args[j-1]) 174 of 'n': 175 flushStrLit() 176 result.add quote do: 177 if optLineDir notin `m`.config.options: 178 `resVar`.add("\L") 179 inc(i) 180 of 'N': 181 strLit.add "\L" 182 inc(i) 183 else: 184 error("ropes: invalid format string $" & frmt[i]) 185 elif frmt[i] == '#' and frmt[i+1] in IdentStartChars: 186 inc(i) 187 var j = i 188 while frmt[j] in IdentChars: inc(j) 189 var ident = newLit(substr(frmt, i, j-1)) 190 i = j 191 flushStrLit() 192 result.add newCall(formatValue, resVar, newCall(ident"cgsym", m, ident)) 193 elif frmt[i] == '#' and frmt[i+1] == '$': 194 inc(i, 2) 195 var j = 0 196 while frmt[i] in Digits: 197 j = (j * 10) + ord(frmt[i]) - ord('0') 198 inc(i) 199 let ident = args[j-1] 200 flushStrLit() 201 result.add newCall(formatValue, resVar, newCall(ident"cgsym", m, ident)) 202 var start = i 203 while i < frmt.len: 204 if frmt[i] != '$' and frmt[i] != '#': inc(i) 205 else: break 206 if i - 1 >= start: 207 strLit.add(substr(frmt, start, i - 1)) 208 209 flushStrLit() 210 result.add newCall(ident"rope", resVar) 211 212proc indentLine(p: BProc, r: Rope): Rope = 213 result = r 214 for i in 0..<p.blocks.len: 215 prepend(result, "\t".rope) 216 217template appcg(m: BModule, c: var Rope, frmt: FormatStr, 218 args: untyped) = 219 c.add(ropecg(m, frmt, args)) 220 221template appcg(m: BModule, sec: TCFileSection, frmt: FormatStr, 222 args: untyped) = 223 m.s[sec].add(ropecg(m, frmt, args)) 224 225template appcg(p: BProc, sec: TCProcSection, frmt: FormatStr, 226 args: untyped) = 227 p.s(sec).add(ropecg(p.module, frmt, args)) 228 229template line(p: BProc, sec: TCProcSection, r: Rope) = 230 p.s(sec).add(indentLine(p, r)) 231 232template line(p: BProc, sec: TCProcSection, r: string) = 233 p.s(sec).add(indentLine(p, r.rope)) 234 235template lineF(p: BProc, sec: TCProcSection, frmt: FormatStr, 236 args: untyped) = 237 p.s(sec).add(indentLine(p, frmt % args)) 238 239template lineCg(p: BProc, sec: TCProcSection, frmt: FormatStr, 240 args: untyped) = 241 p.s(sec).add(indentLine(p, ropecg(p.module, frmt, args))) 242 243template linefmt(p: BProc, sec: TCProcSection, frmt: FormatStr, 244 args: untyped) = 245 p.s(sec).add(indentLine(p, ropecg(p.module, frmt, args))) 246 247proc safeLineNm(info: TLineInfo): int = 248 result = toLinenumber(info) 249 if result < 0: result = 0 # negative numbers are not allowed in #line 250 251proc genCLineDir(r: var Rope, filename: string, line: int; conf: ConfigRef) = 252 assert line >= 0 253 if optLineDir in conf.options and line > 0: 254 r.addf("$N#line $2 $1$N", 255 [rope(makeSingleLineCString(filename)), rope(line)]) 256 257proc genCLineDir(r: var Rope, info: TLineInfo; conf: ConfigRef) = 258 genCLineDir(r, toFullPath(conf, info), info.safeLineNm, conf) 259 260proc freshLineInfo(p: BProc; info: TLineInfo): bool = 261 if p.lastLineInfo.line != info.line or 262 p.lastLineInfo.fileIndex != info.fileIndex: 263 p.lastLineInfo.line = info.line 264 p.lastLineInfo.fileIndex = info.fileIndex 265 result = true 266 267proc genLineDir(p: BProc, t: PNode) = 268 let line = t.info.safeLineNm 269 270 if optEmbedOrigSrc in p.config.globalOptions: 271 p.s(cpsStmts).add(~"//" & sourceLine(p.config, t.info) & "\L") 272 genCLineDir(p.s(cpsStmts), toFullPath(p.config, t.info), line, p.config) 273 if ({optLineTrace, optStackTrace} * p.options == {optLineTrace, optStackTrace}) and 274 (p.prc == nil or sfPure notin p.prc.flags) and t.info.fileIndex != InvalidFileIdx: 275 if freshLineInfo(p, t.info): 276 linefmt(p, cpsStmts, "nimln_($1, $2);$n", 277 [line, quotedFilename(p.config, t.info)]) 278 279proc accessThreadLocalVar(p: BProc, s: PSym) 280proc emulatedThreadVars(conf: ConfigRef): bool {.inline.} 281proc genProc(m: BModule, prc: PSym) 282proc raiseInstr(p: BProc): Rope 283 284template compileToCpp(m: BModule): untyped = 285 m.config.backend == backendCpp or sfCompileToCpp in m.module.flags 286 287proc getTempName(m: BModule): Rope = 288 result = m.tmpBase & rope(m.labels) 289 inc m.labels 290 291proc rdLoc(a: TLoc): Rope = 292 # 'read' location (deref if indirect) 293 result = a.r 294 if lfIndirect in a.flags: result = "(*$1)" % [result] 295 296proc lenField(p: BProc): Rope = 297 result = rope(if p.module.compileToCpp: "len" else: "Sup.len") 298 299proc lenExpr(p: BProc; a: TLoc): Rope = 300 if optSeqDestructors in p.config.globalOptions: 301 result = rdLoc(a) & ".len" 302 else: 303 result = "($1 ? $1->$2 : 0)" % [rdLoc(a), lenField(p)] 304 305proc dataField(p: BProc): Rope = 306 if optSeqDestructors in p.config.globalOptions: 307 result = rope".p->data" 308 else: 309 result = rope"->data" 310 311include ccgliterals 312include ccgtypes 313 314# ------------------------------ Manager of temporaries ------------------ 315 316template mapTypeChooser(n: PNode): TSymKind = 317 (if n.kind == nkSym: n.sym.kind else: skVar) 318 319template mapTypeChooser(a: TLoc): TSymKind = mapTypeChooser(a.lode) 320 321proc addrLoc(conf: ConfigRef; a: TLoc): Rope = 322 result = a.r 323 if lfIndirect notin a.flags and mapType(conf, a.t, mapTypeChooser(a)) != ctArray: 324 result = "(&" & result & ")" 325 326proc byRefLoc(p: BProc; a: TLoc): Rope = 327 result = a.r 328 if lfIndirect notin a.flags and mapType(p.config, a.t, mapTypeChooser(a)) != ctArray and not 329 p.module.compileToCpp: 330 result = "(&" & result & ")" 331 332proc rdCharLoc(a: TLoc): Rope = 333 # read a location that may need a char-cast: 334 result = rdLoc(a) 335 if skipTypes(a.t, abstractRange).kind == tyChar: 336 result = "((NU8)($1))" % [result] 337 338type 339 TAssignmentFlag = enum 340 needToCopy 341 TAssignmentFlags = set[TAssignmentFlag] 342 343proc genObjConstr(p: BProc, e: PNode, d: var TLoc) 344proc rawConstExpr(p: BProc, n: PNode; d: var TLoc) 345proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) 346 347type 348 ObjConstrMode = enum 349 constructObj, 350 constructRefObj 351 352proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: var TLoc, 353 mode: ObjConstrMode) = 354 #if optNimV2 in p.config.globalOptions: return 355 case analyseObjectWithTypeField(t) 356 of frNone: 357 discard 358 of frHeader: 359 var r = rdLoc(a) 360 if mode == constructRefObj: r = "(*$1)" % [r] 361 var s = skipTypes(t, abstractInst) 362 if not p.module.compileToCpp: 363 while s.kind == tyObject and s[0] != nil: 364 r.add(".Sup") 365 s = skipTypes(s[0], skipPtrs) 366 if optTinyRtti in p.config.globalOptions: 367 linefmt(p, section, "$1.m_type = $2;$n", [r, genTypeInfoV2(p.module, t, a.lode.info)]) 368 else: 369 linefmt(p, section, "$1.m_type = $2;$n", [r, genTypeInfoV1(p.module, t, a.lode.info)]) 370 of frEmbedded: 371 # inheritance in C++ does not allow struct initialization: bug #18410 372 if not p.module.compileToCpp and optTinyRtti in p.config.globalOptions: 373 var tmp: TLoc 374 if mode == constructRefObj: 375 let objType = t.skipTypes(abstractInst+{tyRef}) 376 rawConstExpr(p, newNodeIT(nkType, a.lode.info, objType), tmp) 377 linefmt(p, cpsStmts, 378 "#nimCopyMem((void*)$1, (NIM_CONST void*)&$2, sizeof($3));$n", 379 [rdLoc(a), rdLoc(tmp), getTypeDesc(p.module, objType, mapTypeChooser(a))]) 380 else: 381 rawConstExpr(p, newNodeIT(nkType, a.lode.info, t), tmp) 382 genAssignment(p, a, tmp, {}) 383 else: 384 # worst case for performance: 385 var r = if mode == constructObj: addrLoc(p.config, a) else: rdLoc(a) 386 linefmt(p, section, "#objectInit($1, $2);$n", [r, genTypeInfoV1(p.module, t, a.lode.info)]) 387 388 if isException(t): 389 var r = rdLoc(a) 390 if mode == constructRefObj: r = "(*$1)" % [r] 391 var s = skipTypes(t, abstractInst) 392 if not p.module.compileToCpp: 393 while s.kind == tyObject and s[0] != nil and s.sym.magic != mException: 394 r.add(".Sup") 395 s = skipTypes(s[0], skipPtrs) 396 linefmt(p, section, "$1.name = $2;$n", [r, makeCString(t.skipTypes(abstractInst).sym.name.s)]) 397 398proc genRefAssign(p: BProc, dest, src: TLoc) 399 400proc isComplexValueType(t: PType): bool {.inline.} = 401 let t = t.skipTypes(abstractInst + tyUserTypeClasses) 402 result = t.kind in {tyArray, tySet, tyTuple, tyObject, tyOpenArray} or 403 (t.kind == tyProc and t.callConv == ccClosure) 404 405include ccgreset 406 407proc resetLoc(p: BProc, loc: var TLoc) = 408 let containsGcRef = optSeqDestructors notin p.config.globalOptions and containsGarbageCollectedRef(loc.t) 409 let typ = skipTypes(loc.t, abstractVarRange) 410 if isImportedCppType(typ): return 411 if optSeqDestructors in p.config.globalOptions and typ.kind in {tyString, tySequence}: 412 assert rdLoc(loc) != nil 413 414 let atyp = skipTypes(loc.t, abstractInst) 415 if atyp.kind in {tyVar, tyLent}: 416 linefmt(p, cpsStmts, "$1->len = 0; $1->p = NIM_NIL;$n", [rdLoc(loc)]) 417 else: 418 linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)]) 419 elif not isComplexValueType(typ): 420 if containsGcRef: 421 var nilLoc: TLoc 422 initLoc(nilLoc, locTemp, loc.lode, OnStack) 423 nilLoc.r = rope("NIM_NIL") 424 genRefAssign(p, loc, nilLoc) 425 else: 426 linefmt(p, cpsStmts, "$1 = 0;$n", [rdLoc(loc)]) 427 else: 428 if loc.storage != OnStack and containsGcRef: 429 specializeReset(p, loc) 430 when false: 431 linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n", 432 [addrLoc(p.config, loc), genTypeInfoV1(p.module, loc.t, loc.lode.info)]) 433 # XXX: generated reset procs should not touch the m_type 434 # field, so disabling this should be safe: 435 genObjectInit(p, cpsStmts, loc.t, loc, constructObj) 436 else: 437 # array passed as argument decayed into pointer, bug #7332 438 # so we use getTypeDesc here rather than rdLoc(loc) 439 linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));$n", 440 [addrLoc(p.config, loc), 441 getTypeDesc(p.module, loc.t, mapTypeChooser(loc))]) 442 # XXX: We can be extra clever here and call memset only 443 # on the bytes following the m_type field? 444 genObjectInit(p, cpsStmts, loc.t, loc, constructObj) 445 446proc constructLoc(p: BProc, loc: var TLoc, isTemp = false) = 447 let typ = loc.t 448 if optSeqDestructors in p.config.globalOptions and skipTypes(typ, abstractInst + {tyStatic}).kind in {tyString, tySequence}: 449 linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)]) 450 elif not isComplexValueType(typ): 451 if containsGarbageCollectedRef(loc.t): 452 var nilLoc: TLoc 453 initLoc(nilLoc, locTemp, loc.lode, OnStack) 454 nilLoc.r = rope("NIM_NIL") 455 genRefAssign(p, loc, nilLoc) 456 else: 457 linefmt(p, cpsStmts, "$1 = ($2)0;$n", [rdLoc(loc), 458 getTypeDesc(p.module, typ, mapTypeChooser(loc))]) 459 else: 460 if not isTemp or containsGarbageCollectedRef(loc.t): 461 # don't use nimZeroMem for temporary values for performance if we can 462 # avoid it: 463 if not isImportedCppType(typ): 464 linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));$n", 465 [addrLoc(p.config, loc), getTypeDesc(p.module, typ, mapTypeChooser(loc))]) 466 genObjectInit(p, cpsStmts, loc.t, loc, constructObj) 467 468proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) = 469 if sfNoInit notin v.flags: 470 # we know it is a local variable and thus on the stack! 471 # If ``not immediateAsgn`` it is not initialized in a binding like 472 # ``var v = X`` and thus we need to init it. 473 # If ``v`` contains a GC-ref we may pass it to ``unsureAsgnRef`` somehow 474 # which requires initialization. However this can really only happen if 475 # ``var v = X()`` gets transformed into ``X(&v)``. 476 # Nowadays the logic in ccgcalls deals with this case however. 477 if not immediateAsgn: 478 constructLoc(p, v.loc) 479 480proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) = 481 inc(p.labels) 482 result.r = "T" & rope(p.labels) & "_" 483 linefmt(p, cpsLocals, "$1 $2;$n", [getTypeDesc(p.module, t, skVar), result.r]) 484 result.k = locTemp 485 result.lode = lodeTyp t 486 result.storage = OnStack 487 result.flags = {} 488 constructLoc(p, result, not needsInit) 489 when false: 490 # XXX Introduce a compiler switch in order to detect these easily. 491 if getSize(p.config, t) > 1024 * 1024: 492 if p.prc != nil: 493 echo "ENORMOUS TEMPORARY! ", p.config $ p.prc.info 494 else: 495 echo "ENORMOUS TEMPORARY! ", p.config $ p.lastLineInfo 496 writeStackTrace() 497 498proc getTempCpp(p: BProc, t: PType, result: var TLoc; value: Rope) = 499 inc(p.labels) 500 result.r = "T" & rope(p.labels) & "_" 501 linefmt(p, cpsStmts, "$1 $2 = $3;$n", [getTypeDesc(p.module, t, skVar), result.r, value]) 502 result.k = locTemp 503 result.lode = lodeTyp t 504 result.storage = OnStack 505 result.flags = {} 506 507proc getIntTemp(p: BProc, result: var TLoc) = 508 inc(p.labels) 509 result.r = "T" & rope(p.labels) & "_" 510 linefmt(p, cpsLocals, "NI $1;$n", [result.r]) 511 result.k = locTemp 512 result.storage = OnStack 513 result.lode = lodeTyp getSysType(p.module.g.graph, unknownLineInfo, tyInt) 514 result.flags = {} 515 516proc localVarDecl(p: BProc; n: PNode): Rope = 517 let s = n.sym 518 if s.loc.k == locNone: 519 fillLoc(s.loc, locLocalVar, n, mangleLocalName(p, s), OnStack) 520 if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy) 521 if s.kind in {skLet, skVar, skField, skForVar} and s.alignment > 0: 522 result.addf("NIM_ALIGN($1) ", [rope(s.alignment)]) 523 result.add getTypeDesc(p.module, s.typ, skVar) 524 if s.constraint.isNil: 525 if sfRegister in s.flags: result.add(" register") 526 #elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds: 527 # decl.add(" GC_GUARD") 528 if sfVolatile in s.flags: result.add(" volatile") 529 if sfNoalias in s.flags: result.add(" NIM_NOALIAS") 530 result.add(" ") 531 result.add(s.loc.r) 532 else: 533 result = runtimeFormat(s.cgDeclFrmt, [result, s.loc.r]) 534 535proc assignLocalVar(p: BProc, n: PNode) = 536 #assert(s.loc.k == locNone) # not yet assigned 537 # this need not be fulfilled for inline procs; they are regenerated 538 # for each module that uses them! 539 let nl = if optLineDir in p.config.options: "" else: "\L" 540 let decl = localVarDecl(p, n) & ";" & nl 541 line(p, cpsLocals, decl) 542 543include ccgthreadvars 544 545proc varInDynamicLib(m: BModule, sym: PSym) 546 547proc treatGlobalDifferentlyForHCR(m: BModule, s: PSym): bool = 548 return m.hcrOn and {sfThread, sfGlobal} * s.flags == {sfGlobal} and 549 ({lfNoDecl, lfHeader} * s.loc.flags == {}) 550 # and s.owner.kind == skModule # owner isn't always a module (global pragma on local var) 551 # and s.loc.k == locGlobalVar # loc isn't always initialized when this proc is used 552 553proc assignGlobalVar(p: BProc, n: PNode; value: Rope) = 554 let s = n.sym 555 if s.loc.k == locNone: 556 fillLoc(s.loc, locGlobalVar, n, mangleName(p.module, s), OnHeap) 557 if treatGlobalDifferentlyForHCR(p.module, s): incl(s.loc.flags, lfIndirect) 558 559 if lfDynamicLib in s.loc.flags: 560 var q = findPendingModule(p.module, s) 561 if q != nil and not containsOrIncl(q.declaredThings, s.id): 562 varInDynamicLib(q, s) 563 else: 564 s.loc.r = mangleDynLibProc(s) 565 if value != nil: 566 internalError(p.config, n.info, ".dynlib variables cannot have a value") 567 return 568 useHeader(p.module, s) 569 if lfNoDecl in s.loc.flags: return 570 if not containsOrIncl(p.module.declaredThings, s.id): 571 if sfThread in s.flags: 572 declareThreadVar(p.module, s, sfImportc in s.flags) 573 if value != nil: 574 internalError(p.config, n.info, ".threadvar variables cannot have a value") 575 else: 576 var decl: Rope = nil 577 var td = getTypeDesc(p.module, s.loc.t, skVar) 578 if s.constraint.isNil: 579 if s.kind in {skLet, skVar, skField, skForVar} and s.alignment > 0: 580 decl.addf "NIM_ALIGN($1) ", [rope(s.alignment)] 581 if p.hcrOn: decl.add("static ") 582 elif sfImportc in s.flags: decl.add("extern ") 583 elif lfExportLib in s.loc.flags: decl.add("N_LIB_EXPORT_VAR ") 584 else: decl.add("N_LIB_PRIVATE ") 585 if s.kind == skLet and value != nil: decl.add("NIM_CONST ") 586 decl.add(td) 587 if p.hcrOn: decl.add("*") 588 if sfRegister in s.flags: decl.add(" register") 589 if sfVolatile in s.flags: decl.add(" volatile") 590 if sfNoalias in s.flags: decl.add(" NIM_NOALIAS") 591 if value != nil: 592 decl.addf(" $1 = $2;$n", [s.loc.r, value]) 593 else: 594 decl.addf(" $1;$n", [s.loc.r]) 595 else: 596 if value != nil: 597 decl = runtimeFormat(s.cgDeclFrmt & " = $#;$n", [td, s.loc.r, value]) 598 else: 599 decl = runtimeFormat(s.cgDeclFrmt & ";$n", [td, s.loc.r]) 600 p.module.s[cfsVars].add(decl) 601 if p.withinLoop > 0 and value == nil: 602 # fixes tests/run/tzeroarray: 603 resetLoc(p, s.loc) 604 605proc assignParam(p: BProc, s: PSym, retType: PType) = 606 assert(s.loc.r != nil) 607 scopeMangledParam(p, s) 608 609proc fillProcLoc(m: BModule; n: PNode) = 610 let sym = n.sym 611 if sym.loc.k == locNone: 612 fillLoc(sym.loc, locProc, n, mangleName(m, sym), OnStack) 613 614proc getLabel(p: BProc): TLabel = 615 inc(p.labels) 616 result = "LA" & rope(p.labels) & "_" 617 618proc fixLabel(p: BProc, labl: TLabel) = 619 lineF(p, cpsStmts, "$1: ;$n", [labl]) 620 621proc genVarPrototype(m: BModule, n: PNode) 622proc requestConstImpl(p: BProc, sym: PSym) 623proc genStmts(p: BProc, t: PNode) 624proc expr(p: BProc, n: PNode, d: var TLoc) 625proc genProcPrototype(m: BModule, sym: PSym) 626proc putLocIntoDest(p: BProc, d: var TLoc, s: TLoc) 627proc intLiteral(i: BiggestInt): Rope 628proc genLiteral(p: BProc, n: PNode): Rope 629proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType): Rope 630proc raiseExit(p: BProc) 631 632proc initLocExpr(p: BProc, e: PNode, result: var TLoc) = 633 initLoc(result, locNone, e, OnUnknown) 634 expr(p, e, result) 635 636proc initLocExprSingleUse(p: BProc, e: PNode, result: var TLoc) = 637 initLoc(result, locNone, e, OnUnknown) 638 if e.kind in nkCallKinds and (e[0].kind != nkSym or e[0].sym.magic == mNone): 639 # We cannot check for tfNoSideEffect here because of mutable parameters. 640 discard "bug #8202; enforce evaluation order for nested calls for C++ too" 641 # We may need to consider that 'f(g())' cannot be rewritten to 'tmp = g(); f(tmp)' 642 # if 'tmp' lacks a move/assignment operator. 643 if e[0].kind == nkSym and sfCompileToCpp in e[0].sym.flags: 644 result.flags.incl lfSingleUse 645 else: 646 result.flags.incl lfSingleUse 647 expr(p, e, result) 648 649include ccgcalls, "ccgstmts.nim" 650 651proc initFrame(p: BProc, procname, filename: Rope): Rope = 652 const frameDefines = """ 653 $1 define nimfr_(proc, file) \ 654 TFrame FR_; \ 655 FR_.procname = proc; FR_.filename = file; FR_.line = 0; FR_.len = 0; #nimFrame(&FR_); 656 657 $1 define nimfrs_(proc, file, slots, length) \ 658 struct {TFrame* prev;NCSTRING procname;NI line;NCSTRING filename; NI len; VarSlot s[slots];} FR_; \ 659 FR_.procname = proc; FR_.filename = file; FR_.line = 0; FR_.len = length; #nimFrame((TFrame*)&FR_); 660 661 $1 define nimln_(n, file) \ 662 FR_.line = n; FR_.filename = file; 663 """ 664 if p.module.s[cfsFrameDefines].len == 0: 665 appcg(p.module, p.module.s[cfsFrameDefines], frameDefines, ["#"]) 666 667 discard cgsym(p.module, "nimFrame") 668 result = ropecg(p.module, "\tnimfr_($1, $2);$n", [procname, filename]) 669 670proc initFrameNoDebug(p: BProc; frame, procname, filename: Rope; line: int): Rope = 671 discard cgsym(p.module, "nimFrame") 672 p.blocks[0].sections[cpsLocals].addf("TFrame $1;$n", [frame]) 673 result = ropecg(p.module, "\t$1.procname = $2; $1.filename = $3; " & 674 " $1.line = $4; $1.len = -1; nimFrame(&$1);$n", 675 [frame, procname, filename, line]) 676 677proc deinitFrameNoDebug(p: BProc; frame: Rope): Rope = 678 result = ropecg(p.module, "\t#popFrameOfAddr(&$1);$n", [frame]) 679 680proc deinitFrame(p: BProc): Rope = 681 result = ropecg(p.module, "\t#popFrame();$n", []) 682 683include ccgexprs 684 685# ----------------------------- dynamic library handling ----------------- 686# We don't finalize dynamic libs as the OS does this for us. 687 688proc isGetProcAddr(lib: PLib): bool = 689 let n = lib.path 690 result = n.kind in nkCallKinds and n.typ != nil and 691 n.typ.kind in {tyPointer, tyProc} 692 693proc loadDynamicLib(m: BModule, lib: PLib) = 694 assert(lib != nil) 695 if not lib.generated: 696 lib.generated = true 697 var tmp = getTempName(m) 698 assert(lib.name == nil) 699 lib.name = tmp # BUGFIX: cgsym has awful side-effects 700 m.s[cfsVars].addf("static void* $1;$n", [tmp]) 701 if lib.path.kind in {nkStrLit..nkTripleStrLit}: 702 var s: TStringSeq = @[] 703 libCandidates(lib.path.strVal, s) 704 rawMessage(m.config, hintDependency, lib.path.strVal) 705 var loadlib: Rope = nil 706 for i in 0..high(s): 707 inc(m.labels) 708 if i > 0: loadlib.add("||") 709 let n = newStrNode(nkStrLit, s[i]) 710 n.info = lib.path.info 711 appcg(m, loadlib, "($1 = #nimLoadLibrary($2))$n", 712 [tmp, genStringLiteral(m, n)]) 713 appcg(m, m.s[cfsDynLibInit], 714 "if (!($1)) #nimLoadLibraryError($2);$n", 715 [loadlib, genStringLiteral(m, lib.path)]) 716 else: 717 var p = newProc(nil, m) 718 p.options.excl optStackTrace 719 p.flags.incl nimErrorFlagDisabled 720 var dest: TLoc 721 initLoc(dest, locTemp, lib.path, OnStack) 722 dest.r = getTempName(m) 723 appcg(m, m.s[cfsDynLibInit],"$1 $2;$n", 724 [getTypeDesc(m, lib.path.typ, skVar), rdLoc(dest)]) 725 expr(p, lib.path, dest) 726 727 m.s[cfsVars].add(p.s(cpsLocals)) 728 m.s[cfsDynLibInit].add(p.s(cpsInit)) 729 m.s[cfsDynLibInit].add(p.s(cpsStmts)) 730 appcg(m, m.s[cfsDynLibInit], 731 "if (!($1 = #nimLoadLibrary($2))) #nimLoadLibraryError($2);$n", 732 [tmp, rdLoc(dest)]) 733 734 if lib.name == nil: internalError(m.config, "loadDynamicLib") 735 736proc mangleDynLibProc(sym: PSym): Rope = 737 # we have to build this as a single rope in order not to trip the 738 # optimization in genInfixCall, see test tests/cpp/t8241.nim 739 if sfCompilerProc in sym.flags: 740 # NOTE: sym.loc.r is the external name! 741 result = rope(sym.name.s) 742 else: 743 result = rope(strutils.`%`("Dl_$1_", $sym.id)) 744 745proc symInDynamicLib(m: BModule, sym: PSym) = 746 var lib = sym.annex 747 let isCall = isGetProcAddr(lib) 748 var extname = sym.loc.r 749 if not isCall: loadDynamicLib(m, lib) 750 var tmp = mangleDynLibProc(sym) 751 sym.loc.r = tmp # from now on we only need the internal name 752 sym.typ.sym = nil # generate a new name 753 inc(m.labels, 2) 754 if isCall: 755 let n = lib.path 756 var a: TLoc 757 initLocExpr(m.initProc, n[0], a) 758 var params = rdLoc(a) & "(" 759 for i in 1..<n.len-1: 760 initLocExpr(m.initProc, n[i], a) 761 params.add(rdLoc(a)) 762 params.add(", ") 763 let load = "\t$1 = ($2) ($3$4));$n" % 764 [tmp, getTypeDesc(m, sym.typ, skVar), params, makeCString($extname)] 765 var last = lastSon(n) 766 if last.kind == nkHiddenStdConv: last = last[1] 767 internalAssert(m.config, last.kind == nkStrLit) 768 let idx = last.strVal 769 if idx.len == 0: 770 m.initProc.s(cpsStmts).add(load) 771 elif idx.len == 1 and idx[0] in {'0'..'9'}: 772 m.extensionLoaders[idx[0]].add(load) 773 else: 774 internalError(m.config, sym.info, "wrong index: " & idx) 775 else: 776 appcg(m, m.s[cfsDynLibInit], 777 "\t$1 = ($2) #nimGetProcAddr($3, $4);$n", 778 [tmp, getTypeDesc(m, sym.typ, skVar), lib.name, makeCString($extname)]) 779 m.s[cfsVars].addf("$2 $1;$n", [sym.loc.r, getTypeDesc(m, sym.loc.t, skVar)]) 780 781proc varInDynamicLib(m: BModule, sym: PSym) = 782 var lib = sym.annex 783 var extname = sym.loc.r 784 loadDynamicLib(m, lib) 785 incl(sym.loc.flags, lfIndirect) 786 var tmp = mangleDynLibProc(sym) 787 sym.loc.r = tmp # from now on we only need the internal name 788 inc(m.labels, 2) 789 appcg(m, m.s[cfsDynLibInit], 790 "$1 = ($2*) #nimGetProcAddr($3, $4);$n", 791 [tmp, getTypeDesc(m, sym.typ, skVar), lib.name, makeCString($extname)]) 792 m.s[cfsVars].addf("$2* $1;$n", 793 [sym.loc.r, getTypeDesc(m, sym.loc.t, skVar)]) 794 795proc symInDynamicLibPartial(m: BModule, sym: PSym) = 796 sym.loc.r = mangleDynLibProc(sym) 797 sym.typ.sym = nil # generate a new name 798 799proc cgsym(m: BModule, name: string): Rope = 800 let sym = magicsys.getCompilerProc(m.g.graph, name) 801 if sym != nil: 802 case sym.kind 803 of skProc, skFunc, skMethod, skConverter, skIterator: genProc(m, sym) 804 of skVar, skResult, skLet: genVarPrototype(m, newSymNode sym) 805 of skType: discard getTypeDesc(m, sym.typ) 806 else: internalError(m.config, "cgsym: " & name & ": " & $sym.kind) 807 else: 808 # we used to exclude the system module from this check, but for DLL 809 # generation support this sloppyness leads to hard to detect bugs, so 810 # we're picky here for the system module too: 811 rawMessage(m.config, errGenerated, "system module needs: " & name) 812 result = sym.loc.r 813 if m.hcrOn and sym != nil and sym.kind in {skProc..skIterator}: 814 result.addActualSuffixForHCR(m.module, sym) 815 816proc generateHeaders(m: BModule) = 817 m.s[cfsHeaders].add("\L#include \"nimbase.h\"\L") 818 819 for it in m.headerFiles: 820 if it[0] == '#': 821 m.s[cfsHeaders].add(rope(it.replace('`', '"') & "\L")) 822 elif it[0] notin {'"', '<'}: 823 m.s[cfsHeaders].addf("#include \"$1\"$N", [rope(it)]) 824 else: 825 m.s[cfsHeaders].addf("#include $1$N", [rope(it)]) 826 m.s[cfsHeaders].add("""#undef LANGUAGE_C 827#undef MIPSEB 828#undef MIPSEL 829#undef PPC 830#undef R3000 831#undef R4000 832#undef i386 833#undef linux 834#undef mips 835#undef near 836#undef far 837#undef powerpc 838#undef unix 839""") 840 841proc openNamespaceNim(namespace: string): Rope = 842 result.add("namespace ") 843 result.add(namespace) 844 result.add(" {\L") 845 846proc closeNamespaceNim(): Rope = 847 result.add("}\L") 848 849proc closureSetup(p: BProc, prc: PSym) = 850 if tfCapturesEnv notin prc.typ.flags: return 851 # prc.ast[paramsPos].last contains the type we're after: 852 var ls = lastSon(prc.ast[paramsPos]) 853 if ls.kind != nkSym: 854 internalError(p.config, prc.info, "closure generation failed") 855 var env = ls.sym 856 #echo "created environment: ", env.id, " for ", prc.name.s 857 assignLocalVar(p, ls) 858 # generate cast assignment: 859 if p.config.selectedGC == gcGo: 860 linefmt(p, cpsStmts, "#unsureAsgnRef((void**) $1, ($2) ClE_0);$n", 861 [addrLoc(p.config, env.loc), getTypeDesc(p.module, env.typ)]) 862 else: 863 linefmt(p, cpsStmts, "$1 = ($2) ClE_0;$n", 864 [rdLoc(env.loc), getTypeDesc(p.module, env.typ)]) 865 866proc containsResult(n: PNode): bool = 867 result = false 868 case n.kind 869 of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkFormalParams: 870 discard 871 of nkSym: 872 if n.sym.kind == skResult: 873 result = true 874 else: 875 for i in 0..<n.len: 876 if containsResult(n[i]): return true 877 878const harmless = {nkConstSection, nkTypeSection, nkEmpty, nkCommentStmt, nkTemplateDef, 879 nkMacroDef, nkMixinStmt, nkBindStmt} + 880 declarativeDefs 881 882proc easyResultAsgn(n: PNode): PNode = 883 case n.kind 884 of nkStmtList, nkStmtListExpr: 885 var i = 0 886 while i < n.len and n[i].kind in harmless: inc i 887 if i < n.len: result = easyResultAsgn(n[i]) 888 of nkAsgn, nkFastAsgn: 889 if n[0].kind == nkSym and n[0].sym.kind == skResult and not containsResult(n[1]): 890 incl n.flags, nfPreventCg 891 return n[1] 892 of nkReturnStmt: 893 if n.len > 0: 894 result = easyResultAsgn(n[0]) 895 if result != nil: incl n.flags, nfPreventCg 896 else: discard 897 898type 899 InitResultEnum = enum Unknown, InitSkippable, InitRequired 900 901proc allPathsAsgnResult(n: PNode): InitResultEnum = 902 # Exceptions coming from calls don't have not be considered here: 903 # 904 # proc bar(): string = raise newException(...) 905 # 906 # proc foo(): string = 907 # # optimized out: 'reset(result)' 908 # result = bar() 909 # 910 # try: 911 # a = foo() 912 # except: 913 # echo "a was not written to" 914 # 915 template allPathsInBranch(it) = 916 let a = allPathsAsgnResult(it) 917 case a 918 of InitRequired: return InitRequired 919 of InitSkippable: discard 920 of Unknown: 921 # sticky, but can be overwritten by InitRequired: 922 result = Unknown 923 924 result = Unknown 925 case n.kind 926 of nkStmtList, nkStmtListExpr: 927 for it in n: 928 result = allPathsAsgnResult(it) 929 if result != Unknown: return result 930 of nkAsgn, nkFastAsgn: 931 if n[0].kind == nkSym and n[0].sym.kind == skResult: 932 if not containsResult(n[1]): result = InitSkippable 933 else: result = InitRequired 934 elif containsResult(n): 935 result = InitRequired 936 of nkReturnStmt: 937 if n.len > 0: 938 if n[0].kind == nkEmpty and result != InitSkippable: 939 # This is a bare `return` statement, if `result` was not initialized 940 # anywhere else (or if we're not sure about this) let's require it to be 941 # initialized. This avoids cases like #9286 where this heuristic lead to 942 # wrong code being generated. 943 result = InitRequired 944 else: result = allPathsAsgnResult(n[0]) 945 of nkIfStmt, nkIfExpr: 946 var exhaustive = false 947 result = InitSkippable 948 for it in n: 949 # Every condition must not use 'result': 950 if it.len == 2 and containsResult(it[0]): 951 return InitRequired 952 if it.len == 1: exhaustive = true 953 allPathsInBranch(it.lastSon) 954 # if the 'if' statement is not exhaustive and yet it touched 'result' 955 # in some way, say Unknown. 956 if not exhaustive: result = Unknown 957 of nkCaseStmt: 958 if containsResult(n[0]): return InitRequired 959 result = InitSkippable 960 var exhaustive = skipTypes(n[0].typ, 961 abstractVarRange-{tyTypeDesc}).kind notin {tyFloat..tyFloat128, tyString} 962 for i in 1..<n.len: 963 let it = n[i] 964 allPathsInBranch(it.lastSon) 965 if it.kind == nkElse: exhaustive = true 966 if not exhaustive: result = Unknown 967 of nkWhileStmt: 968 # some dubious code can assign the result in the 'while' 969 # condition and that would be fine. Everything else isn't: 970 result = allPathsAsgnResult(n[0]) 971 if result == Unknown: 972 result = allPathsAsgnResult(n[1]) 973 # we cannot assume that the 'while' loop is really executed at least once: 974 if result == InitSkippable: result = Unknown 975 of harmless: 976 result = Unknown 977 of nkGotoState, nkBreakState: 978 # give up for now. 979 result = InitRequired 980 of nkSym: 981 # some path reads from 'result' before it was written to! 982 if n.sym.kind == skResult: result = InitRequired 983 of nkTryStmt, nkHiddenTryStmt: 984 # We need to watch out for the following problem: 985 # try: 986 # result = stuffThatRaises() 987 # except: 988 # discard "result was not set" 989 # 990 # So ... even if the assignment to 'result' is the very first 991 # assignment this is not good enough! The only pattern we allow for 992 # is 'finally: result = x' 993 result = InitSkippable 994 allPathsInBranch(n[0]) 995 for i in 1..<n.len: 996 if n[i].kind == nkFinally: 997 result = allPathsAsgnResult(n[i].lastSon) 998 else: 999 allPathsInBranch(n[i].lastSon) 1000 else: 1001 for i in 0..<n.safeLen: 1002 allPathsInBranch(n[i]) 1003 1004proc getProcTypeCast(m: BModule, prc: PSym): Rope = 1005 result = getTypeDesc(m, prc.loc.t) 1006 if prc.typ.callConv == ccClosure: 1007 var rettype, params: Rope 1008 var check = initIntSet() 1009 genProcParams(m, prc.typ, rettype, params, check) 1010 result = "$1(*)$2" % [rettype, params] 1011 1012proc genProcBody(p: BProc; procBody: PNode) = 1013 genStmts(p, procBody) # modifies p.locals, p.init, etc. 1014 if {nimErrorFlagAccessed, nimErrorFlagDeclared} * p.flags == {nimErrorFlagAccessed}: 1015 p.flags.incl nimErrorFlagDeclared 1016 p.blocks[0].sections[cpsLocals].add(ropecg(p.module, "NIM_BOOL* nimErr_;$n", [])) 1017 p.blocks[0].sections[cpsInit].add(ropecg(p.module, "nimErr_ = #nimErrorFlag();$n", [])) 1018 1019proc isNoReturn(m: BModule; s: PSym): bool {.inline.} = 1020 sfNoReturn in s.flags and m.config.exc != excGoto 1021 1022proc genProcAux(m: BModule, prc: PSym) = 1023 var p = newProc(prc, m) 1024 var header = genProcHeader(m, prc) 1025 var returnStmt: Rope = nil 1026 assert(prc.ast != nil) 1027 1028 var procBody = transformBody(m.g.graph, m.idgen, prc, cache = false) 1029 if sfInjectDestructors in prc.flags: 1030 procBody = injectDestructorCalls(m.g.graph, m.idgen, prc, procBody) 1031 1032 if sfPure notin prc.flags and prc.typ[0] != nil: 1033 if resultPos >= prc.ast.len: 1034 internalError(m.config, prc.info, "proc has no result symbol") 1035 let resNode = prc.ast[resultPos] 1036 let res = resNode.sym # get result symbol 1037 if not isInvalidReturnType(m.config, prc.typ[0]): 1038 if sfNoInit in prc.flags: incl(res.flags, sfNoInit) 1039 if sfNoInit in prc.flags and p.module.compileToCpp and (let val = easyResultAsgn(procBody); val != nil): 1040 var decl = localVarDecl(p, resNode) 1041 var a: TLoc 1042 initLocExprSingleUse(p, val, a) 1043 linefmt(p, cpsStmts, "$1 = $2;$n", [decl, rdLoc(a)]) 1044 else: 1045 # declare the result symbol: 1046 assignLocalVar(p, resNode) 1047 assert(res.loc.r != nil) 1048 initLocalVar(p, res, immediateAsgn=false) 1049 returnStmt = ropecg(p.module, "\treturn $1;$n", [rdLoc(res.loc)]) 1050 else: 1051 fillResult(p.config, resNode) 1052 assignParam(p, res, prc.typ[0]) 1053 # We simplify 'unsureAsgn(result, nil); unsureAsgn(result, x)' 1054 # to 'unsureAsgn(result, x)' 1055 # Sketch why this is correct: If 'result' points to a stack location 1056 # the 'unsureAsgn' is a nop. If it points to a global variable the 1057 # global is either 'nil' or points to valid memory and so the RC operation 1058 # succeeds without touching not-initialized memory. 1059 if sfNoInit in prc.flags: discard 1060 elif allPathsAsgnResult(procBody) == InitSkippable: discard 1061 else: 1062 resetLoc(p, res.loc) 1063 if skipTypes(res.typ, abstractInst).kind == tyArray: 1064 #incl(res.loc.flags, lfIndirect) 1065 res.loc.storage = OnUnknown 1066 1067 for i in 1..<prc.typ.n.len: 1068 let param = prc.typ.n[i].sym 1069 if param.typ.isCompileTimeOnly: continue 1070 assignParam(p, param, prc.typ[0]) 1071 closureSetup(p, prc) 1072 genProcBody(p, procBody) 1073 1074 var generatedProc: Rope 1075 generatedProc.genCLineDir prc.info, m.config 1076 if isNoReturn(p.module, prc): 1077 if hasDeclspec in extccomp.CC[p.config.cCompiler].props: 1078 header = "__declspec(noreturn) " & header 1079 if sfPure in prc.flags: 1080 if hasDeclspec in extccomp.CC[p.config.cCompiler].props: 1081 header = "__declspec(naked) " & header 1082 generatedProc.add ropecg(p.module, "$1 {$n$2$3$4}$N$N", 1083 [header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)]) 1084 else: 1085 if m.hcrOn and isReloadable(m, prc): 1086 # Add forward declaration for "_actual"-suffixed functions defined in the same module (or inline). 1087 # This fixes the use of methods and also the case when 2 functions within the same module 1088 # call each other using directly the "_actual" versions (an optimization) - see issue #11608 1089 m.s[cfsProcHeaders].addf("$1;\n", [header]) 1090 generatedProc.add ropecg(p.module, "$1 {$n", [header]) 1091 if optStackTrace in prc.options: 1092 generatedProc.add(p.s(cpsLocals)) 1093 var procname = makeCString(prc.name.s) 1094 generatedProc.add(initFrame(p, procname, quotedFilename(p.config, prc.info))) 1095 else: 1096 generatedProc.add(p.s(cpsLocals)) 1097 if optProfiler in prc.options: 1098 # invoke at proc entry for recursion: 1099 appcg(p, cpsInit, "\t#nimProfile();$n", []) 1100 # this pair of {} is required for C++ (C++ is weird with its 1101 # control flow integrity checks): 1102 if beforeRetNeeded in p.flags: generatedProc.add("{") 1103 generatedProc.add(p.s(cpsInit)) 1104 generatedProc.add(p.s(cpsStmts)) 1105 if beforeRetNeeded in p.flags: generatedProc.add(~"\t}BeforeRet_: ;$n") 1106 if optStackTrace in prc.options: generatedProc.add(deinitFrame(p)) 1107 generatedProc.add(returnStmt) 1108 generatedProc.add(~"}$N") 1109 m.s[cfsProcs].add(generatedProc) 1110 if isReloadable(m, prc): 1111 m.s[cfsDynLibInit].addf("\t$1 = ($3) hcrRegisterProc($4, \"$1\", (void*)$2);$n", 1112 [prc.loc.r, prc.loc.r & "_actual", getProcTypeCast(m, prc), getModuleDllPath(m, prc)]) 1113 1114proc requiresExternC(m: BModule; sym: PSym): bool {.inline.} = 1115 result = (sfCompileToCpp in m.module.flags and 1116 sfCompileToCpp notin sym.getModule().flags and 1117 m.config.backend != backendCpp) or ( 1118 sym.flags * {sfInfixCall, sfCompilerProc, sfMangleCpp} == {} and 1119 sym.flags * {sfImportc, sfExportc} != {} and 1120 sym.magic == mNone and 1121 m.config.backend == backendCpp) 1122 1123proc genProcPrototype(m: BModule, sym: PSym) = 1124 useHeader(m, sym) 1125 if lfNoDecl in sym.loc.flags: return 1126 if lfDynamicLib in sym.loc.flags: 1127 if sym.itemId.module != m.module.position and 1128 not containsOrIncl(m.declaredThings, sym.id): 1129 m.s[cfsVars].add(ropecg(m, "$1 $2 $3;$n", 1130 [(if isReloadable(m, sym): "static" else: "extern"), 1131 getTypeDesc(m, sym.loc.t), mangleDynLibProc(sym)])) 1132 if isReloadable(m, sym): 1133 m.s[cfsDynLibInit].addf("\t$1 = ($2) hcrGetProc($3, \"$1\");$n", 1134 [mangleDynLibProc(sym), getTypeDesc(m, sym.loc.t), getModuleDllPath(m, sym)]) 1135 elif not containsOrIncl(m.declaredProtos, sym.id): 1136 let asPtr = isReloadable(m, sym) 1137 var header = genProcHeader(m, sym, asPtr) 1138 if not asPtr: 1139 if isNoReturn(m, sym) and hasDeclspec in extccomp.CC[m.config.cCompiler].props: 1140 header = "__declspec(noreturn) " & header 1141 if sym.typ.callConv != ccInline and requiresExternC(m, sym): 1142 header = "extern \"C\" " & header 1143 if sfPure in sym.flags and hasAttribute in CC[m.config.cCompiler].props: 1144 header.add(" __attribute__((naked))") 1145 if isNoReturn(m, sym) and hasAttribute in CC[m.config.cCompiler].props: 1146 header.add(" __attribute__((noreturn))") 1147 m.s[cfsProcHeaders].add(ropecg(m, "$1;$N", [header])) 1148 1149# TODO: figure out how to rename this - it DOES generate a forward declaration 1150proc genProcNoForward(m: BModule, prc: PSym) = 1151 if lfImportCompilerProc in prc.loc.flags: 1152 fillProcLoc(m, prc.ast[namePos]) 1153 useHeader(m, prc) 1154 # dependency to a compilerproc: 1155 discard cgsym(m, prc.name.s) 1156 return 1157 if lfNoDecl in prc.loc.flags: 1158 fillProcLoc(m, prc.ast[namePos]) 1159 genProcPrototype(m, prc) 1160 elif prc.typ.callConv == ccInline: 1161 # We add inline procs to the calling module to enable C based inlining. 1162 # This also means that a check with ``q.declaredThings`` is wrong, we need 1163 # a check for ``m.declaredThings``. 1164 if not containsOrIncl(m.declaredThings, prc.id): 1165 #if prc.loc.k == locNone: 1166 # mangle the inline proc based on the module where it is defined - 1167 # not on the first module that uses it 1168 let m2 = if m.config.symbolFiles != disabledSf: m 1169 else: findPendingModule(m, prc) 1170 fillProcLoc(m2, prc.ast[namePos]) 1171 #elif {sfExportc, sfImportc} * prc.flags == {}: 1172 # # reset name to restore consistency in case of hashing collisions: 1173 # echo "resetting ", prc.id, " by ", m.module.name.s 1174 # prc.loc.r = nil 1175 # prc.loc.r = mangleName(m, prc) 1176 genProcPrototype(m, prc) 1177 genProcAux(m, prc) 1178 elif lfDynamicLib in prc.loc.flags: 1179 var q = findPendingModule(m, prc) 1180 fillProcLoc(q, prc.ast[namePos]) 1181 genProcPrototype(m, prc) 1182 if q != nil and not containsOrIncl(q.declaredThings, prc.id): 1183 symInDynamicLib(q, prc) 1184 # register the procedure even though it is in a different dynamic library and will not be 1185 # reloadable (and has no _actual suffix) - other modules will need to be able to get it through 1186 # the hcr dynlib (also put it in the DynLibInit section - right after it gets loaded) 1187 if isReloadable(q, prc): 1188 q.s[cfsDynLibInit].addf("\t$1 = ($2) hcrRegisterProc($3, \"$1\", (void*)$1);$n", 1189 [prc.loc.r, getTypeDesc(q, prc.loc.t), getModuleDllPath(m, q.module)]) 1190 else: 1191 symInDynamicLibPartial(m, prc) 1192 elif sfImportc notin prc.flags: 1193 var q = findPendingModule(m, prc) 1194 fillProcLoc(q, prc.ast[namePos]) 1195 # generate a getProc call to initialize the pointer for this 1196 # externally-to-the-current-module defined proc, also important 1197 # to do the declaredProtos check before the call to genProcPrototype 1198 if isReloadable(m, prc) and prc.id notin m.declaredProtos and 1199 q != nil and q.module.id != m.module.id: 1200 m.s[cfsDynLibInit].addf("\t$1 = ($2) hcrGetProc($3, \"$1\");$n", 1201 [prc.loc.r, getProcTypeCast(m, prc), getModuleDllPath(m, prc)]) 1202 genProcPrototype(m, prc) 1203 if q != nil and not containsOrIncl(q.declaredThings, prc.id): 1204 # make sure there is a "prototype" in the external module 1205 # which will actually become a function pointer 1206 if isReloadable(m, prc): 1207 genProcPrototype(q, prc) 1208 genProcAux(q, prc) 1209 else: 1210 fillProcLoc(m, prc.ast[namePos]) 1211 useHeader(m, prc) 1212 if sfInfixCall notin prc.flags: genProcPrototype(m, prc) 1213 1214proc requestConstImpl(p: BProc, sym: PSym) = 1215 if genConstSetup(p, sym): 1216 let m = p.module 1217 # declare implementation: 1218 var q = findPendingModule(m, sym) 1219 if q != nil and not containsOrIncl(q.declaredThings, sym.id): 1220 assert q.initProc.module == q 1221 genConstDefinition(q, p, sym) 1222 # declare header: 1223 if q != m and not containsOrIncl(m.declaredThings, sym.id): 1224 genConstHeader(m, q, p, sym) 1225 1226proc isActivated(prc: PSym): bool = prc.typ != nil 1227 1228proc genProc(m: BModule, prc: PSym) = 1229 if sfBorrow in prc.flags or not isActivated(prc): return 1230 if sfForward in prc.flags: 1231 addForwardedProc(m, prc) 1232 fillProcLoc(m, prc.ast[namePos]) 1233 else: 1234 genProcNoForward(m, prc) 1235 if {sfExportc, sfCompilerProc} * prc.flags == {sfExportc} and 1236 m.g.generatedHeader != nil and lfNoDecl notin prc.loc.flags: 1237 genProcPrototype(m.g.generatedHeader, prc) 1238 if prc.typ.callConv == ccInline: 1239 if not containsOrIncl(m.g.generatedHeader.declaredThings, prc.id): 1240 genProcAux(m.g.generatedHeader, prc) 1241 1242proc genVarPrototype(m: BModule, n: PNode) = 1243 #assert(sfGlobal in sym.flags) 1244 let sym = n.sym 1245 useHeader(m, sym) 1246 fillLoc(sym.loc, locGlobalVar, n, mangleName(m, sym), OnHeap) 1247 if treatGlobalDifferentlyForHCR(m, sym): incl(sym.loc.flags, lfIndirect) 1248 1249 if (lfNoDecl in sym.loc.flags) or contains(m.declaredThings, sym.id): 1250 return 1251 if sym.owner.id != m.module.id: 1252 # else we already have the symbol generated! 1253 assert(sym.loc.r != nil) 1254 if sfThread in sym.flags: 1255 declareThreadVar(m, sym, true) 1256 else: 1257 incl(m.declaredThings, sym.id) 1258 if sym.kind in {skLet, skVar, skField, skForVar} and sym.alignment > 0: 1259 m.s[cfsVars].addf "NIM_ALIGN($1) ", [rope(sym.alignment)] 1260 m.s[cfsVars].add(if m.hcrOn: "static " else: "extern ") 1261 m.s[cfsVars].add(getTypeDesc(m, sym.loc.t, skVar)) 1262 if m.hcrOn: m.s[cfsVars].add("*") 1263 if lfDynamicLib in sym.loc.flags: m.s[cfsVars].add("*") 1264 if sfRegister in sym.flags: m.s[cfsVars].add(" register") 1265 if sfVolatile in sym.flags: m.s[cfsVars].add(" volatile") 1266 if sfNoalias in sym.flags: m.s[cfsVars].add(" NIM_NOALIAS") 1267 m.s[cfsVars].addf(" $1;$n", [sym.loc.r]) 1268 if m.hcrOn: m.initProc.procSec(cpsLocals).addf( 1269 "\t$1 = ($2*)hcrGetGlobal($3, \"$1\");$n", [sym.loc.r, 1270 getTypeDesc(m, sym.loc.t, skVar), getModuleDllPath(m, sym)]) 1271 1272proc addNimDefines(result: var Rope; conf: ConfigRef) {.inline.} = 1273 result.addf("#define NIM_INTBITS $1\L", [ 1274 platform.CPU[conf.target.targetCPU].intSize.rope]) 1275 if conf.cppCustomNamespace.len > 0: 1276 result.add("#define USE_NIM_NAMESPACE ") 1277 result.add(conf.cppCustomNamespace) 1278 result.add("\L") 1279 if conf.isDefined("nimEmulateOverflowChecks"): 1280 result.add("#define NIM_EmulateOverflowChecks\L") 1281 1282proc headerTop(): Rope = 1283 result = "/* Generated by Nim Compiler v$1 */$N" % [rope(VersionAsString)] 1284 1285proc getCopyright(conf: ConfigRef; cfile: Cfile): Rope = 1286 result = headerTop() 1287 if optCompileOnly notin conf.globalOptions: 1288 result.add ("/* Compiled for: $1, $2, $3 */$N" & 1289 "/* Command for C compiler:$n $4 */$N") % 1290 [rope(platform.OS[conf.target.targetOS].name), 1291 rope(platform.CPU[conf.target.targetCPU].name), 1292 rope(extccomp.CC[conf.cCompiler].name), 1293 rope(getCompileCFileCmd(conf, cfile))] 1294 1295proc getFileHeader(conf: ConfigRef; cfile: Cfile): Rope = 1296 result = getCopyright(conf, cfile) 1297 if conf.hcrOn: result.add("#define NIM_HOT_CODE_RELOADING\L") 1298 addNimDefines(result, conf) 1299 1300proc getSomeNameForModule(m: PSym): Rope = 1301 assert m.kind == skModule 1302 assert m.owner.kind == skPackage 1303 if {sfSystemModule, sfMainModule} * m.flags == {}: 1304 result = m.owner.name.s.mangle.rope 1305 result.add "_" 1306 result.add m.name.s.mangle 1307 1308proc getSomeInitName(m: BModule, suffix: string): Rope = 1309 if not m.hcrOn: 1310 result = getSomeNameForModule(m.module) 1311 result.add suffix 1312 1313proc getInitName(m: BModule): Rope = 1314 if sfMainModule in m.module.flags: 1315 # generate constant name for main module, for "easy" debugging. 1316 result = rope"NimMainModule" 1317 else: 1318 result = getSomeInitName(m, "Init000") 1319 1320proc getDatInitName(m: BModule): Rope = getSomeInitName(m, "DatInit000") 1321proc getHcrInitName(m: BModule): Rope = getSomeInitName(m, "HcrInit000") 1322 1323proc hcrGetProcLoadCode(m: BModule, sym, prefix, handle, getProcFunc: string): Rope 1324 1325proc genMainProc(m: BModule) = 1326 ## this function is called in cgenWriteModules after all modules are closed, 1327 ## it means raising dependency on the symbols is too late as it will not propagate 1328 ## into other modules, only simple rope manipulations are allowed 1329 1330 var preMainCode: Rope 1331 if m.hcrOn: 1332 proc loadLib(handle: string, name: string): Rope = 1333 let prc = magicsys.getCompilerProc(m.g.graph, name) 1334 assert prc != nil 1335 let n = newStrNode(nkStrLit, prc.annex.path.strVal) 1336 n.info = prc.annex.path.info 1337 appcg(m, result, "\tif (!($1 = #nimLoadLibrary($2)))$N" & 1338 "\t\t#nimLoadLibraryError($2);$N", 1339 [handle, genStringLiteral(m, n)]) 1340 1341 preMainCode.add(loadLib("hcr_handle", "hcrGetProc")) 1342 preMainCode.add("\tvoid* rtl_handle;\L") 1343 preMainCode.add(loadLib("rtl_handle", "nimGC_setStackBottom")) 1344 preMainCode.add(hcrGetProcLoadCode(m, "nimGC_setStackBottom", "nimrtl_", "rtl_handle", "nimGetProcAddr")) 1345 preMainCode.add("\tinner = PreMain;\L") 1346 preMainCode.add("\tinitStackBottomWith_actual((void *)&inner);\L") 1347 preMainCode.add("\t(*inner)();\L") 1348 else: 1349 preMainCode.add("\tPreMain();\L") 1350 1351 const 1352 # not a big deal if we always compile these 3 global vars... makes the HCR code easier 1353 PosixCmdLine = 1354 "N_LIB_PRIVATE int cmdCount;$N" & 1355 "N_LIB_PRIVATE char** cmdLine;$N" & 1356 "N_LIB_PRIVATE char** gEnv;$N" 1357 1358 # The use of a volatile function pointer to call Pre/NimMainInner 1359 # prevents inlining of the NimMainInner function and dependent 1360 # functions, which might otherwise merge their stack frames. 1361 PreMainBody = "$N" & 1362 "N_LIB_PRIVATE void PreMainInner(void) {$N" & 1363 "$2" & 1364 "}$N$N" & 1365 PosixCmdLine & 1366 "N_LIB_PRIVATE void PreMain(void) {$N" & 1367 "\tvoid (*volatile inner)(void);$N" & 1368 "\tinner = PreMainInner;$N" & 1369 "$1" & 1370 "\t(*inner)();$N" & 1371 "}$N$N" 1372 1373 MainProcs = 1374 "\t$^NimMain();$N" 1375 1376 MainProcsWithResult = 1377 MainProcs & ("\treturn $1nim_program_result;$N") 1378 1379 NimMainInner = "N_LIB_PRIVATE N_CDECL(void, NimMainInner)(void) {$N" & 1380 "$1" & 1381 "}$N$N" 1382 1383 NimMainProc = 1384 "N_CDECL(void, $5NimMain)(void) {$N" & 1385 "\tvoid (*volatile inner)(void);$N" & 1386 "$4" & 1387 "\tinner = NimMainInner;$N" & 1388 "$2" & 1389 "\t(*inner)();$N" & 1390 "}$N$N" 1391 1392 NimMainBody = NimMainInner & NimMainProc 1393 1394 PosixCMain = 1395 "int main(int argc, char** args, char** env) {$N" & 1396 "\tcmdLine = args;$N" & 1397 "\tcmdCount = argc;$N" & 1398 "\tgEnv = env;$N" & 1399 MainProcsWithResult & 1400 "}$N$N" 1401 1402 StandaloneCMain = 1403 "int main(void) {$N" & 1404 MainProcs & 1405 "\treturn 0;$N" & 1406 "}$N$N" 1407 1408 WinNimMain = NimMainBody 1409 1410 WinCMain = "N_STDCALL(int, WinMain)(HINSTANCE hCurInstance, $N" & 1411 " HINSTANCE hPrevInstance, $N" & 1412 " LPSTR lpCmdLine, int nCmdShow) {$N" & 1413 MainProcsWithResult & "}$N$N" 1414 1415 WinNimDllMain = NimMainInner & "N_LIB_EXPORT " & NimMainProc 1416 1417 WinCDllMain = 1418 "BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fwdreason, $N" & 1419 " LPVOID lpvReserved) {$N" & 1420 "\tif(fwdreason == DLL_PROCESS_ATTACH) {$N" & MainProcs & "}$N" & 1421 "\treturn 1;$N}$N$N" 1422 1423 PosixNimDllMain = WinNimDllMain 1424 1425 PosixCDllMain = 1426 "N_LIB_PRIVATE void NIM_POSIX_INIT NimMainInit(void) {$N" & 1427 MainProcs & 1428 "}$N$N" 1429 1430 GenodeNimMain = 1431 "extern Genode::Env *nim_runtime_env;$N" & 1432 "extern \"C\" void nim_component_construct(Genode::Env*);$N$N" & 1433 NimMainBody 1434 1435 ComponentConstruct = 1436 "void Libc::Component::construct(Libc::Env &env) {$N" & 1437 "\t// Set Env used during runtime initialization$N" & 1438 "\tnim_runtime_env = &env;$N" & 1439 "\tLibc::with_libc([&] () {$N\t" & 1440 "\t// Initialize runtime and globals$N" & 1441 MainProcs & 1442 "\t// Call application construct$N" & 1443 "\t\tnim_component_construct(&env);$N" & 1444 "\t});$N" & 1445 "}$N$N" 1446 1447 if m.config.target.targetOS == osWindows and 1448 m.config.globalOptions * {optGenGuiApp, optGenDynLib} != {}: 1449 m.includeHeader("<windows.h>") 1450 elif m.config.target.targetOS == osGenode: 1451 m.includeHeader("<libc/component.h>") 1452 1453 let initStackBottomCall = 1454 if m.config.target.targetOS == osStandalone or m.config.selectedGC == gcNone: "".rope 1455 else: ropecg(m, "\t#initStackBottomWith((void *)&inner);$N", []) 1456 inc(m.labels) 1457 appcg(m, m.s[cfsProcs], PreMainBody, [m.g.mainDatInit, m.g.otherModsInit]) 1458 1459 if m.config.target.targetOS == osWindows and 1460 m.config.globalOptions * {optGenGuiApp, optGenDynLib} != {}: 1461 if optGenGuiApp in m.config.globalOptions: 1462 const nimMain = WinNimMain 1463 appcg(m, m.s[cfsProcs], nimMain, 1464 [m.g.mainModInit, initStackBottomCall, m.labels, preMainCode, m.config.nimMainPrefix]) 1465 else: 1466 const nimMain = WinNimDllMain 1467 appcg(m, m.s[cfsProcs], nimMain, 1468 [m.g.mainModInit, initStackBottomCall, m.labels, preMainCode, m.config.nimMainPrefix]) 1469 elif m.config.target.targetOS == osGenode: 1470 const nimMain = GenodeNimMain 1471 appcg(m, m.s[cfsProcs], nimMain, 1472 [m.g.mainModInit, initStackBottomCall, m.labels, preMainCode, m.config.nimMainPrefix]) 1473 elif optGenDynLib in m.config.globalOptions: 1474 const nimMain = PosixNimDllMain 1475 appcg(m, m.s[cfsProcs], nimMain, 1476 [m.g.mainModInit, initStackBottomCall, m.labels, preMainCode, m.config.nimMainPrefix]) 1477 elif m.config.target.targetOS == osStandalone: 1478 const nimMain = NimMainBody 1479 appcg(m, m.s[cfsProcs], nimMain, 1480 [m.g.mainModInit, initStackBottomCall, m.labels, preMainCode, m.config.nimMainPrefix]) 1481 else: 1482 const nimMain = NimMainBody 1483 appcg(m, m.s[cfsProcs], nimMain, 1484 [m.g.mainModInit, initStackBottomCall, m.labels, preMainCode, m.config.nimMainPrefix]) 1485 1486 if optNoMain notin m.config.globalOptions: 1487 if m.config.cppCustomNamespace.len > 0: 1488 m.s[cfsProcs].add closeNamespaceNim() & "using namespace " & m.config.cppCustomNamespace & ";\L" 1489 1490 if m.config.target.targetOS == osWindows and 1491 m.config.globalOptions * {optGenGuiApp, optGenDynLib} != {}: 1492 if optGenGuiApp in m.config.globalOptions: 1493 const otherMain = WinCMain 1494 appcg(m, m.s[cfsProcs], otherMain, [if m.hcrOn: "*" else: "", m.config.nimMainPrefix]) 1495 else: 1496 const otherMain = WinCDllMain 1497 appcg(m, m.s[cfsProcs], otherMain, [m.config.nimMainPrefix]) 1498 elif m.config.target.targetOS == osGenode: 1499 const otherMain = ComponentConstruct 1500 appcg(m, m.s[cfsProcs], otherMain, [m.config.nimMainPrefix]) 1501 elif optGenDynLib in m.config.globalOptions: 1502 const otherMain = PosixCDllMain 1503 appcg(m, m.s[cfsProcs], otherMain, [m.config.nimMainPrefix]) 1504 elif m.config.target.targetOS == osStandalone: 1505 const otherMain = StandaloneCMain 1506 appcg(m, m.s[cfsProcs], otherMain, [m.config.nimMainPrefix]) 1507 else: 1508 const otherMain = PosixCMain 1509 appcg(m, m.s[cfsProcs], otherMain, [if m.hcrOn: "*" else: "", m.config.nimMainPrefix]) 1510 1511 if m.config.cppCustomNamespace.len > 0: 1512 m.s[cfsProcs].add openNamespaceNim(m.config.cppCustomNamespace) 1513 1514proc registerInitProcs*(g: BModuleList; m: PSym; flags: set[ModuleBackendFlag]) = 1515 ## Called from the IC backend. 1516 if HasDatInitProc in flags: 1517 let datInit = getSomeNameForModule(m) & "DatInit000" 1518 g.mainModProcs.addf("N_LIB_PRIVATE N_NIMCALL(void, $1)(void);$N", [datInit]) 1519 g.mainDatInit.addf("\t$1();$N", [datInit]) 1520 if HasModuleInitProc in flags: 1521 let init = getSomeNameForModule(m) & "Init000" 1522 g.mainModProcs.addf("N_LIB_PRIVATE N_NIMCALL(void, $1)(void);$N", [init]) 1523 let initCall = "\t$1();$N" % [init] 1524 if sfMainModule in m.flags: 1525 g.mainModInit.add(initCall) 1526 elif sfSystemModule in m.flags: 1527 g.mainDatInit.add(initCall) # systemInit must called right after systemDatInit if any 1528 else: 1529 g.otherModsInit.add(initCall) 1530 1531proc whichInitProcs*(m: BModule): set[ModuleBackendFlag] = 1532 # called from IC. 1533 result = {} 1534 if m.hcrOn or m.preInitProc.s(cpsInit).len > 0 or m.preInitProc.s(cpsStmts).len > 0: 1535 result.incl HasModuleInitProc 1536 for i in cfsTypeInit1..cfsDynLibInit: 1537 if m.s[i].len != 0: 1538 result.incl HasDatInitProc 1539 break 1540 1541proc registerModuleToMain(g: BModuleList; m: BModule) = 1542 let 1543 init = m.getInitName 1544 datInit = m.getDatInitName 1545 1546 if m.hcrOn: 1547 var hcrModuleMeta = "$nN_LIB_PRIVATE const char* hcr_module_list[] = {$n" % [] 1548 let systemModulePath = getModuleDllPath(m, g.modules[g.graph.config.m.systemFileIdx.int].module) 1549 let mainModulePath = getModuleDllPath(m, m.module) 1550 if sfMainModule in m.module.flags: 1551 hcrModuleMeta.addf("\t$1,$n", [systemModulePath]) 1552 g.graph.importDeps.withValue(FileIndex(m.module.position), deps): 1553 for curr in deps[]: 1554 hcrModuleMeta.addf("\t$1,$n", [getModuleDllPath(m, g.modules[curr.int].module)]) 1555 hcrModuleMeta.addf("\t\"\"};$n", []) 1556 hcrModuleMeta.addf("$nN_LIB_EXPORT N_NIMCALL(void**, HcrGetImportedModules)() { return (void**)hcr_module_list; }$n", []) 1557 hcrModuleMeta.addf("$nN_LIB_EXPORT N_NIMCALL(char*, HcrGetSigHash)() { return \"$1\"; }$n$n", 1558 [($sigHash(m.module)).rope]) 1559 if sfMainModule in m.module.flags: 1560 g.mainModProcs.add(hcrModuleMeta) 1561 g.mainModProcs.addf("static void* hcr_handle;$N", []) 1562 g.mainModProcs.addf("N_LIB_EXPORT N_NIMCALL(void, $1)(void);$N", [init]) 1563 g.mainModProcs.addf("N_LIB_EXPORT N_NIMCALL(void, $1)(void);$N", [datInit]) 1564 g.mainModProcs.addf("N_LIB_EXPORT N_NIMCALL(void, $1)(void*, N_NIMCALL_PTR(void*, getProcAddr)(void*, char*));$N", [m.getHcrInitName]) 1565 g.mainModProcs.addf("N_LIB_EXPORT N_NIMCALL(void, HcrCreateTypeInfos)(void);$N", []) 1566 g.mainModInit.addf("\t$1();$N", [init]) 1567 g.otherModsInit.addf("\thcrInit((void**)hcr_module_list, $1, $2, $3, hcr_handle, nimGetProcAddr);$n", 1568 [mainModulePath, systemModulePath, datInit]) 1569 g.mainDatInit.addf("\t$1(hcr_handle, nimGetProcAddr);$N", [m.getHcrInitName]) 1570 g.mainDatInit.addf("\thcrAddModule($1);\n", [mainModulePath]) 1571 g.mainDatInit.addf("\tHcrCreateTypeInfos();$N", []) 1572 # nasty nasty hack to get the command line functionality working with HCR 1573 # register the 2 variables on behalf of the os module which might not even 1574 # be loaded (in which case it will get collected but that is not a problem) 1575 # EDIT: indeed, this hack, in combination with another un-necessary one 1576 # (`makeCString` was doing line wrap of string litterals) was root cause for 1577 # bug #16265. 1578 let osModulePath = ($systemModulePath).replace("stdlib_system", "stdlib_os").rope 1579 g.mainDatInit.addf("\thcrAddModule($1);\n", [osModulePath]) 1580 g.mainDatInit.add("\tint* cmd_count;\n") 1581 g.mainDatInit.add("\tchar*** cmd_line;\n") 1582 g.mainDatInit.addf("\thcrRegisterGlobal($1, \"cmdCount\", sizeof(cmd_count), NULL, (void**)&cmd_count);$N", [osModulePath]) 1583 g.mainDatInit.addf("\thcrRegisterGlobal($1, \"cmdLine\", sizeof(cmd_line), NULL, (void**)&cmd_line);$N", [osModulePath]) 1584 g.mainDatInit.add("\t*cmd_count = cmdCount;\n") 1585 g.mainDatInit.add("\t*cmd_line = cmdLine;\n") 1586 else: 1587 m.s[cfsInitProc].add(hcrModuleMeta) 1588 return 1589 1590 if m.s[cfsDatInitProc].len > 0: 1591 g.mainModProcs.addf("N_LIB_PRIVATE N_NIMCALL(void, $1)(void);$N", [datInit]) 1592 g.mainDatInit.addf("\t$1();$N", [datInit]) 1593 1594 # Initialization of TLS and GC should be done in between 1595 # systemDatInit and systemInit calls if any 1596 if sfSystemModule in m.module.flags: 1597 if emulatedThreadVars(m.config) and m.config.target.targetOS != osStandalone: 1598 g.mainDatInit.add(ropecg(m, "\t#initThreadVarsEmulation();$N", [])) 1599 if m.config.target.targetOS != osStandalone and m.config.selectedGC notin {gcNone, gcArc, gcOrc}: 1600 g.mainDatInit.add(ropecg(m, "\t#initStackBottomWith((void *)&inner);$N", [])) 1601 1602 if m.s[cfsInitProc].len > 0: 1603 g.mainModProcs.addf("N_LIB_PRIVATE N_NIMCALL(void, $1)(void);$N", [init]) 1604 let initCall = "\t$1();$N" % [init] 1605 if sfMainModule in m.module.flags: 1606 g.mainModInit.add(initCall) 1607 elif sfSystemModule in m.module.flags: 1608 g.mainDatInit.add(initCall) # systemInit must called right after systemDatInit if any 1609 else: 1610 g.otherModsInit.add(initCall) 1611 1612proc genDatInitCode(m: BModule) = 1613 ## this function is called in cgenWriteModules after all modules are closed, 1614 ## it means raising dependency on the symbols is too late as it will not propagate 1615 ## into other modules, only simple rope manipulations are allowed 1616 1617 var moduleDatInitRequired = m.hcrOn 1618 1619 var prc = "$1 N_NIMCALL(void, $2)(void) {$N" % 1620 [rope(if m.hcrOn: "N_LIB_EXPORT" else: "N_LIB_PRIVATE"), getDatInitName(m)] 1621 1622 # we don't want to break into such init code - could happen if a line 1623 # directive from a function written by the user spills after itself 1624 genCLineDir(prc, "generated_not_to_break_here", 999999, m.config) 1625 1626 for i in cfsTypeInit1..cfsDynLibInit: 1627 if m.s[i].len != 0: 1628 moduleDatInitRequired = true 1629 prc.add(m.s[i]) 1630 1631 prc.addf("}$N$N", []) 1632 1633 if moduleDatInitRequired: 1634 m.s[cfsDatInitProc].add(prc) 1635 #rememberFlag(m.g.graph, m.module, HasDatInitProc) 1636 1637# Very similar to the contents of symInDynamicLib - basically only the 1638# things needed for the hot code reloading runtime procs to be loaded 1639proc hcrGetProcLoadCode(m: BModule, sym, prefix, handle, getProcFunc: string): Rope = 1640 let prc = magicsys.getCompilerProc(m.g.graph, sym) 1641 assert prc != nil 1642 fillProcLoc(m, prc.ast[namePos]) 1643 1644 var extname = prefix & sym 1645 var tmp = mangleDynLibProc(prc) 1646 prc.loc.r = tmp 1647 prc.typ.sym = nil 1648 1649 if not containsOrIncl(m.declaredThings, prc.id): 1650 m.s[cfsVars].addf("static $2 $1;$n", [prc.loc.r, getTypeDesc(m, prc.loc.t, skVar)]) 1651 1652 result = "\t$1 = ($2) $3($4, $5);$n" % 1653 [tmp, getTypeDesc(m, prc.typ, skVar), getProcFunc.rope, handle.rope, makeCString(prefix & sym)] 1654 1655proc genInitCode(m: BModule) = 1656 ## this function is called in cgenWriteModules after all modules are closed, 1657 ## it means raising dependency on the symbols is too late as it will not propagate 1658 ## into other modules, only simple rope manipulations are allowed 1659 var moduleInitRequired = m.hcrOn 1660 let initname = getInitName(m) 1661 var prc = "$1 N_NIMCALL(void, $2)(void) {$N" % 1662 [rope(if m.hcrOn: "N_LIB_EXPORT" else: "N_LIB_PRIVATE"), initname] 1663 # we don't want to break into such init code - could happen if a line 1664 # directive from a function written by the user spills after itself 1665 genCLineDir(prc, "generated_not_to_break_here", 999999, m.config) 1666 if m.typeNodes > 0: 1667 if m.hcrOn: 1668 appcg(m, m.s[cfsTypeInit1], "\t#TNimNode* $1;$N", [m.typeNodesName]) 1669 appcg(m, m.s[cfsTypeInit1], "\thcrRegisterGlobal($3, \"$1_$2\", sizeof(TNimNode) * $2, NULL, (void**)&$1);$N", 1670 [m.typeNodesName, m.typeNodes, getModuleDllPath(m, m.module)]) 1671 else: 1672 appcg(m, m.s[cfsTypeInit1], "static #TNimNode $1[$2];$n", 1673 [m.typeNodesName, m.typeNodes]) 1674 if m.nimTypes > 0: 1675 appcg(m, m.s[cfsTypeInit1], "static #TNimType $1[$2];$n", 1676 [m.nimTypesName, m.nimTypes]) 1677 1678 if m.hcrOn: 1679 prc.addf("\tint* nim_hcr_dummy_ = 0;$n" & 1680 "\tNIM_BOOL nim_hcr_do_init_ = " & 1681 "hcrRegisterGlobal($1, \"module_initialized_\", 1, NULL, (void**)&nim_hcr_dummy_);$n", 1682 [getModuleDllPath(m, m.module)]) 1683 1684 template writeSection(thing: untyped, section: TCProcSection, addHcrGuards = false) = 1685 if m.thing.s(section).len > 0: 1686 moduleInitRequired = true 1687 if addHcrGuards: prc.add("\tif (nim_hcr_do_init_) {\n\n") 1688 prc.add(m.thing.s(section)) 1689 if addHcrGuards: prc.add("\n\t} // nim_hcr_do_init_\n") 1690 1691 if m.preInitProc.s(cpsInit).len > 0 or m.preInitProc.s(cpsStmts).len > 0: 1692 # Give this small function its own scope 1693 prc.addf("{$N", []) 1694 # Keep a bogus frame in case the code needs one 1695 prc.add(~"\tTFrame FR_; FR_.len = 0;$N") 1696 1697 writeSection(preInitProc, cpsLocals) 1698 writeSection(preInitProc, cpsInit, m.hcrOn) 1699 writeSection(preInitProc, cpsStmts) 1700 prc.addf("}/* preInitProc end */$N", []) 1701 when false: 1702 m.initProc.blocks[0].sections[cpsLocals].add m.preInitProc.s(cpsLocals) 1703 m.initProc.blocks[0].sections[cpsInit].prepend m.preInitProc.s(cpsInit) 1704 m.initProc.blocks[0].sections[cpsStmts].prepend m.preInitProc.s(cpsStmts) 1705 1706 # add new scope for following code, because old vcc compiler need variable 1707 # be defined at the top of the block 1708 prc.addf("{$N", []) 1709 writeSection(initProc, cpsLocals) 1710 1711 if m.initProc.s(cpsInit).len > 0 or m.initProc.s(cpsStmts).len > 0: 1712 moduleInitRequired = true 1713 if optStackTrace in m.initProc.options and frameDeclared notin m.flags: 1714 # BUT: the generated init code might depend on a current frame, so 1715 # declare it nevertheless: 1716 incl m.flags, frameDeclared 1717 if preventStackTrace notin m.flags: 1718 var procname = makeCString(m.module.name.s) 1719 prc.add(initFrame(m.initProc, procname, quotedFilename(m.config, m.module.info))) 1720 else: 1721 prc.add(~"\tTFrame FR_; FR_.len = 0;$N") 1722 1723 writeSection(initProc, cpsInit, m.hcrOn) 1724 writeSection(initProc, cpsStmts) 1725 1726 if beforeRetNeeded in m.initProc.flags: 1727 prc.add(~"\tBeforeRet_: ;$n") 1728 1729 if sfMainModule in m.module.flags and m.config.exc == excGoto: 1730 if getCompilerProc(m.g.graph, "nimTestErrorFlag") != nil: 1731 m.appcg(prc, "\t#nimTestErrorFlag();$n", []) 1732 1733 if optStackTrace in m.initProc.options and preventStackTrace notin m.flags: 1734 prc.add(deinitFrame(m.initProc)) 1735 1736 prc.addf("}$N", []) 1737 1738 prc.addf("}$N$N", []) 1739 1740 # we cannot simply add the init proc to ``m.s[cfsProcs]`` anymore because 1741 # that would lead to a *nesting* of merge sections which the merger does 1742 # not support. So we add it to another special section: ``cfsInitProc`` 1743 1744 if m.hcrOn: 1745 var procsToLoad = @["hcrRegisterProc", "hcrGetProc", "hcrRegisterGlobal", "hcrGetGlobal"] 1746 1747 m.s[cfsInitProc].addf("N_LIB_EXPORT N_NIMCALL(void, $1)(void* handle, N_NIMCALL_PTR(void*, getProcAddr)(void*, char*)) {$N", [getHcrInitName(m)]) 1748 if sfMainModule in m.module.flags: 1749 # additional procs to load 1750 procsToLoad.add("hcrInit") 1751 procsToLoad.add("hcrAddModule") 1752 # load procs 1753 for curr in procsToLoad: 1754 m.s[cfsInitProc].add(hcrGetProcLoadCode(m, curr, "", "handle", "getProcAddr")) 1755 m.s[cfsInitProc].addf("}$N$N", []) 1756 1757 for i, el in pairs(m.extensionLoaders): 1758 if el != nil: 1759 let ex = "NIM_EXTERNC N_NIMCALL(void, nimLoadProcs$1)(void) {$2}$N$N" % 1760 [(i.ord - '0'.ord).rope, el] 1761 moduleInitRequired = true 1762 prc.add(ex) 1763 1764 if moduleInitRequired or sfMainModule in m.module.flags: 1765 m.s[cfsInitProc].add(prc) 1766 #rememberFlag(m.g.graph, m.module, HasModuleInitProc) 1767 1768 genDatInitCode(m) 1769 1770 if m.hcrOn: 1771 m.s[cfsInitProc].addf("N_LIB_EXPORT N_NIMCALL(void, HcrCreateTypeInfos)(void) {$N", []) 1772 m.s[cfsInitProc].add(m.hcrCreateTypeInfosProc) 1773 m.s[cfsInitProc].addf("}$N$N", []) 1774 1775 registerModuleToMain(m.g, m) 1776 1777proc genModule(m: BModule, cfile: Cfile): Rope = 1778 var moduleIsEmpty = true 1779 1780 result = getFileHeader(m.config, cfile) 1781 1782 generateThreadLocalStorage(m) 1783 generateHeaders(m) 1784 result.add(m.s[cfsHeaders]) 1785 if m.config.cppCustomNamespace.len > 0: 1786 result.add openNamespaceNim(m.config.cppCustomNamespace) 1787 if m.s[cfsFrameDefines].len > 0: 1788 result.add(m.s[cfsFrameDefines]) 1789 else: 1790 result.add("#define nimfr_(x, y)\n#define nimln_(x, y)\n") 1791 1792 for i in cfsForwardTypes..cfsProcs: 1793 if m.s[i].len > 0: 1794 moduleIsEmpty = false 1795 result.add(m.s[i]) 1796 1797 if m.s[cfsInitProc].len > 0: 1798 moduleIsEmpty = false 1799 result.add(m.s[cfsInitProc]) 1800 if m.s[cfsDatInitProc].len > 0 or m.hcrOn: 1801 moduleIsEmpty = false 1802 result.add(m.s[cfsDatInitProc]) 1803 1804 if m.config.cppCustomNamespace.len > 0: 1805 result.add closeNamespaceNim() 1806 1807 if moduleIsEmpty: 1808 result = nil 1809 1810proc initProcOptions(m: BModule): TOptions = 1811 let opts = m.config.options 1812 if sfSystemModule in m.module.flags: opts-{optStackTrace} else: opts 1813 1814proc rawNewModule(g: BModuleList; module: PSym, filename: AbsoluteFile): BModule = 1815 new(result) 1816 result.g = g 1817 result.tmpBase = rope("TM" & $hashOwner(module) & "_") 1818 result.headerFiles = @[] 1819 result.declaredThings = initIntSet() 1820 result.declaredProtos = initIntSet() 1821 result.cfilename = filename 1822 result.filename = filename 1823 result.typeCache = initTable[SigHash, Rope]() 1824 result.forwTypeCache = initTable[SigHash, Rope]() 1825 result.module = module 1826 result.typeInfoMarker = initTable[SigHash, Rope]() 1827 result.sigConflicts = initCountTable[SigHash]() 1828 result.initProc = newProc(nil, result) 1829 result.initProc.options = initProcOptions(result) 1830 result.preInitProc = newProc(nil, result) 1831 result.preInitProc.flags.incl nimErrorFlagDisabled 1832 result.preInitProc.labels = 100_000 # little hack so that unique temporaries are generated 1833 initNodeTable(result.dataCache) 1834 result.typeStack = @[] 1835 result.typeNodesName = getTempName(result) 1836 result.nimTypesName = getTempName(result) 1837 # no line tracing for the init sections of the system module so that we 1838 # don't generate a TFrame which can confuse the stack bottom initialization: 1839 if sfSystemModule in module.flags: 1840 incl result.flags, preventStackTrace 1841 excl(result.preInitProc.options, optStackTrace) 1842 let ndiName = if optCDebug in g.config.globalOptions: changeFileExt(completeCfilePath(g.config, filename), "ndi") 1843 else: AbsoluteFile"" 1844 open(result.ndi, ndiName, g.config) 1845 1846proc rawNewModule(g: BModuleList; module: PSym; conf: ConfigRef): BModule = 1847 result = rawNewModule(g, module, AbsoluteFile toFullPath(conf, module.position.FileIndex)) 1848 1849proc newModule*(g: BModuleList; module: PSym; conf: ConfigRef): BModule = 1850 # we should create only one cgen module for each module sym 1851 result = rawNewModule(g, module, conf) 1852 if module.position >= g.modules.len: 1853 setLen(g.modules, module.position + 1) 1854 #growCache g.modules, module.position 1855 g.modules[module.position] = result 1856 1857template injectG() {.dirty.} = 1858 if graph.backend == nil: 1859 graph.backend = newModuleList(graph) 1860 let g = BModuleList(graph.backend) 1861 1862when not defined(nimHasSinkInference): 1863 {.pragma: nosinks.} 1864 1865proc myOpen(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext {.nosinks.} = 1866 injectG() 1867 result = newModule(g, module, graph.config) 1868 result.idgen = idgen 1869 if optGenIndex in graph.config.globalOptions and g.generatedHeader == nil: 1870 let f = if graph.config.headerFile.len > 0: AbsoluteFile graph.config.headerFile 1871 else: graph.config.projectFull 1872 g.generatedHeader = rawNewModule(g, module, 1873 changeFileExt(completeCfilePath(graph.config, f), hExt)) 1874 incl g.generatedHeader.flags, isHeaderFile 1875 1876proc writeHeader(m: BModule) = 1877 var result = headerTop() 1878 var guard = "__$1__" % [m.filename.splitFile.name.rope] 1879 result.addf("#ifndef $1$n#define $1$n", [guard]) 1880 addNimDefines(result, m.config) 1881 generateHeaders(m) 1882 1883 generateThreadLocalStorage(m) 1884 for i in cfsHeaders..cfsProcs: 1885 result.add(m.s[i]) 1886 if m.config.cppCustomNamespace.len > 0 and i == cfsHeaders: result.add openNamespaceNim(m.config.cppCustomNamespace) 1887 result.add(m.s[cfsInitProc]) 1888 1889 if optGenDynLib in m.config.globalOptions: 1890 result.add("N_LIB_IMPORT ") 1891 result.addf("N_CDECL(void, $1NimMain)(void);$n", [rope m.config.nimMainPrefix]) 1892 if m.config.cppCustomNamespace.len > 0: result.add closeNamespaceNim() 1893 result.addf("#endif /* $1 */$n", [guard]) 1894 if not writeRope(result, m.filename): 1895 rawMessage(m.config, errCannotOpenFile, m.filename.string) 1896 1897proc getCFile(m: BModule): AbsoluteFile = 1898 let ext = 1899 if m.compileToCpp: ".nim.cpp" 1900 elif m.config.backend == backendObjc or sfCompileToObjc in m.module.flags: ".nim.m" 1901 else: ".nim.c" 1902 result = changeFileExt(completeCfilePath(m.config, withPackageName(m.config, m.cfilename)), ext) 1903 1904when false: 1905 proc myOpenCached(graph: ModuleGraph; module: PSym, rd: PRodReader): PPassContext = 1906 injectG() 1907 var m = newModule(g, module, graph.config) 1908 readMergeInfo(getCFile(m), m) 1909 result = m 1910 1911proc addHcrInitGuards(p: BProc, n: PNode, inInitGuard: var bool) = 1912 if n.kind == nkStmtList: 1913 for child in n: 1914 addHcrInitGuards(p, child, inInitGuard) 1915 else: 1916 let stmtShouldExecute = n.kind in {nkVarSection, nkLetSection} or 1917 nfExecuteOnReload in n.flags 1918 if inInitGuard: 1919 if stmtShouldExecute: 1920 endBlock(p) 1921 inInitGuard = false 1922 else: 1923 if not stmtShouldExecute: 1924 line(p, cpsStmts, "if (nim_hcr_do_init_)\n") 1925 startBlock(p) 1926 inInitGuard = true 1927 1928 genStmts(p, n) 1929 1930proc genTopLevelStmt*(m: BModule; n: PNode) = 1931 ## Also called from `ic/cbackend.nim`. 1932 if passes.skipCodegen(m.config, n): return 1933 m.initProc.options = initProcOptions(m) 1934 #softRnl = if optLineDir in m.config.options: noRnl else: rnl 1935 # XXX replicate this logic! 1936 var transformedN = transformStmt(m.g.graph, m.idgen, m.module, n) 1937 if sfInjectDestructors in m.module.flags: 1938 transformedN = injectDestructorCalls(m.g.graph, m.idgen, m.module, transformedN) 1939 1940 if m.hcrOn: 1941 addHcrInitGuards(m.initProc, transformedN, m.inHcrInitGuard) 1942 else: 1943 genProcBody(m.initProc, transformedN) 1944 1945proc myProcess(b: PPassContext, n: PNode): PNode = 1946 result = n 1947 if b != nil: 1948 var m = BModule(b) 1949 genTopLevelStmt(m, n) 1950 1951proc shouldRecompile(m: BModule; code: Rope, cfile: Cfile): bool = 1952 if optForceFullMake notin m.config.globalOptions: 1953 if not moduleHasChanged(m.g.graph, m.module): 1954 result = false 1955 elif not equalsFile(code, cfile.cname): 1956 when false: 1957 #m.config.symbolFiles == readOnlySf: #isDefined(m.config, "nimdiff"): 1958 if fileExists(cfile.cname): 1959 copyFile(cfile.cname.string, cfile.cname.string & ".backup") 1960 echo "diff ", cfile.cname.string, ".backup ", cfile.cname.string 1961 else: 1962 echo "new file ", cfile.cname.string 1963 if not writeRope(code, cfile.cname): 1964 rawMessage(m.config, errCannotOpenFile, cfile.cname.string) 1965 result = true 1966 elif fileExists(cfile.obj) and os.fileNewer(cfile.obj.string, cfile.cname.string): 1967 result = false 1968 else: 1969 result = true 1970 else: 1971 if not writeRope(code, cfile.cname): 1972 rawMessage(m.config, errCannotOpenFile, cfile.cname.string) 1973 result = true 1974 1975# We need 2 different logics here: pending modules (including 1976# 'nim__dat') may require file merging for the combination of dead code 1977# elimination and incremental compilation! Non pending modules need no 1978# such logic and in fact the logic hurts for the main module at least; 1979# it would generate multiple 'main' procs, for instance. 1980 1981proc writeModule(m: BModule, pending: bool) = 1982 template onExit() = close(m.ndi, m.config) 1983 let cfile = getCFile(m) 1984 if moduleHasChanged(m.g.graph, m.module): 1985 genInitCode(m) 1986 finishTypeDescriptions(m) 1987 if sfMainModule in m.module.flags: 1988 # generate main file: 1989 genMainProc(m) 1990 m.s[cfsProcHeaders].add(m.g.mainModProcs) 1991 generateThreadVarsSize(m) 1992 1993 var cf = Cfile(nimname: m.module.name.s, cname: cfile, 1994 obj: completeCfilePath(m.config, toObjFile(m.config, cfile)), flags: {}) 1995 var code = genModule(m, cf) 1996 if code != nil or m.config.symbolFiles != disabledSf: 1997 when hasTinyCBackend: 1998 if m.config.cmd == cmdTcc: 1999 tccgen.compileCCode($code, m.config) 2000 onExit() 2001 return 2002 2003 if not shouldRecompile(m, code, cf): cf.flags = {CfileFlag.Cached} 2004 addFileToCompile(m.config, cf) 2005 onExit() 2006 2007proc updateCachedModule(m: BModule) = 2008 let cfile = getCFile(m) 2009 var cf = Cfile(nimname: m.module.name.s, cname: cfile, 2010 obj: completeCfilePath(m.config, toObjFile(m.config, cfile)), flags: {}) 2011 if sfMainModule notin m.module.flags: 2012 genMainProc(m) 2013 cf.flags = {CfileFlag.Cached} 2014 addFileToCompile(m.config, cf) 2015 2016proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode) = 2017 ## Also called from IC. 2018 if sfMainModule in m.module.flags: 2019 # phase ordering problem here: We need to announce this 2020 # dependency to 'nimTestErrorFlag' before system.c has been written to disk. 2021 if m.config.exc == excGoto and getCompilerProc(graph, "nimTestErrorFlag") != nil: 2022 discard cgsym(m, "nimTestErrorFlag") 2023 2024 if {optGenStaticLib, optGenDynLib, optNoMain} * m.config.globalOptions == {}: 2025 for i in countdown(high(graph.globalDestructors), 0): 2026 n.add graph.globalDestructors[i] 2027 if passes.skipCodegen(m.config, n): return 2028 if moduleHasChanged(graph, m.module): 2029 # if the module is cached, we don't regenerate the main proc 2030 # nor the dispatchers? But if the dispatchers changed? 2031 # XXX emit the dispatchers into its own .c file? 2032 if n != nil: 2033 m.initProc.options = initProcOptions(m) 2034 genProcBody(m.initProc, n) 2035 2036 if m.hcrOn: 2037 # make sure this is pulled in (meaning hcrGetGlobal() is called for it during init) 2038 discard cgsym(m, "programResult") 2039 if m.inHcrInitGuard: 2040 endBlock(m.initProc) 2041 2042 if sfMainModule in m.module.flags: 2043 if m.hcrOn: 2044 # pull ("define" since they are inline when HCR is on) these functions in the main file 2045 # so it can load the HCR runtime and later pass the library handle to the HCR runtime which 2046 # will in turn pass it to the other modules it initializes so they can initialize the 2047 # register/get procs so they don't have to have the definitions of these functions as well 2048 discard cgsym(m, "nimLoadLibrary") 2049 discard cgsym(m, "nimLoadLibraryError") 2050 discard cgsym(m, "nimGetProcAddr") 2051 discard cgsym(m, "procAddrError") 2052 discard cgsym(m, "rawWrite") 2053 2054 # raise dependencies on behalf of genMainProc 2055 if m.config.target.targetOS != osStandalone and m.config.selectedGC != gcNone: 2056 discard cgsym(m, "initStackBottomWith") 2057 if emulatedThreadVars(m.config) and m.config.target.targetOS != osStandalone: 2058 discard cgsym(m, "initThreadVarsEmulation") 2059 2060 if m.g.forwardedProcs.len == 0: 2061 incl m.flags, objHasKidsValid 2062 let disp = generateMethodDispatchers(graph) 2063 for x in disp: genProcAux(m, x.sym) 2064 2065 let mm = m 2066 m.g.modulesClosed.add mm 2067 2068 2069proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode = 2070 result = n 2071 if b == nil: return 2072 finalCodegenActions(graph, BModule(b), n) 2073 2074proc genForwardedProcs(g: BModuleList) = 2075 # Forward declared proc:s lack bodies when first encountered, so they're given 2076 # a second pass here 2077 # Note: ``genProcNoForward`` may add to ``forwardedProcs`` 2078 while g.forwardedProcs.len > 0: 2079 let 2080 prc = g.forwardedProcs.pop() 2081 m = g.modules[prc.itemId.module] 2082 if sfForward in prc.flags: 2083 internalError(m.config, prc.info, "still forwarded: " & prc.name.s) 2084 2085 genProcNoForward(m, prc) 2086 2087proc cgenWriteModules*(backend: RootRef, config: ConfigRef) = 2088 let g = BModuleList(backend) 2089 g.config = config 2090 2091 # we need to process the transitive closure because recursive module 2092 # deps are allowed (and the system module is processed in the wrong 2093 # order anyway) 2094 genForwardedProcs(g) 2095 2096 for m in cgenModules(g): 2097 m.writeModule(pending=true) 2098 writeMapping(config, g.mapping) 2099 if g.generatedHeader != nil: writeHeader(g.generatedHeader) 2100 2101const cgenPass* = makePass(myOpen, myProcess, myClose) 2102