From 49184fe4ba93f063b9d446b04ae12cc7c8934273 Mon Sep 17 00:00:00 2001 From: metagn Date: Thu, 28 Nov 2024 08:12:51 +0300 Subject: [PATCH] implement and extend #24454 --- compiler/cbuilderbase.nim | 45 +++++++++++++++++++++++++++++++++++++++ compiler/ccgexprs.nim | 10 ++++----- compiler/ccgstmts.nim | 18 ++++++++-------- compiler/cgen.nim | 28 ++++++++++++------------ compiler/pragmas.nim | 9 ++++---- 5 files changed, 78 insertions(+), 32 deletions(-) diff --git a/compiler/cbuilderbase.nim b/compiler/cbuilderbase.nim index 3cb42bbd95c39..046f9b8ed2bea 100644 --- a/compiler/cbuilderbase.nim +++ b/compiler/cbuilderbase.nim @@ -282,3 +282,48 @@ type WaitingIf, WaitingElseIf, InBlock IfBuilder* = object state*: IfBuilderState + +when buildNifc: + import std/assertions + + proc cSymbol*(s: string): Snippet = + result = newStringOfCap(s.len) + for c in s: + case c + of 'A'..'Z', 'a'..'z', '0'..'9', '_': + result.add(c) + else: + const HexChars = "0123456789ABCDEF" + result.add('\\') + result.add(HexChars[(c.byte shr 4) and 0xF]) + result.add(HexChars[c.byte and 0xF]) + result.add(".c") + + proc getHexChar(c: char): byte = + case c + of '0'..'9': c.byte - '0'.byte + of 'A'..'Z': c.byte - 'A'.byte + 10 + of 'a'..'z': c.byte - 'a'.byte + 10 + else: raiseAssert "invalid hex char " & c + + proc unescapeCSymbol*(s: string): Snippet = + assert s.len >= 2 and s[^2 .. ^1] == ".c" + let viewLen = s.len - 2 + result = newStringOfCap(viewLen) + var i = 0 + while i < viewLen: + case s[i] + of 'A'..'Z', 'a'..'z', '0'..'9', '_': + result.add(s[i]) + of '\\': + assert i + 2 < viewLen + let b = (getHexChar(s[i + 1]) shl 4) or getHexChar(s[i + 2]) + result.add(char(b)) + inc i, 2 + else: + raiseAssert "invalid char in escaped c symbol " & s[i] + inc i + +else: + template cSymbol*(x: string): Snippet = x + template unescapeCSymbol*(x: Snippet): string = x diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 1a9b4cf9583b0..16459147c42f1 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1425,7 +1425,7 @@ proc genEcho(p: BProc, n: PNode) = p.module.includeHeader("") p.module.includeHeader("") var a: TLoc - let logName = "Genode::log" + let logName = cSymbol("Genode::log") var logCall: CallBuilder p.s(cpsStmts).addStmt(): p.s(cpsStmts).addCall(logCall, logName): @@ -1436,7 +1436,7 @@ proc genEcho(p: BProc, n: PNode) = elif n.len != 0: a = initLocExpr(p, it) let ra = a.rdLoc - let fnName = "Genode::Cstring" + let fnName = cSymbol("Genode::Cstring") p.s(cpsStmts).addArgument(logCall): case detectStrVersion(p.module) of 2: @@ -3019,8 +3019,8 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = # - not sure, and it wouldn't work if the symbol behind the magic isn't # somehow forward-declared from some other usage, but it is *possible* if lfNoDecl notin opr.loc.flags: - let prc = magicsys.getCompilerProc(p.module.g.graph, $opr.loc.snippet) - assert prc != nil, $opr.loc.snippet + let prc = magicsys.getCompilerProc(p.module.g.graph, unescapeCSymbol(opr.loc.snippet)) + assert prc != nil, unescapeCSymbol(opr.loc.snippet) # HACK: # Explicitly add this proc as declared here so the cgsym call doesn't # add a forward declaration - without this we could end up with the same @@ -3033,7 +3033,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = let wasDeclared = containsOrIncl(p.module.declaredProtos, prc.id) # Make the function behind the magic get actually generated - this will # not lead to a forward declaration! The genCall will lead to one. - cgsym(p.module, $opr.loc.snippet) + cgsym(p.module, unescapeCSymbol(opr.loc.snippet)) # make sure we have pointer-initialising code for hot code reloading if not wasDeclared and p.hcrOn: let name = mangleDynLibProc(prc) diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index e5fb1bfd18ecd..7cb62ced6adfd 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -1104,10 +1104,10 @@ proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) = if not hasDefault: if hasBuiltinUnreachable in CC[p.config.cCompiler].props: p.s(cpsStmts).addSwitchElse(): - p.s(cpsStmts).addCallStmt("__builtin_unreachable") + p.s(cpsStmts).addCallStmt(cSymbol("__builtin_unreachable")) elif hasAssume in CC[p.config.cCompiler].props: p.s(cpsStmts).addSwitchElse(): - p.s(cpsStmts).addCallStmt("__assume", cIntValue(0)) + p.s(cpsStmts).addCallStmt(cSymbol("__assume"), cIntValue(0)) if lend != "": fixLabel(p, lend) proc genCase(p: BProc, t: PNode, d: var TLoc) = @@ -1618,20 +1618,20 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) = p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "pushSafePoint"), cAddr(safePoint)) if isDefined(p.config, "nimStdSetjmp"): p.s(cpsStmts).addFieldAssignmentWithValue(safePoint, "status"): - p.s(cpsStmts).addCall("setjmp", dotField(safePoint, "context")) + p.s(cpsStmts).addCall(cSymbol("setjmp"), dotField(safePoint, "context")) elif isDefined(p.config, "nimSigSetjmp"): p.s(cpsStmts).addFieldAssignmentWithValue(safePoint, "status"): - p.s(cpsStmts).addCall("sigsetjmp", dotField(safePoint, "context"), cIntValue(0)) + p.s(cpsStmts).addCall(cSymbol("sigsetjmp"), dotField(safePoint, "context"), cIntValue(0)) elif isDefined(p.config, "nimBuiltinSetjmp"): p.s(cpsStmts).addFieldAssignmentWithValue(safePoint, "status"): - p.s(cpsStmts).addCall("__builtin_setjmp", dotField(safePoint, "context")) + p.s(cpsStmts).addCall(cSymbol("__builtin_setjmp"), dotField(safePoint, "context")) elif isDefined(p.config, "nimRawSetjmp"): if isDefined(p.config, "mswindows"): if isDefined(p.config, "vcc") or isDefined(p.config, "clangcl"): # For the vcc compiler, use `setjmp()` with one argument. # See https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/setjmp?view=msvc-170 p.s(cpsStmts).addFieldAssignmentWithValue(safePoint, "status"): - p.s(cpsStmts).addCall("setjmp", dotField(safePoint, "context")) + p.s(cpsStmts).addCall(cSymbol("setjmp"), dotField(safePoint, "context")) else: # The Windows `_setjmp()` takes two arguments, with the second being an # undocumented buffer used by the SEH mechanism for stack unwinding. @@ -1640,13 +1640,13 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) = # it to NULL. # More details: https://github.com/status-im/nimbus-eth2/issues/3121 p.s(cpsStmts).addFieldAssignmentWithValue(safePoint, "status"): - p.s(cpsStmts).addCall("_setjmp", dotField(safePoint, "context"), cIntValue(0)) + p.s(cpsStmts).addCall(cSymbol("_setjmp"), dotField(safePoint, "context"), cIntValue(0)) else: p.s(cpsStmts).addFieldAssignmentWithValue(safePoint, "status"): - p.s(cpsStmts).addCall("_setjmp", dotField(safePoint, "context")) + p.s(cpsStmts).addCall(cSymbol("_setjmp"), dotField(safePoint, "context")) else: p.s(cpsStmts).addFieldAssignmentWithValue(safePoint, "status"): - p.s(cpsStmts).addCall("setjmp", dotField(safePoint, "context")) + p.s(cpsStmts).addCall(cSymbol("setjmp"), dotField(safePoint, "context")) nonQuirkyIf = initIfStmt(p.s(cpsStmts)) initElifBranch(p.s(cpsStmts), nonQuirkyIf, removeSinglePar( cOp(Equal, dotField(safePoint, "status"), cIntValue(0)))) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 17bb6ef06635e..ce3a1042dc683 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -1736,7 +1736,7 @@ proc genNimMainBody(m: BModule, preMainCode: Snippet) = genNimMainProc(m, preMainCode) proc genPosixCMain(m: BModule) = - m.s[cfsProcs].addProcHeader("main", CInt, cProcParams( + m.s[cfsProcs].addProcHeader(cSymbol("main"), CInt, cProcParams( (name: "argc", typ: CInt), (name: "args", typ: ptrType(ptrType(CChar))), (name: "env", typ: ptrType(ptrType(CChar))))) @@ -1748,7 +1748,7 @@ proc genPosixCMain(m: BModule) = m.s[cfsProcs].addNewline() proc genStandaloneCMain(m: BModule) = - m.s[cfsProcs].addProcHeader("main", CInt, cProcParams()) + m.s[cfsProcs].addProcHeader(cSymbol("main"), CInt, cProcParams()) m.s[cfsProcs].finishProcHeaderWithBody(): genMainProcs(m) m.s[cfsProcs].addReturn(cIntValue(0)) @@ -1758,10 +1758,10 @@ proc genWinNimMain(m: BModule, preMainCode: Snippet) = genNimMainBody(m, preMainCode) proc genWinCMain(m: BModule) = - m.s[cfsProcs].addProcHeader(ccStdCall, "WinMain", CInt, cProcParams( - (name: "hCurInstance", typ: "HINSTANCE"), - (name: "hPrevInstance", typ: "HINSTANCE"), - (name: "lpCmdLine", typ: "LPSTR"), + m.s[cfsProcs].addProcHeader(ccStdCall, cSymbol("WinMain"), CInt, cProcParams( + (name: "hCurInstance", typ: cSymbol("HINSTANCE")), + (name: "hPrevInstance", typ: cSymbol("HINSTANCE")), + (name: "lpCmdLine", typ: cSymbol("LPSTR")), (name: "nCmdShow", typ: CInt))) m.s[cfsProcs].finishProcHeaderWithBody(): genMainProcsWithResult(m) @@ -1774,12 +1774,12 @@ proc genWinNimDllMain(m: BModule, preMainCode: Snippet) = 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].addProcHeader(ccStdCall, cSymbol("DllMain"), cSymbol("BOOL"), cProcParams( + (name: "hinstDLL", typ: cSymbol("HINSTANCE")), + (name: "fwdreason", typ: cSymbol("DWORD")), + (name: "lpvReserved", typ: cSymbol("LPVOID")))) m.s[cfsProcs].finishProcHeaderWithBody(): - m.s[cfsProcs].addSingleIfStmt(removeSinglePar(cOp(Equal, "fwdreason", "DLL_PROCESS_ATTACH"))): + m.s[cfsProcs].addSingleIfStmt(removeSinglePar(cOp(Equal, "fwdreason", cSymbol("DLL_PROCESS_ATTACH")))): genMainProcs(m) m.s[cfsProcs].addReturn(cIntValue(1)) m.s[cfsProcs].addNewline() @@ -1795,7 +1795,7 @@ proc genPosixCDllMain(m: BModule) = m.s[cfsProcs].addNewline() proc genGenodeNimMain(m: BModule, preMainCode: Snippet) = - let typName = "Genode::Env" + let typName = cSymbol("Genode::Env") m.s[cfsProcs].addDeclWithVisibility(Extern): m.s[cfsProcs].addVar(name = "nim_runtime_env", typ = ptrType(typName)) m.s[cfsProcs].addDeclWithVisibility(ExternC): @@ -1804,8 +1804,8 @@ proc genGenodeNimMain(m: BModule, preMainCode: Snippet) = genNimMainBody(m, preMainCode) proc genComponentConstruct(m: BModule) = - let fnName = "Libc::Component::construct" - let typName = "Libc::Env" + let fnName = cSymbol("Libc::Component::construct") + let typName = cSymbol("Libc::Env") m.s[cfsProcs].addProcHeader(fnName, CVoid, cProcParams((name: "env", typ: cppRefType(typName)))) m.s[cfsProcs].finishProcHeaderWithBody(): m.s[cfsProcs].addLineComment("Set Env used during runtime initialization") diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index c38fa2e62af6a..06e4f7f8f27d1 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -12,7 +12,8 @@ import condsyms, ast, astalgo, idents, semdata, msgs, renderer, wordrecg, ropes, options, extccomp, magicsys, trees, - types, lookups, lineinfos, pathutils, linter, modulepaths + types, lookups, lineinfos, pathutils, linter, modulepaths, + cbuilderbase from sigmatch import trySuggestPragmas @@ -156,12 +157,12 @@ proc pragmaEnsures(c: PContext, n: PNode) = proc setExternName(c: PContext; s: PSym, extname: string, info: TLineInfo) = # special cases to improve performance: if extname == "$1": - s.loc.snippet = rope(s.name.s) + s.loc.snippet = cSymbol(s.name.s) elif '$' notin extname: - s.loc.snippet = rope(extname) + s.loc.snippet = cSymbol(extname) else: try: - s.loc.snippet = rope(extname % s.name.s) + s.loc.snippet = cSymbol(extname % s.name.s) except ValueError: localError(c.config, info, "invalid extern name: '" & extname & "'. (Forgot to escape '$'?)") when hasFFI: