Skip to content

Commit

Permalink
implement and extend nim-lang#24454
Browse files Browse the repository at this point in the history
  • Loading branch information
metagn committed Nov 28, 2024
1 parent 6f52db5 commit 49184fe
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 32 deletions.
45 changes: 45 additions & 0 deletions compiler/cbuilderbase.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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
10 changes: 5 additions & 5 deletions compiler/ccgexprs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1425,7 +1425,7 @@ proc genEcho(p: BProc, n: PNode) =
p.module.includeHeader("<base/log.h>")
p.module.includeHeader("<util/string.h>")
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):
Expand All @@ -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:
Expand Down Expand Up @@ -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
Expand All @@ -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)
Expand Down
18 changes: 9 additions & 9 deletions compiler/ccgstmts.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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) =
Expand Down Expand Up @@ -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.
Expand All @@ -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))))
Expand Down
28 changes: 14 additions & 14 deletions compiler/cgen.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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)))))
Expand All @@ -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))
Expand All @@ -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)
Expand All @@ -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()
Expand All @@ -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):
Expand All @@ -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")
Expand Down
9 changes: 5 additions & 4 deletions compiler/pragmas.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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:
Expand Down

0 comments on commit 49184fe

Please sign in to comment.