diff --git a/compiler/cbuilderbase.nim b/compiler/cbuilderbase.nim index 8cd302a793a8..163b08b1bac5 100644 --- a/compiler/cbuilderbase.nim +++ b/compiler/cbuilderbase.nim @@ -42,6 +42,12 @@ proc addLineEndDedent*(builder: var Builder, s: string) = builder.addDedent(s) builder.addNewline() +proc addLineComment*(builder: var Builder, comment: string) = + # probably no-op on nifc + builder.add("// ") + builder.add(comment) + builder.addNewline() + proc addIntValue*(builder: var Builder, val: int) = builder.buf.addInt(val) diff --git a/compiler/cbuilderdecls.nim b/compiler/cbuilderdecls.nim index 28d28579a4ca..0a605f31e4e7 100644 --- a/compiler/cbuilderdecls.nim +++ b/compiler/cbuilderdecls.nim @@ -468,6 +468,19 @@ proc addUnnamedParam(builder: var Builder, params: var ProcParamBuilder, typ: Sn params.needsComma = true builder.add(typ) +proc addProcTypedParam(builder: var Builder, paramBuilder: var ProcParamBuilder, callConv: TCallingConvention, name: string, rettype, params: Snippet) = + if paramBuilder.needsComma: + builder.add(", ") + else: + paramBuilder.needsComma = true + builder.add(CallingConvToStr[callConv]) + builder.add("_PTR(") + builder.add(rettype) + builder.add(", ") + builder.add(name) + builder.add(")") + builder.add(params) + proc addVarargsParam(builder: var Builder, params: var ProcParamBuilder) = # does not exist in NIFC, needs to be proc pragma if params.needsComma: @@ -481,6 +494,20 @@ template addProcParams(builder: var Builder, params: out ProcParamBuilder, body: body finishProcParamBuilder(builder, params) +type SimpleProcParam = tuple + name, typ: string + +proc cProcParams(params: varargs[SimpleProcParam]): Snippet = + if params.len == 0: return "(void)" + result = "(" + for i in 0 ..< params.len: + if i != 0: result.add(", ") + result.add(params[i].typ) + if params[i].name.len != 0: + result.add(" ") + result.add(params[i].name) + result.add(")") + template addProcHeaderWithParams(builder: var Builder, callConv: TCallingConvention, name: string, rettype: Snippet, paramBuilder: typed) = # on nifc should build something like (proc name params type pragmas @@ -502,6 +529,15 @@ proc addProcHeader(builder: var Builder, callConv: TCallingConvention, addProcHeaderWithParams(builder, callConv, name, rettype): builder.add(params) +proc addProcHeader(builder: var Builder, name: string, rettype, params: Snippet, isConstructor = false) = + # no callconv + builder.add(rettype) + builder.add(" ") + if isConstructor: + builder.add("__attribute__((constructor)) ") + builder.add(name) + builder.add(params) + proc addProcHeader(builder: var Builder, m: BModule, prc: PSym, name: string, params, rettype: Snippet, addAttributes: bool) = # on nifc should build something like (proc name params type pragmas # with no body given @@ -560,7 +596,8 @@ proc addProcVar(builder: var Builder, m: BModule, prc: PSym, name: string, param builder.addLineEnd(";") proc addProcVar(builder: var Builder, callConv: TCallingConvention, - name: string, params, rettype: Snippet, isStatic = false) = + name: string, params, rettype: Snippet, + isStatic = false, isVolatile = false) = # on nifc, builds full variable if isStatic: builder.add("static ") @@ -568,6 +605,24 @@ proc addProcVar(builder: var Builder, callConv: TCallingConvention, builder.add("_PTR(") builder.add(rettype) builder.add(", ") + if isVolatile: + builder.add("volatile ") + builder.add(name) + builder.add(")") + builder.add(params) + # ensure we are just adding a variable: + builder.addLineEnd(";") + +proc addProcVar(builder: var Builder, + name: string, params, rettype: Snippet, + isStatic = false, isVolatile = false) = + # no callconv + if isStatic: + builder.add("static ") + builder.add(rettype) + builder.add(" (*") + if isVolatile: + builder.add("volatile ") builder.add(name) builder.add(")") builder.add(params) diff --git a/compiler/cbuilderexprs.nim b/compiler/cbuilderexprs.nim index 5609df0c61fc..8a85310cb90f 100644 --- a/compiler/cbuilderexprs.nim +++ b/compiler/cbuilderexprs.nim @@ -14,6 +14,9 @@ proc ptrConstType(t: Snippet): Snippet = proc ptrType(t: Snippet): Snippet = t & "*" +proc cppRefType(t: Snippet): Snippet = + t & "&" + const CallingConvToStr: array[TCallingConvention, string] = ["N_NIMCALL", "N_STDCALL", "N_CDECL", "N_SAFECALL", @@ -32,6 +35,20 @@ proc procPtrTypeUnnamedNimCall(rettype, params: Snippet): Snippet = proc procPtrTypeUnnamed(callConv: TCallingConvention, rettype, params: Snippet): Snippet = CallingConvToStr[callConv] & "_PTR(" & rettype & ", )" & params +type CppCaptureKind = enum None, ByReference, ByCopy + +template addCppLambda(builder: var Builder, captures: CppCaptureKind, params: Snippet, body: typed) = + builder.add("[") + case captures + of None: discard + of ByReference: builder.add("&") + of ByCopy: builder.add("=") + builder.add("] ") + builder.add(params) + builder.addLineEndIndent(" {") + body + builder.addLineEndDedent("}") + proc cCast(typ, value: Snippet): Snippet = "((" & typ & ") " & value & ")" diff --git a/compiler/ccgthreadvars.nim b/compiler/ccgthreadvars.nim index 65f5275baa8b..0bc4414d2297 100644 --- a/compiler/ccgthreadvars.nim +++ b/compiler/ccgthreadvars.nim @@ -59,9 +59,6 @@ proc generateThreadVarsSize(m: BModule) = sfCompileToCpp in m.module.flags: ExternC else: None m.s[cfsProcs].addDeclWithVisibility(externc): - m.s[cfsProcs].addProcHeaderWithParams(ccNoConvention, "NimThreadVarsSize", "NI"): - var params: ProcParamBuilder - m.s[cfsProcs].addProcParams(params): - discard + m.s[cfsProcs].addProcHeader("NimThreadVarsSize", "NI", cProcParams()) m.s[cfsProcs].finishProcHeaderWithBody(): m.s[cfsProcs].addReturn(cCast("NI", cSizeof("NimThreadVars"))) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index e79f6b377433..4b7d2e14344a 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -820,6 +820,7 @@ proc initLocExprSingleUse(p: BProc, e: PNode): TLoc = include ccgcalls, "ccgstmts.nim" proc initFrame(p: BProc, procname, filename: Rope): Rope = + # XXX cbuilder const frameDefines = """ $1define nimfr_(proc, file) \ TFrame FR_; \ @@ -1636,16 +1637,174 @@ proc getInitName(m: BModule): Rope = proc getDatInitName(m: BModule): Rope = getSomeInitName(m, "DatInit000") proc getHcrInitName(m: BModule): Rope = getSomeInitName(m, "HcrInit000") -proc hcrGetProcLoadCode(m: BModule, sym, prefix, handle, getProcFunc: string): Rope +proc hcrGetProcLoadCode(builder: var Builder, m: BModule, sym, prefix, handle, getProcFunc: string) + +# The use of a volatile function pointer to call Pre/NimMainInner +# prevents inlining of the NimMainInner function and dependent +# functions, which might otherwise merge their stack frames. +proc isInnerMainVolatile(m: BModule): bool = + m.config.selectedGC notin {gcNone, gcArc, gcAtomicArc, gcOrc} + +proc genPreMain(m: BModule) = + m.s[cfsProcs].addDeclWithVisibility(Private): + m.s[cfsProcs].addProcHeader(m.config.nimMainPrefix & "PreMainInner", "void", cProcParams()) + m.s[cfsProcs].finishProcHeaderWithBody(): + m.s[cfsProcs].add(extract(m.g.otherModsInit)) + if optNoMain notin m.config.globalOptions: + m.s[cfsProcs].addDeclWithVisibility(Private): + m.s[cfsProcs].addVar(name = "cmdCount", typ = "int") + m.s[cfsProcs].addDeclWithVisibility(Private): + m.s[cfsProcs].addVar(name = "cmdLine", typ = ptrType(ptrType("char"))) + m.s[cfsProcs].addDeclWithVisibility(Private): + m.s[cfsProcs].addVar(name = "gEnv", typ = ptrType(ptrType("char"))) + m.s[cfsProcs].addDeclWithVisibility(Private): + m.s[cfsProcs].addProcHeader(m.config.nimMainPrefix & "PreMain", "void", cProcParams()) + m.s[cfsProcs].finishProcHeaderWithBody(): + if isInnerMainVolatile(m): + m.s[cfsProcs].addProcVar(name = "inner", rettype = "void", params = cProcParams(), isVolatile = true) + m.s[cfsProcs].addAssignment("inner", m.config.nimMainPrefix & "PreMainInner") + m.s[cfsProcs].add(extract(m.g.mainDatInit)) + m.s[cfsProcs].addCallStmt(cDeref("inner")) + else: + # not volatile + m.s[cfsProcs].add(extract(m.g.mainDatInit)) + m.s[cfsProcs].addCallStmt(m.config.nimMainPrefix & "PreMainInner") + +proc genMainProcs(m: BModule) = + m.s[cfsProcs].addCallStmt(m.config.nimMainPrefix & "NimMain") + +proc genMainProcsWithResult(m: BModule) = + genMainProcs(m) + var res = "nim_program_result" + if m.hcrOn: res = cDeref(res) + m.s[cfsProcs].addReturn(res) + +proc genNimMainInner(m: BModule) = + m.s[cfsProcs].addDeclWithVisibility(Private): + m.s[cfsProcs].addProcHeader(ccCDecl, m.config.nimMainPrefix & "NimMainInner", "void", cProcParams()) + m.s[cfsProcs].finishProcHeaderWithBody(): + m.s[cfsProcs].add(extract(m.g.mainModInit)) + m.s[cfsProcs].addNewline() + +proc initStackBottom(m: BModule): bool = + not (m.config.target.targetOS == osStandalone or m.config.selectedGC in {gcNone, gcArc, gcAtomicArc, gcOrc}) + +proc genNimMainProc(m: BModule, preMainCode: Snippet) = + m.s[cfsProcs].addProcHeader(ccCDecl, m.config.nimMainPrefix & "NimMain", "void", cProcParams()) + m.s[cfsProcs].finishProcHeaderWithBody(): + if isInnerMainVolatile(m): + m.s[cfsProcs].addProcVar(name = "inner", rettype = "void", params = cProcParams(), isVolatile = true) + m.s[cfsProcs].add(preMainCode) + m.s[cfsProcs].addAssignment("inner", m.config.nimMainPrefix & "NimMainInner") + if initStackBottom(m): + m.s[cfsProcs].addCallStmt("initStackBottomWith", cCast("void*", cAddr("inner"))) + m.s[cfsProcs].addCallStmt(cDeref("inner")) + else: + # not volatile + m.s[cfsProcs].add(preMainCode) + if initStackBottom(m): + m.s[cfsProcs].addCallStmt("initStackBottomWith", cCast("void*", cAddr("inner"))) + m.s[cfsProcs].addCallStmt(m.config.nimMainPrefix & "NimMainInner") + m.s[cfsProcs].addNewline() + +proc genNimMainBody(m: BModule, preMainCode: Snippet) = + genNimMainInner(m) + genNimMainProc(m, preMainCode) + +proc genPosixCMain(m: BModule) = + m.s[cfsProcs].addProcHeader("main", "int", cProcParams( + (name: "argc", typ: "int"), + (name: "args", typ: ptrType(ptrType("char"))), + (name: "env", typ: ptrType(ptrType("char"))))) + m.s[cfsProcs].finishProcHeaderWithBody(): + m.s[cfsProcs].addAssignment("cmdLine", "args") + m.s[cfsProcs].addAssignment("cmdCount", "argc") + m.s[cfsProcs].addAssignment("gEnv", "env") + genMainProcsWithResult(m) + m.s[cfsProcs].addNewline() + +proc genStandaloneCMain(m: BModule) = + m.s[cfsProcs].addProcHeader("main", "int", cProcParams()) + m.s[cfsProcs].finishProcHeaderWithBody(): + genMainProcs(m) + m.s[cfsProcs].addReturn(cIntValue(0)) + m.s[cfsProcs].addNewline() + +proc genWinNimMain(m: BModule, preMainCode: Snippet) = + genNimMainBody(m, preMainCode) + +proc genWinCMain(m: BModule) = + m.s[cfsProcs].addProcHeader(ccStdCall, "WinMain", "int", cProcParams( + (name: "hCurInstance", typ: "HINSTANCE"), + (name: "hPrevInstance", typ: "HINSTANCE"), + (name: "lpCmdLine", typ: "LPSTR"), + (name: "nCmdShow", typ: "int"))) + m.s[cfsProcs].finishProcHeaderWithBody(): + genMainProcsWithResult(m) + m.s[cfsProcs].addNewline() + +proc genWinNimDllMain(m: BModule, preMainCode: Snippet) = + genNimMainInner(m) + m.s[cfsProcs].addDeclWithVisibility(ExportLib): + genNimMainProc(m, preMainCode) + +proc genWinCDllMain(m: BModule) = + # used to use WINAPI macro, now ccStdCall: + m.s[cfsProcs].addProcHeader(ccStdCall, "DllMain", "BOOL", cProcParams( + (name: "hinstDLL", typ: "HINSTANCE"), + (name: "fwdreason", typ: "DWORD"), + (name: "lpvReserved", typ: "LPVOID"))) + m.s[cfsProcs].finishProcHeaderWithBody(): + m.s[cfsProcs].addSingleIfStmt(removeSinglePar(cOp(Equal, "fwdreason", "DLL_PROCESS_ATTACH"))): + genMainProcs(m) + m.s[cfsProcs].addReturn(cIntValue(1)) + m.s[cfsProcs].addNewline() + +proc genPosixNimDllMain(m: BModule, preMainCode: Snippet) = + genWinNimDllMain(m, preMainCode) + +proc genPosixCDllMain(m: BModule) = + # used to use NIM_POSIX_INIT, now uses direct constructor attribute + m.s[cfsProcs].addProcHeader("NimMainInit", "void", cProcParams(), isConstructor = true) + m.s[cfsProcs].finishProcHeaderWithBody(): + genMainProcs(m) + m.s[cfsProcs].addNewline() + +proc genGenodeNimMain(m: BModule, preMainCode: Snippet) = + let typName = "Genode::Env" + m.s[cfsProcs].addDeclWithVisibility(Extern): + m.s[cfsProcs].addVar(name = "nim_runtime_env", typ = ptrType(typName)) + m.s[cfsProcs].addDeclWithVisibility(ExternC): + m.s[cfsProcs].addProcHeader("nim_component_construct", "void", cProcParams((name: "", typ: ptrType(typName)))) + m.s[cfsProcs].finishProcHeaderAsProto() + genNimMainBody(m, preMainCode) + +proc genComponentConstruct(m: BModule) = + let fnName = "Libc::Component::construct" + let typName = "Libc::Env" + m.s[cfsProcs].addProcHeader(fnName, "void", cProcParams((name: "env", typ: cppRefType(typName)))) + m.s[cfsProcs].finishProcHeaderWithBody(): + m.s[cfsProcs].addLineComment("Set Env used during runtime initialization") + m.s[cfsProcs].addAssignment("nim_runtime_env", cAddr("env")) + let callFn = "Libc::with_libc" + var call: CallBuilder + m.s[cfsProcs].addStmt(): + m.s[cfsProcs].addCall(call, callFn): + m.s[cfsProcs].addArgument(call): + m.s[cfsProcs].addCppLambda(ByReference, cProcParams()): + m.s[cfsProcs].addLineComment("Initialize runtime and globals") + genMainProcs(m) + m.s[cfsProcs].addLineComment("Call application construct") + m.s[cfsProcs].addCallStmt("nim_component_construct", cAddr("env")) + m.s[cfsProcs].addNewline() proc genMainProc(m: BModule) = ## this function is called in cgenWriteModules after all modules are closed, ## it means raising dependency on the symbols is too late as it will not propagate ## into other modules, only simple rope manipulations are allowed - var preMainCode: Rope = "" + var preMainBuilder = newBuilder("") if m.hcrOn: - proc loadLib(handle: string, name: string): Rope = - result = "" + proc loadLib(builder: var Builder, handle: string, name: string) = let prc = magicsys.getCompilerProc(m.g.graph, name) assert prc != nil let n = newStrNode(nkStrLit, prc.annex.path.strVal) @@ -1653,130 +1812,23 @@ proc genMainProc(m: BModule) = var strLitBuilder = newBuilder("") genStringLiteral(m, n, strLitBuilder) let strLit = extract(strLitBuilder) - appcg(m, result, "\tif (!($1 = #nimLoadLibrary($2)))$N" & - "\t\t#nimLoadLibraryError($2);$N", - [handle, strLit]) + builder.addAssignment(handle, cCall(cgsymValue(m, "nimLoadLibrary"), strLit)) + builder.addSingleIfStmt(cOp(Not, handle)): + builder.addCallStmt(cgsymValue(m, "nimLoadLibraryError"), strLit) - preMainCode.add(loadLib("hcr_handle", "hcrGetProc")) + loadLib(preMainBuilder, "hcr_handle", "hcrGetProc") if m.config.selectedGC in {gcArc, gcAtomicArc, gcOrc}: - preMainCode.add("\t$1PreMain();\L" % [rope m.config.nimMainPrefix]) + preMainBuilder.addCallStmt(m.config.nimMainPrefix & "PreMain") else: - preMainCode.add("\tvoid* rtl_handle;\L") - preMainCode.add(loadLib("rtl_handle", "nimGC_setStackBottom")) - preMainCode.add(hcrGetProcLoadCode(m, "nimGC_setStackBottom", "nimrtl_", "rtl_handle", "nimGetProcAddr")) - preMainCode.add("\tinner = $1PreMain;\L" % [rope m.config.nimMainPrefix]) - preMainCode.add("\tinitStackBottomWith_actual((void *)&inner);\L") - preMainCode.add("\t(*inner)();\L") + preMainBuilder.addVar(name = "rtl_handle", typ = "void*") + loadLib(preMainBuilder, "rtl_handle", "nimGC_setStackBottom") + hcrGetProcLoadCode(preMainBuilder, m, "nimGC_setStackBottom", "nimrtl_", "rtl_handle", "nimGetProcAddr") + preMainBuilder.addAssignment("inner", m.config.nimMainPrefix & "PreMain") + preMainBuilder.addCallStmt("initStackBottomWith_actual", cCast("void*", cAddr("inner"))) + preMainBuilder.addCallStmt(cDeref("inner")) else: - preMainCode.add("\t$1PreMain();\L" % [rope m.config.nimMainPrefix]) - - var posixCmdLine: Rope = "" - if optNoMain notin m.config.globalOptions: - posixCmdLine.add "N_LIB_PRIVATE int cmdCount;\L" - posixCmdLine.add "N_LIB_PRIVATE char** cmdLine;\L" - posixCmdLine.add "N_LIB_PRIVATE char** gEnv;\L" - - const - # The use of a volatile function pointer to call Pre/NimMainInner - # prevents inlining of the NimMainInner function and dependent - # functions, which might otherwise merge their stack frames. - - PreMainBody = "$N" & - "N_LIB_PRIVATE void $3PreMainInner(void) {$N" & - "$2" & - "}$N$N" & - "$4" & - "N_LIB_PRIVATE void $3PreMain(void) {$N" & - "##if $5$N" & # 1 for volatile call, 0 for non-volatile - "\tvoid (*volatile inner)(void);$N" & - "\tinner = $3PreMainInner;$N" & - "$1" & - "\t(*inner)();$N" & - "##else$N" & - "$1" & - "\t$3PreMainInner();$N" & - "##endif$N" & - "}$N$N" - - MainProcs = - "\t$^NimMain();$N" - - MainProcsWithResult = - MainProcs & ("\treturn $1nim_program_result;$N") - - NimMainInner = "N_LIB_PRIVATE N_CDECL(void, $5NimMainInner)(void) {$N" & - "$1" & - "}$N$N" - - NimMainProc = - "N_CDECL(void, $5NimMain)(void) {$N" & - "##if $6$N" & # 1 for volatile call, 0 for non-volatile - "\tvoid (*volatile inner)(void);$N" & - "$4" & - "\tinner = $5NimMainInner;$N" & - "$2" & - "\t(*inner)();$N" & - "##else$N" & - "$4" & - "$2" & - "\t$5NimMainInner();$N" & - "##endif$N" & - "}$N$N" - - NimMainBody = NimMainInner & NimMainProc - - PosixCMain = - "int main(int argc, char** args, char** env) {$N" & - "\tcmdLine = args;$N" & - "\tcmdCount = argc;$N" & - "\tgEnv = env;$N" & - MainProcsWithResult & - "}$N$N" - - StandaloneCMain = - "int main(void) {$N" & - MainProcs & - "\treturn 0;$N" & - "}$N$N" - - WinNimMain = NimMainBody - - WinCMain = "N_STDCALL(int, WinMain)(HINSTANCE hCurInstance, $N" & - " HINSTANCE hPrevInstance, $N" & - " LPSTR lpCmdLine, int nCmdShow) {$N" & - MainProcsWithResult & "}$N$N" - - WinNimDllMain = NimMainInner & "N_LIB_EXPORT " & NimMainProc - - WinCDllMain = - "BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fwdreason, $N" & - " LPVOID lpvReserved) {$N" & - "\tif (fwdreason == DLL_PROCESS_ATTACH) {$N" & MainProcs & "\t}$N" & - "\treturn 1;$N}$N$N" - - PosixNimDllMain = WinNimDllMain - - PosixCDllMain = - "N_LIB_PRIVATE void NIM_POSIX_INIT NimMainInit(void) {$N" & - MainProcs & - "}$N$N" - - GenodeNimMain = - "extern Genode::Env *nim_runtime_env;$N" & - "extern \"C\" void nim_component_construct(Genode::Env*);$N$N" & - NimMainBody - - ComponentConstruct = - "void Libc::Component::construct(Libc::Env &env) {$N" & - "\t// Set Env used during runtime initialization$N" & - "\tnim_runtime_env = &env;$N" & - "\tLibc::with_libc([&] () {$N\t" & - "\t// Initialize runtime and globals$N" & - MainProcs & - "\t// Call application construct$N" & - "\t\tnim_component_construct(&env);$N" & - "\t});$N" & - "}$N$N" + preMainBuilder.addCallStmt(m.config.nimMainPrefix & "PreMain") + let preMainCode = extract(preMainBuilder) if m.config.target.targetOS == osWindows and m.config.globalOptions * {optGenGuiApp, optGenDynLib} != {}: @@ -1784,36 +1836,24 @@ proc genMainProc(m: BModule) = elif m.config.target.targetOS == osGenode: m.includeHeader("") - let initStackBottomCall = - if m.config.target.targetOS == osStandalone or m.config.selectedGC in {gcNone, gcArc, gcAtomicArc, gcOrc}: "".rope - else: ropecg(m, "\t#initStackBottomWith((void *)&inner);$N", []) + if initStackBottom(m): + cgsym(m, "initStackBottomWith") inc(m.labels) - let isVolatile = if m.config.selectedGC notin {gcNone, gcArc, gcAtomicArc, gcOrc}: "1" else: "0" - appcg(m, m.s[cfsProcs], PreMainBody, [m.g.mainDatInit, m.g.otherModsInit, m.config.nimMainPrefix, posixCmdLine, isVolatile]) + genPreMain(m) if m.config.target.targetOS == osWindows and m.config.globalOptions * {optGenGuiApp, optGenDynLib} != {}: if optGenGuiApp in m.config.globalOptions: - const nimMain = WinNimMain - appcg(m, m.s[cfsProcs], nimMain, - [m.g.mainModInit, initStackBottomCall, m.labels, preMainCode, m.config.nimMainPrefix, isVolatile]) + genWinNimMain(m, preMainCode) else: - const nimMain = WinNimDllMain - appcg(m, m.s[cfsProcs], nimMain, - [m.g.mainModInit, initStackBottomCall, m.labels, preMainCode, m.config.nimMainPrefix, isVolatile]) + genWinNimDllMain(m, preMainCode) elif m.config.target.targetOS == osGenode: - const nimMain = GenodeNimMain - appcg(m, m.s[cfsProcs], nimMain, - [m.g.mainModInit, initStackBottomCall, m.labels, preMainCode, m.config.nimMainPrefix, isVolatile]) + genGenodeNimMain(m, preMainCode) elif optGenDynLib in m.config.globalOptions: - const nimMain = PosixNimDllMain - appcg(m, m.s[cfsProcs], nimMain, - [m.g.mainModInit, initStackBottomCall, m.labels, preMainCode, m.config.nimMainPrefix, isVolatile]) + genPosixNimDllMain(m, preMainCode) else: - const nimMain = NimMainBody - appcg(m, m.s[cfsProcs], nimMain, - [m.g.mainModInit, initStackBottomCall, m.labels, preMainCode, m.config.nimMainPrefix, isVolatile]) + genNimMainBody(m, preMainCode) if optNoMain notin m.config.globalOptions: if m.config.cppCustomNamespace.len > 0: @@ -1823,23 +1863,17 @@ proc genMainProc(m: BModule) = if m.config.target.targetOS == osWindows and m.config.globalOptions * {optGenGuiApp, optGenDynLib} != {}: if optGenGuiApp in m.config.globalOptions: - const otherMain = WinCMain - appcg(m, m.s[cfsProcs], otherMain, [if m.hcrOn: "*" else: "", m.config.nimMainPrefix]) + genWinCMain(m) else: - const otherMain = WinCDllMain - appcg(m, m.s[cfsProcs], otherMain, [m.config.nimMainPrefix]) + genWinCDllMain(m) elif m.config.target.targetOS == osGenode: - const otherMain = ComponentConstruct - appcg(m, m.s[cfsProcs], otherMain, [m.config.nimMainPrefix]) + genComponentConstruct(m) elif optGenDynLib in m.config.globalOptions: - const otherMain = PosixCDllMain - appcg(m, m.s[cfsProcs], otherMain, [m.config.nimMainPrefix]) + genPosixCDllMain(m) elif m.config.target.targetOS == osStandalone: - const otherMain = StandaloneCMain - appcg(m, m.s[cfsProcs], otherMain, [m.config.nimMainPrefix]) + genStandaloneCMain(m) else: - const otherMain = PosixCMain - appcg(m, m.s[cfsProcs], otherMain, [if m.hcrOn: "*" else: "", m.config.nimMainPrefix]) + genPosixCMain(m) if m.config.cppCustomNamespace.len > 0: openNamespaceNim(m.config.cppCustomNamespace, m.s[cfsProcs]) @@ -1848,18 +1882,21 @@ proc registerInitProcs*(g: BModuleList; m: PSym; flags: set[ModuleBackendFlag]) ## Called from the IC backend. if HasDatInitProc in flags: let datInit = getSomeNameForModule(g.config, g.config.toFullPath(m.info.fileIndex).AbsoluteFile) & "DatInit000" - g.mainModProcs.addf("N_LIB_PRIVATE N_NIMCALL(void, $1)(void);$N", [datInit]) - g.mainDatInit.addf("\t$1();$N", [datInit]) + g.mainModProcs.addDeclWithVisibility(Private): + g.mainModProcs.addProcHeader(ccNimCall, datInit, "void", cProcParams()) + g.mainModProcs.finishProcHeaderAsProto() + g.mainDatInit.addCallStmt(datInit) if HasModuleInitProc in flags: let init = getSomeNameForModule(g.config, g.config.toFullPath(m.info.fileIndex).AbsoluteFile) & "Init000" - g.mainModProcs.addf("N_LIB_PRIVATE N_NIMCALL(void, $1)(void);$N", [init]) - let initCall = "\t$1();$N" % [init] + g.mainModProcs.addDeclWithVisibility(Private): + g.mainModProcs.addProcHeader(ccNimCall, init, "void", cProcParams()) + g.mainModProcs.finishProcHeaderAsProto() if sfMainModule in m.flags: - g.mainModInit.add(initCall) + g.mainModInit.addCallStmt(init) elif sfSystemModule in m.flags: - g.mainDatInit.add(initCall) # systemInit must called right after systemDatInit if any + g.mainDatInit.addCallStmt(init) # systemInit must called right after systemDatInit if any else: - g.otherModsInit.add(initCall) + g.otherModsInit.addCallStmt(init) proc whichInitProcs*(m: BModule): set[ModuleBackendFlag] = # called from IC. @@ -1877,31 +1914,68 @@ proc registerModuleToMain(g: BModuleList; m: BModule) = datInit = m.getDatInitName if m.hcrOn: - var hcrModuleMeta = "$nN_LIB_PRIVATE const char* hcr_module_list[] = {$n" % [] + var hcrModuleMeta = newBuilder("") let systemModulePath = getModuleDllPath(m, g.modules[g.graph.config.m.systemFileIdx.int].module) let mainModulePath = getModuleDllPath(m, m.module) + hcrModuleMeta.addDeclWithVisibility(Private): + hcrModuleMeta.addArrayVarWithInitializer(kind = Local, + name = "hcr_module_list", + elementType = ptrConstType("char"), + len = g.graph.importDeps.getOrDefault(FileIndex(m.module.position)).len + + ord(sfMainModule in m.module.flags) + + 1): + var modules: StructInitializer + hcrModuleMeta.addStructInitializer(modules, siArray): + if sfMainModule in m.module.flags: + hcrModuleMeta.addField(modules, ""): + hcrModuleMeta.add(systemModulePath) + g.graph.importDeps.withValue(FileIndex(m.module.position), deps): + for curr in deps[]: + hcrModuleMeta.addField(modules, ""): + hcrModuleMeta.add(getModuleDllPath(m, g.modules[curr.int].module)) + hcrModuleMeta.addField(modules, ""): + hcrModuleMeta.add("\"\"") + hcrModuleMeta.addDeclWithVisibility(ExportLib): + hcrModuleMeta.addProcHeader(ccNimCall, "HcrGetImportedModules", "void**", cProcParams()) + hcrModuleMeta.finishProcHeaderWithBody(): + hcrModuleMeta.addReturn(cCast("void**", "hcr_module_list")) + hcrModuleMeta.addDeclWithVisibility(ExportLib): + hcrModuleMeta.addProcHeader(ccNimCall, "HcrGetSigHash", ptrType("char"), cProcParams()) + hcrModuleMeta.finishProcHeaderWithBody(): + hcrModuleMeta.addReturn('"' & $sigHash(m.module, m.config) & '"') if sfMainModule in m.module.flags: - hcrModuleMeta.addf("\t$1,$n", [systemModulePath]) - g.graph.importDeps.withValue(FileIndex(m.module.position), deps): - for curr in deps[]: - hcrModuleMeta.addf("\t$1,$n", [getModuleDllPath(m, g.modules[curr.int].module)]) - hcrModuleMeta.addf("\t\"\"};$n", []) - hcrModuleMeta.addf("$nN_LIB_EXPORT N_NIMCALL(void**, HcrGetImportedModules)() { return (void**)hcr_module_list; }$n", []) - hcrModuleMeta.addf("$nN_LIB_EXPORT N_NIMCALL(char*, HcrGetSigHash)() { return \"$1\"; }$n$n", - [($sigHash(m.module, m.config)).rope]) - if sfMainModule in m.module.flags: - g.mainModProcs.add(hcrModuleMeta) - g.mainModProcs.addf("static void* hcr_handle;$N", []) - g.mainModProcs.addf("N_LIB_EXPORT N_NIMCALL(void, $1)(void);$N", [init]) - g.mainModProcs.addf("N_LIB_EXPORT N_NIMCALL(void, $1)(void);$N", [datInit]) - g.mainModProcs.addf("N_LIB_EXPORT N_NIMCALL(void, $1)(void*, N_NIMCALL_PTR(void*, getProcAddr)(void*, char*));$N", [m.getHcrInitName]) - g.mainModProcs.addf("N_LIB_EXPORT N_NIMCALL(void, HcrCreateTypeInfos)(void);$N", []) - g.mainModInit.addf("\t$1();$N", [init]) - g.otherModsInit.addf("\thcrInit((void**)hcr_module_list, $1, $2, $3, hcr_handle, nimGetProcAddr);$n", - [mainModulePath, systemModulePath, datInit]) - g.mainDatInit.addf("\t$1(hcr_handle, nimGetProcAddr);$N", [m.getHcrInitName]) - g.mainDatInit.addf("\thcrAddModule($1);\n", [mainModulePath]) - g.mainDatInit.addf("\tHcrCreateTypeInfos();$N", []) + g.mainModProcs.add(extract(hcrModuleMeta)) + g.mainModProcs.addDeclWithVisibility(StaticProc): + g.mainModProcs.addVar(name = "hcr_handle", typ = "void*") + g.mainModProcs.addDeclWithVisibility(ExportLib): + g.mainModProcs.addProcHeader(ccNimCall, init, "void", cProcParams()) + g.mainModProcs.finishProcHeaderAsProto() + g.mainModProcs.addDeclWithVisibility(ExportLib): + g.mainModProcs.addProcHeader(ccNimCall, datInit, "void", cProcParams()) + g.mainModProcs.finishProcHeaderAsProto() + g.mainModProcs.addDeclWithVisibility(ExportLib): + g.mainModProcs.addProcHeaderWithParams(ccNimCall, m.getHcrInitName, "void"): + var hcrInitParams: ProcParamBuilder + g.mainModProcs.addProcParams(hcrInitParams): + g.mainModProcs.addUnnamedParam(hcrInitParams, "void*") + g.mainModProcs.addProcTypedParam(hcrInitParams, ccNimCall, "getProcAddr", "void*", cProcParams( + (name: "", typ: "void*"), + (name: "", typ: ptrType("char")))) + g.mainModProcs.finishProcHeaderAsProto() + g.mainModProcs.addDeclWithVisibility(ExportLib): + g.mainModProcs.addProcHeader(ccNimCall, "HcrCreateTypeInfos", "void", cProcParams()) + g.mainModProcs.finishProcHeaderAsProto() + g.mainModInit.addCallStmt(init) + g.otherModsInit.addCallStmt("hcrInit", + cCast("void**", "hcr_module_list"), + mainModulePath, + systemModulePath, + datInit, + "hcr_handle", + "nimGetProcAddr") + g.mainDatInit.addCallStmt(m.getHcrInitName, "hcr_handle", "nimGetProcAddr") + g.mainDatInit.addCallStmt("hcrAddModule", mainModulePath) + g.mainDatInit.addCallStmt("HcrCreateTypeInfos") # nasty nasty hack to get the command line functionality working with HCR # register the 2 variables on behalf of the os module which might not even # be loaded (in which case it will get collected but that is not a problem) @@ -1909,38 +1983,52 @@ proc registerModuleToMain(g: BModuleList; m: BModule) = # (`makeCString` was doing line wrap of string litterals) was root cause for # bug #16265. let osModulePath = ($systemModulePath).replace("stdlib_system", "stdlib_os").rope - g.mainDatInit.addf("\thcrAddModule($1);\n", [osModulePath]) - g.mainDatInit.add("\tint* cmd_count;\n") - g.mainDatInit.add("\tchar*** cmd_line;\n") - g.mainDatInit.addf("\thcrRegisterGlobal($1, \"cmdCount\", sizeof(cmd_count), NULL, (void**)&cmd_count);$N", [osModulePath]) - g.mainDatInit.addf("\thcrRegisterGlobal($1, \"cmdLine\", sizeof(cmd_line), NULL, (void**)&cmd_line);$N", [osModulePath]) - g.mainDatInit.add("\t*cmd_count = cmdCount;\n") - g.mainDatInit.add("\t*cmd_line = cmdLine;\n") + g.mainDatInit.addCallStmt("hcrAddModule", osModulePath) + g.mainDatInit.addVar(name = "cmd_count", typ = ptrType("int")) + g.mainDatInit.addVar(name = "cmd_line", typ = ptrType(ptrType(ptrType("char")))) + g.mainDatInit.addCallStmt("hcrRegisterGlobal", + osModulePath, + "\"cmdCount\"", + cSizeof("cmd_count"), + "NULL", + cCast("void**", cAddr("cmd_count"))) + g.mainDatInit.addCallStmt("hcrRegisterGlobal", + osModulePath, + "\"cmdLine\"", + cSizeof("cmd_line"), + "NULL", + cCast("void**", cAddr("cmd_line"))) + g.mainDatInit.addAssignment(cDeref("cmd_count"), "cmdCount") + g.mainDatInit.addAssignment(cDeref("cmd_line"), "cmdLine") else: - m.s[cfsInitProc].add(hcrModuleMeta) + m.s[cfsInitProc].add(extract(hcrModuleMeta)) return if m.s[cfsDatInitProc].buf.len > 0: - g.mainModProcs.addf("N_LIB_PRIVATE N_NIMCALL(void, $1)(void);$N", [datInit]) - g.mainDatInit.addf("\t$1();$N", [datInit]) + g.mainModProcs.addDeclWithVisibility(Private): + g.mainModProcs.addProcHeader(ccNimCall, datInit, "void", cProcParams()) + g.mainModProcs.finishProcHeaderAsProto() + g.mainDatInit.addCallStmt(datInit) # Initialization of TLS and GC should be done in between # systemDatInit and systemInit calls if any if sfSystemModule in m.module.flags: if emulatedThreadVars(m.config) and m.config.target.targetOS != osStandalone: - g.mainDatInit.add(ropecg(m, "\t#initThreadVarsEmulation();$N", [])) + g.mainDatInit.addCallStmt(cgsymValue(m, "initThreadVarsEmulation")) if m.config.target.targetOS != osStandalone and m.config.selectedGC notin {gcNone, gcArc, gcAtomicArc, gcOrc}: - g.mainDatInit.add(ropecg(m, "\t#initStackBottomWith((void *)&inner);$N", [])) + g.mainDatInit.addCallStmt(cgsymValue(m, "initStackBottomWith"), + cCast("void*", cAddr("inner"))) if m.s[cfsInitProc].buf.len > 0: - g.mainModProcs.addf("N_LIB_PRIVATE N_NIMCALL(void, $1)(void);$N", [init]) - let initCall = "\t$1();$N" % [init] + g.mainModProcs.addDeclWithVisibility(Private): + g.mainModProcs.addProcHeader(ccNimCall, init, "void", cProcParams()) + g.mainModProcs.finishProcHeaderAsProto() if sfMainModule in m.module.flags: - g.mainModInit.add(initCall) + g.mainModInit.addCallStmt(init) elif sfSystemModule in m.module.flags: - g.mainDatInit.add(initCall) # systemInit must called right after systemDatInit if any + g.mainDatInit.addCallStmt(init) # systemInit must called right after systemDatInit if any else: - g.otherModsInit.add(initCall) + g.otherModsInit.addCallStmt(init) proc genDatInitCode(m: BModule) = ## this function is called in cgenWriteModules after all modules are closed, @@ -1949,19 +2037,21 @@ proc genDatInitCode(m: BModule) = var moduleDatInitRequired = m.hcrOn - var prc = newBuilder("$1 N_NIMCALL(void, $2)(void) {$N" % - [rope(if m.hcrOn: "N_LIB_EXPORT" else: "N_LIB_PRIVATE"), getDatInitName(m)]) - - # we don't want to break into such init code - could happen if a line - # directive from a function written by the user spills after itself - genCLineDir(prc, InvalidFileIdx, 999999, m.config) + var prc = newBuilder("") + let vis = if m.hcrOn: ExportLib else: Private + prc.addDeclWithVisibility(vis): + prc.addProcHeader(ccNimCall, getDatInitName(m), "void", cProcParams()) + prc.finishProcHeaderWithBody(): + # we don't want to break into such init code - could happen if a line + # directive from a function written by the user spills after itself + genCLineDir(prc, InvalidFileIdx, 999999, m.config) - for i in cfsTypeInit1..cfsDynLibInit: - if m.s[i].buf.len != 0: - moduleDatInitRequired = true - prc.add(extract(m.s[i])) + for i in cfsTypeInit1..cfsDynLibInit: + if m.s[i].buf.len != 0: + moduleDatInitRequired = true + prc.add(extract(m.s[i])) - prc.addf("}$N$N", []) + prc.addNewline() if moduleDatInitRequired: m.s[cfsDatInitProc].add(extract(prc)) @@ -1969,7 +2059,7 @@ proc genDatInitCode(m: BModule) = # Very similar to the contents of symInDynamicLib - basically only the # things needed for the hot code reloading runtime procs to be loaded -proc hcrGetProcLoadCode(m: BModule, sym, prefix, handle, getProcFunc: string): Rope = +proc hcrGetProcLoadCode(builder: var Builder, m: BModule, sym, prefix, handle, getProcFunc: string) = let prc = magicsys.getCompilerProc(m.g.graph, sym) assert prc != nil fillProcLoc(m, prc.ast[namePos]) @@ -1980,10 +2070,10 @@ proc hcrGetProcLoadCode(m: BModule, sym, prefix, handle, getProcFunc: string): R prc.typ.sym = nil if not containsOrIncl(m.declaredThings, prc.id): - m.s[cfsVars].addf("static $2 $1;$n", [prc.loc.snippet, getTypeDesc(m, prc.loc.t, dkVar)]) + m.s[cfsVars].addVar(Global, name = prc.loc.snippet, typ = getTypeDesc(m, prc.loc.t, dkVar)) - result = "\t$1 = ($2) $3($4, $5);$n" % - [tmp, getTypeDesc(m, prc.typ, dkVar), getProcFunc.rope, handle.rope, makeCString(prefix & sym)] + builder.addAssignment(tmp, cCast(getTypeDesc(m, prc.typ, dkVar), + cCall(getProcFunc, handle, makeCString(prefix & sym)))) proc genInitCode(m: BModule) = ## this function is called in cgenWriteModules after all modules are closed, @@ -1991,46 +2081,57 @@ proc genInitCode(m: BModule) = ## into other modules, only simple rope manipulations are allowed var moduleInitRequired = m.hcrOn let initname = getInitName(m) - var prc = newBuilder("$1 N_NIMCALL(void, $2)(void) {$N" % - [rope(if m.hcrOn: "N_LIB_EXPORT" else: "N_LIB_PRIVATE"), initname]) + var prcBody = newBuilder("") # we don't want to break into such init code - could happen if a line # directive from a function written by the user spills after itself - genCLineDir(prc, InvalidFileIdx, 999999, m.config) + genCLineDir(prcBody, InvalidFileIdx, 999999, m.config) if m.typeNodes > 0: if m.hcrOn: - appcg(m, m.s[cfsTypeInit1], "\t#TNimNode* $1;$N", [m.typeNodesName]) - appcg(m, m.s[cfsTypeInit1], "\thcrRegisterGlobal($3, \"$1_$2\", sizeof(TNimNode) * $2, NULL, (void**)&$1);$N", - [m.typeNodesName, m.typeNodes, getModuleDllPath(m, m.module)]) + m.s[cfsTypeInit1].addVar(name = m.typeNodesName, typ = ptrType(cgsymValue(m, "TNimNode"))) + m.s[cfsTypeInit1].addCallStmt("hcrRegisterGlobal", + getModuleDllPath(m, m.module), + '"' & m.typeNodesName & '_' & $m.typeNodes & '"', + cOp(Mul, "NI", cSizeof("TNimNode"), cIntValue(m.typeNodes)), + "NULL", + cCast("void**", cAddr(m.typeNodesName))) else: - appcg(m, m.s[cfsTypeInit1], "static #TNimNode $1[$2];$n", - [m.typeNodesName, m.typeNodes]) + m.s[cfsTypeInit1].addArrayVar(Global, name = m.typeNodesName, + elementType = cgsymValue(m, "TNimNode"), len = m.typeNodes) if m.nimTypes > 0: - appcg(m, m.s[cfsTypeInit1], "static #TNimType $1[$2];$n", - [m.nimTypesName, m.nimTypes]) + m.s[cfsTypeInit1].addArrayVar(Global, name = m.nimTypesName, + elementType = cgsymValue(m, "TNimType"), len = m.nimTypes) if m.hcrOn: - prc.addf("\tint* nim_hcr_dummy_ = 0;$n" & - "\tNIM_BOOL nim_hcr_do_init_ = " & - "hcrRegisterGlobal($1, \"module_initialized_\", 1, NULL, (void**)&nim_hcr_dummy_);$n", - [getModuleDllPath(m, m.module)]) + prcBody.addVar(name = "nim_hcr_dummy_", typ = ptrType("int"), initializer = cIntValue(0)) + prcBody.addVar(name = "nim_hcr_do_init_", typ = "NIM_BOOL", + initializer = cCall("hcrRegisterGlobal", + getModuleDllPath(m, m.module), + "\"module_initialized_\"", + cIntValue(1), + "NULL", + cCast("void**", cAddr("nim_hcr_dummy_")))) template writeSection(thing: untyped, section: TCProcSection, addHcrGuards = false) = if m.thing.s(section).buf.len > 0: moduleInitRequired = true - if addHcrGuards: prc.add("\tif (nim_hcr_do_init_) {\n\n") - prc.add(extract(m.thing.s(section))) - if addHcrGuards: prc.add("\n\t} // nim_hcr_do_init_\n") + if addHcrGuards: + prcBody.addSingleIfStmt("nim_hcr_do_init_"): + prcBody.addNewline() + prcBody.add(extract(m.thing.s(section))) + prcBody.addNewline() + else: + prcBody.add(extract(m.thing.s(section))) if m.preInitProc.s(cpsInit).buf.len > 0 or m.preInitProc.s(cpsStmts).buf.len > 0: # Give this small function its own scope - prc.addf("{$N", []) - # Keep a bogus frame in case the code needs one - prc.add("\tTFrame FR_; FR_.len = 0;\n") - - writeSection(preInitProc, cpsLocals) - writeSection(preInitProc, cpsInit, m.hcrOn) - writeSection(preInitProc, cpsStmts) - prc.addf("}/* preInitProc end */$N", []) + prcBody.addScope(): + # Keep a bogus frame in case the code needs one + prcBody.addVar(name = "FR_", typ = "TFrame") + prcBody.addFieldAssignment("FR_", "len", cIntValue(0)) + + writeSection(preInitProc, cpsLocals) + writeSection(preInitProc, cpsInit, m.hcrOn) + writeSection(preInitProc, cpsStmts) when false: m.initProc.blocks[0].sections[cpsLocals].add m.preInitProc.s(cpsLocals) m.initProc.blocks[0].sections[cpsInit].prepend m.preInitProc.s(cpsInit) @@ -2038,37 +2139,41 @@ proc genInitCode(m: BModule) = # add new scope for following code, because old vcc compiler need variable # be defined at the top of the block - prc.addf("{$N", []) - writeSection(initProc, cpsLocals) - - if m.initProc.s(cpsInit).buf.len > 0 or m.initProc.s(cpsStmts).buf.len > 0: - moduleInitRequired = true - if optStackTrace in m.initProc.options and frameDeclared notin m.flags: - # BUT: the generated init code might depend on a current frame, so - # declare it nevertheless: - incl m.flags, frameDeclared - if preventStackTrace notin m.flags: - var procname = makeCString(m.module.name.s) - prc.add(initFrame(m.initProc, procname, quotedFilename(m.config, m.module.info))) - else: - prc.add("\tTFrame FR_; FR_.len = 0;\n") + prcBody.addScope(): + writeSection(initProc, cpsLocals) - writeSection(initProc, cpsInit, m.hcrOn) - writeSection(initProc, cpsStmts) + if m.initProc.s(cpsInit).buf.len > 0 or m.initProc.s(cpsStmts).buf.len > 0: + moduleInitRequired = true + if optStackTrace in m.initProc.options and frameDeclared notin m.flags: + # BUT: the generated init code might depend on a current frame, so + # declare it nevertheless: + incl m.flags, frameDeclared + if preventStackTrace notin m.flags: + var procname = makeCString(m.module.name.s) + prcBody.add(initFrame(m.initProc, procname, quotedFilename(m.config, m.module.info))) + else: + prcBody.addVar(name = "FR_", typ = "TFrame") + prcBody.addFieldAssignment("FR_", "len", cIntValue(0)) - if beforeRetNeeded in m.initProc.flags: - prc.add("\tBeforeRet_: ;\n") + writeSection(initProc, cpsInit, m.hcrOn) + writeSection(initProc, cpsStmts) - if m.config.exc == excGoto: - if getCompilerProc(m.g.graph, "nimTestErrorFlag") != nil: - m.appcg(prc, "\t#nimTestErrorFlag();$n", []) + if beforeRetNeeded in m.initProc.flags: + prcBody.addLabel("BeforeRet_") - if optStackTrace in m.initProc.options and preventStackTrace notin m.flags: - prc.add(deinitFrame(m.initProc)) + if m.config.exc == excGoto: + if getCompilerProc(m.g.graph, "nimTestErrorFlag") != nil: + prcBody.addCallStmt(cgsymValue(m, "nimTestErrorFlag")) - prc.addf("}$N", []) + if optStackTrace in m.initProc.options and preventStackTrace notin m.flags: + prcBody.add(deinitFrame(m.initProc)) - prc.addf("}$N$N", []) + var procs = newBuilder("") + let vis = if m.hcrOn: ExportLib else: Private + procs.addDeclWithVisibility(vis): + procs.addProcHeader(ccNimCall, initname, "void", cProcParams()) + procs.finishProcHeaderWithBody(): + procs.add(extract(prcBody)) # we cannot simply add the init proc to ``m.s[cfsProcs]`` anymore because # that would lead to a *nesting* of merge sections which the merger does @@ -2077,33 +2182,43 @@ proc genInitCode(m: BModule) = if m.hcrOn: var procsToLoad = @["hcrRegisterProc", "hcrGetProc", "hcrRegisterGlobal", "hcrGetGlobal"] - m.s[cfsInitProc].addf("N_LIB_EXPORT N_NIMCALL(void, $1)(void* handle, N_NIMCALL_PTR(void*, getProcAddr)(void*, char*)) {$N", [getHcrInitName(m)]) - if sfMainModule in m.module.flags: - # additional procs to load - procsToLoad.add("hcrInit") - procsToLoad.add("hcrAddModule") - # load procs - for curr in procsToLoad: - m.s[cfsInitProc].add(hcrGetProcLoadCode(m, curr, "", "handle", "getProcAddr")) - m.s[cfsInitProc].addf("}$N$N", []) + m.s[cfsInitProc].addDeclWithVisibility(ExportLib): + m.s[cfsInitProc].addProcHeaderWithParams(ccNimCall, getHcrInitName(m), "void"): + var hcrInitParams: ProcParamBuilder + m.s[cfsInitProc].addProcParams(hcrInitParams): + m.s[cfsInitProc].addParam(hcrInitParams, "handle", "void*") + m.s[cfsInitProc].addProcTypedParam(hcrInitParams, ccNimCall, "getProcAddr", "void*", cProcParams( + (name: "", typ: "void*"), + (name: "", typ: ptrType("char")))) + m.s[cfsInitProc].finishProcHeaderWithBody(): + if sfMainModule in m.module.flags: + # additional procs to load + procsToLoad.add("hcrInit") + procsToLoad.add("hcrAddModule") + # load procs + for curr in procsToLoad: + hcrGetProcLoadCode(m.s[cfsInitProc], m, curr, "", "handle", "getProcAddr") for i, el in pairs(m.extensionLoaders): if el.buf.len != 0: - let ex = "NIM_EXTERNC N_NIMCALL(void, nimLoadProcs$1)(void) {$2}$N$N" % - [(i.ord - '0'.ord).rope, extract(el)] moduleInitRequired = true - prc.add(ex) + procs.addDeclWithVisibility(ExternC): + procs.addProcHeader(ccNimCall, "nimLoadProcs" & $(i.ord - '0'.ord), "void", cProcParams()) + procs.finishProcHeaderWithBody(): + procs.add(extract(el)) if moduleInitRequired or sfMainModule in m.module.flags: - m.s[cfsInitProc].add(extract(prc)) + m.s[cfsInitProc].add(extract(procs)) #rememberFlag(m.g.graph, m.module, HasModuleInitProc) genDatInitCode(m) if m.hcrOn: - m.s[cfsInitProc].addf("N_LIB_EXPORT N_NIMCALL(void, HcrCreateTypeInfos)(void) {$N", []) - m.s[cfsInitProc].add(extract(m.hcrCreateTypeInfosProc)) - m.s[cfsInitProc].addf("}$N$N", []) + m.s[cfsInitProc].addDeclWithVisibility(ExportLib): + m.s[cfsInitProc].addProcHeader(ccNimCall, "HcrCreateTypeInfos", "void", cProcParams()) + m.s[cfsInitProc].finishProcHeaderWithBody(): + m.s[cfsInitProc].add(extract(m.hcrCreateTypeInfosProc)) + m.s[cfsInitProc].addNewline() registerModuleToMain(m.g, m) @@ -2257,9 +2372,10 @@ proc writeHeader(m: BModule) = openNamespaceNim(m.config.cppCustomNamespace, result) result.add(extract(m.s[cfsInitProc])) - if optGenDynLib in m.config.globalOptions: - result.add("N_LIB_IMPORT ") - result.addf("N_CDECL(void, $1NimMain)(void);$n", [rope m.config.nimMainPrefix]) + let vis = if optGenDynLib in m.config.globalOptions: ImportLib else: None + result.addDeclWithVisibility(vis): + result.addProcHeader(ccCDecl, m.config.nimMainPrefix & "NimMain", "void", cProcParams()) + result.finishProcHeaderAsProto() if m.config.cppCustomNamespace.len > 0: closeNamespaceNim(result) result.addf("#endif /* $1 */$n", [guard]) if not writeRope(extract(result), m.filename): @@ -2354,7 +2470,7 @@ proc writeModule(m: BModule, pending: bool) = if sfMainModule in m.module.flags: # generate main file: genMainProc(m) - m.s[cfsProcHeaders].add(m.g.mainModProcs) + m.s[cfsProcHeaders].add(extract(m.g.mainModProcs)) generateThreadVarsSize(m) var cf = Cfile(nimname: m.module.name.s, cname: cfile, diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index 38b716c7b31e..f9ed9c6fdae9 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -115,7 +115,7 @@ type # computing alive data on our own. BModuleList* = ref object of RootObj - mainModProcs*, mainModInit*, otherModsInit*, mainDatInit*: Rope + mainModProcs*, mainModInit*, otherModsInit*, mainDatInit*: Builder mapping*: Rope # the generated mapping file (if requested) modules*: seq[BModule] # list of all compiled modules modulesClosed*: seq[BModule] # list of the same compiled modules, but in the order they were closed diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index 6ead190962c5..1d5ceec0a367 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -628,7 +628,7 @@ template withValue*[A, B](t: var Table[A, B], key: A, value, body: untyped) = assert t[1].uid == 1314 mixin rawGet - var hc: Hash + var hc: Hash = default(Hash) var index = rawGet(t, key, hc) let hasKey = index >= 0 if hasKey: