From 726195d784b452e001ccf31ee3f79655a92c1fa6 Mon Sep 17 00:00:00 2001 From: metagn Date: Thu, 14 Nov 2024 18:28:13 +0300 Subject: [PATCH] cbuilder: second half of cgen (#24432) Follows up #24423, needed more refactoring than I expected, sorry for ugly diff. With this pretty much all of the raw C code generating parts of the codegen are abstracted into the cbuilder API (to my knowledge at least). The current design of NIFC does not implement everything the codegen generates, such things have mostly not been adapted, they are the following along with how I'm guessing they could be implemented: * C++ specific codegen: Maybe a dialect of NIFC for generating C++? * `codegenDecl` pragma: Could be passed as a pragma to NIFC * C macros, currently only used for line info IIRC i.e. `nimln_(123)`: Just inline them when generating NIFC * Other C defines & `#line`: Maybe as NIFC directives or line infos? * There is also [this `#ifndef`](https://github.com/nim-lang/Nim/blob/21420d8b0976dc034feb90ab2878ae0dd63121ae/compiler/cgen.nim#L2249) when generating headers but NIFC shouldn't need it * `alignof`/`offsetof`: Is in `cbuilder` but not implemented in NIFC, should be easy For now we can disable C++ and the `codegenDecl` pragma when generating NIFC but since cbuilder is mostly designed to generate NIFC as a flag when booting the compiler, this hinders the ability to run the CI against NIFC. Maybe we could also make cbuilder able to generate both C and NIFC at runtime, this would be a large refactor but wouldn't be too difficult. Other missing abstractions before being able to generate NIFC are: * Primitive types and symbols i.e. `int`, `void*`, `NI`, `NIM_NULL` are currently still constant string literals, `NU8`, `NU16` etc are also sometimes generated like `"NU" & $bits`. * NIFC identifiers, i.e. adding `.c` to imported symbols and properly mangling generated ones. Not sure how difficult this is going to be. --- compiler/cbuilderbase.nim | 6 + compiler/cbuilderdecls.nim | 57 ++- compiler/cbuilderexprs.nim | 17 + compiler/ccgthreadvars.nim | 5 +- compiler/cgen.nim | 690 +++++++++++++++++++------------- compiler/cgendata.nim | 2 +- lib/pure/collections/tables.nim | 2 +- 7 files changed, 485 insertions(+), 294 deletions(-) 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: