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`](21420d8b09/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.
This commit is contained in:
metagn
2024-11-14 18:28:13 +03:00
committed by GitHub
parent 21420d8b09
commit 726195d784
7 changed files with 484 additions and 293 deletions

View File

@@ -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)

View File

@@ -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)

View File

@@ -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 & ")"

View File

@@ -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")))

View File

@@ -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("<libc/component.h>")
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)])
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)
# 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")
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)
prc.addf("}/* preInitProc end */$N", [])
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)
prcBody.addScope():
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")
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))
writeSection(initProc, cpsInit, m.hcrOn)
writeSection(initProc, cpsStmts)
writeSection(initProc, cpsInit, m.hcrOn)
writeSection(initProc, cpsStmts)
if beforeRetNeeded in m.initProc.flags:
prc.add("\tBeforeRet_: ;\n")
if beforeRetNeeded in m.initProc.flags:
prcBody.addLabel("BeforeRet_")
if m.config.exc == excGoto:
if getCompilerProc(m.g.graph, "nimTestErrorFlag") != nil:
m.appcg(prc, "\t#nimTestErrorFlag();$n", [])
if m.config.exc == excGoto:
if getCompilerProc(m.g.graph, "nimTestErrorFlag") != nil:
prcBody.addCallStmt(cgsymValue(m, "nimTestErrorFlag"))
if optStackTrace in m.initProc.options and preventStackTrace notin m.flags:
prc.add(deinitFrame(m.initProc))
if optStackTrace in m.initProc.options and preventStackTrace notin m.flags:
prcBody.add(deinitFrame(m.initProc))
prc.addf("}$N", [])
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,

View File

@@ -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

View File

@@ -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: