don't generate memset calls for C++ objects

This commit is contained in:
Araq 2015-03-17 21:36:40 +01:00
commit 1fc590b6ea
5 changed files with 448 additions and 440 deletions

View file

@ -9,7 +9,7 @@
## This module implements the C code generator.
import
import
ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp,
options, intsets,
nversion, nimsets, msgs, crc, bitsets, idents, lists, types, ccgutils, os,
@ -25,7 +25,7 @@ when options.hasTinyCBackend:
var
generatedHeader: BModule
proc addForwardedProc(m: BModule, prc: PSym) =
proc addForwardedProc(m: BModule, prc: PSym) =
m.forwardedProcs.add(prc)
inc(gForwardedProcsCounter)
@ -33,7 +33,7 @@ proc getCgenModule(s: PSym): BModule =
result = if s.position >= 0 and s.position < gModules.len: gModules[s.position]
else: nil
proc findPendingModule(m: BModule, s: PSym): BModule =
proc findPendingModule(m: BModule, s: PSym): BModule =
var ms = getModule(s)
result = gModules[ms.position]
@ -41,21 +41,21 @@ proc emitLazily(s: PSym): bool {.inline.} =
result = optDeadCodeElim in gGlobalOptions or
sfDeadCodeElim in getModule(s).flags
proc initLoc(result: var TLoc, k: TLocKind, typ: PType, s: TStorageLoc) =
proc initLoc(result: var TLoc, k: TLocKind, typ: PType, s: TStorageLoc) =
result.k = k
result.s = s
result.t = typ
result.r = nil
result.flags = {}
proc fillLoc(a: var TLoc, k: TLocKind, typ: PType, r: PRope, s: TStorageLoc) =
proc fillLoc(a: var TLoc, k: TLocKind, typ: PType, r: PRope, s: TStorageLoc) =
# fills the loc if it is not already initialized
if a.k == locNone:
if a.k == locNone:
a.k = k
a.t = typ
a.s = s
if a.r == nil: a.r = r
proc isSimpleConst(typ: PType): bool =
let t = skipTypes(typ, abstractVar)
result = t.kind notin
@ -67,43 +67,43 @@ proc useStringh(m: BModule) =
m.includesStringh = true
discard lists.includeStr(m.headerFiles, "<string.h>")
proc useHeader(m: BModule, sym: PSym) =
if lfHeader in sym.loc.flags:
proc useHeader(m: BModule, sym: PSym) =
if lfHeader in sym.loc.flags:
assert(sym.annex != nil)
discard lists.includeStr(m.headerFiles, getStr(sym.annex.path))
proc cgsym(m: BModule, name: string): PRope
proc ropecg(m: BModule, frmt: TFormatStr, args: varargs[PRope]): PRope =
proc ropecg(m: BModule, frmt: TFormatStr, args: varargs[PRope]): PRope =
var i = 0
var length = len(frmt)
result = nil
var num = 0
while i < length:
if frmt[i] == '$':
while i < length:
if frmt[i] == '$':
inc(i) # skip '$'
case frmt[i]
of '$':
of '$':
app(result, "$")
inc(i)
of '#':
of '#':
inc(i)
app(result, args[num])
inc(num)
of '0'..'9':
of '0'..'9':
var j = 0
while true:
while true:
j = (j * 10) + ord(frmt[i]) - ord('0')
inc(i)
if i >= length or not (frmt[i] in {'0'..'9'}): break
if i >= length or not (frmt[i] in {'0'..'9'}): break
num = j
if j > high(args) + 1:
if j > high(args) + 1:
internalError("ropes: invalid format string $" & $j)
app(result, args[j-1])
of 'n':
if optLineDir notin gOptions: app(result, rnl)
inc(i)
of 'N':
of 'N':
app(result, rnl)
inc(i)
else: internalError("ropes: invalid format string $" & frmt[i])
@ -117,37 +117,37 @@ proc ropecg(m: BModule, frmt: TFormatStr, args: varargs[PRope]): PRope =
elif frmt[i] == '#' and frmt[i+1] == '$':
inc(i, 2)
var j = 0
while frmt[i] in Digits:
while frmt[i] in Digits:
j = (j * 10) + ord(frmt[i]) - ord('0')
inc(i)
app(result, cgsym(m, args[j-1].ropeToStr))
var start = i
while i < length:
while i < length:
if frmt[i] != '$' and frmt[i] != '#': inc(i)
else: break
if i - 1 >= start:
else: break
if i - 1 >= start:
app(result, substr(frmt, start, i - 1))
template rfmt(m: BModule, fmt: string, args: varargs[PRope]): expr =
ropecg(m, fmt, args)
proc appcg(m: BModule, c: var PRope, frmt: TFormatStr,
args: varargs[PRope]) =
proc appcg(m: BModule, c: var PRope, frmt: TFormatStr,
args: varargs[PRope]) =
app(c, ropecg(m, frmt, args))
proc appcg(m: BModule, s: TCFileSection, frmt: TFormatStr,
args: varargs[PRope]) =
proc appcg(m: BModule, s: TCFileSection, frmt: TFormatStr,
args: varargs[PRope]) =
app(m.s[s], ropecg(m, frmt, args))
proc appcg(p: BProc, s: TCProcSection, frmt: TFormatStr,
args: varargs[PRope]) =
proc appcg(p: BProc, s: TCProcSection, frmt: TFormatStr,
args: varargs[PRope]) =
app(p.s(s), ropecg(p.module, frmt, args))
var indent = "\t".toRope
proc indentLine(p: BProc, r: PRope): PRope =
result = r
for i in countup(0, p.blocks.len-1): prepend(result, indent)
proc line(p: BProc, s: TCProcSection, r: PRope) =
app(p.s(s), indentLine(p, r))
@ -180,7 +180,7 @@ proc genCLineDir(r: var PRope, filename: string, line: int) =
appf(r, "$N#line $2 $1$N",
[toRope(makeSingleLineCString(filename)), toRope(line)])
proc genCLineDir(r: var PRope, info: TLineInfo) =
proc genCLineDir(r: var PRope, info: TLineInfo) =
genCLineDir(r, info.toFullPath, info.safeLineNm)
proc genLineDir(p: BProc, t: PNode) =
@ -261,7 +261,9 @@ proc isComplexValueType(t: PType): bool {.inline.} =
proc resetLoc(p: BProc, loc: var TLoc) =
let containsGcRef = containsGarbageCollectedRef(loc.t)
if not isComplexValueType(skipTypes(loc.t, abstractVarRange)):
let typ = skipTypes(loc.t, abstractVarRange)
if isImportedCppType(typ): return
if not isComplexValueType(typ):
if containsGcRef:
var nilLoc: TLoc
initLoc(nilLoc, locTemp, loc.t, OnStack)
@ -282,35 +284,37 @@ proc resetLoc(p: BProc, loc: var TLoc) =
useStringh(p.module)
linefmt(p, cpsStmts, "memset((void*)$1, 0, sizeof($2));$n",
addrLoc(loc), rdLoc(loc))
# XXX: We can be extra clever here and call memset only
# XXX: We can be extra clever here and call memset only
# on the bytes following the m_type field?
genObjectInit(p, cpsStmts, loc.t, loc, true)
proc constructLoc(p: BProc, loc: TLoc, isTemp = false) =
if not isComplexValueType(skipTypes(loc.t, abstractRange)):
let typ = skipTypes(loc.t, abstractRange)
if not isComplexValueType(typ):
linefmt(p, cpsStmts, "$1 = 0;$n", rdLoc(loc))
else:
if not isTemp or containsGarbageCollectedRef(loc.t):
# don't use memset for temporary values for performance if we can
# avoid it:
useStringh(p.module)
linefmt(p, cpsStmts, "memset((void*)$1, 0, sizeof($2));$n",
addrLoc(loc), rdLoc(loc))
if not isImportedCppType(typ):
useStringh(p.module)
linefmt(p, cpsStmts, "memset((void*)$1, 0, sizeof($2));$n",
addrLoc(loc), rdLoc(loc))
genObjectInit(p, cpsStmts, loc.t, loc, true)
proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
if sfNoInit notin v.flags:
# we know it is a local variable and thus on the stack!
# If ``not immediateAsgn`` it is not initialized in a binding like
# ``var v = X`` and thus we need to init it.
# ``var v = X`` and thus we need to init it.
# If ``v`` contains a GC-ref we may pass it to ``unsureAsgnRef`` somehow
# which requires initialization. However this can really only happen if
# ``var v = X()`` gets transformed into ``X(&v)``.
# ``var v = X()`` gets transformed into ``X(&v)``.
# Nowadays the logic in ccgcalls deals with this case however.
if not immediateAsgn:
constructLoc(p, v.loc)
proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) =
proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) =
inc(p.labels)
result.r = con("LOC", toRope(p.labels))
linefmt(p, cpsLocals, "$1 $2;$n", getTypeDesc(p.module, t), result.r)
@ -353,10 +357,10 @@ proc deinitGCFrame(p: BProc): PRope =
if p.gcFrameId > 0:
result = ropecg(p.module,
"if (((NU)&GCFRAME) < 4096) #nimGCFrame(&GCFRAME);$n")
proc allocParam(p: BProc, s: PSym) =
proc allocParam(p: BProc, s: PSym) =
assert(s.kind == skParam)
if lfParamCopy notin s.loc.flags:
if lfParamCopy notin s.loc.flags:
inc(p.labels)
var tmp = con("%LOC", toRope(p.labels))
incl(s.loc.flags, lfParamCopy)
@ -365,8 +369,8 @@ proc allocParam(p: BProc, s: PSym) =
[tmp, s.loc.r, getTypeDesc(p.module, s.loc.t)])
s.loc.r = tmp
proc localDebugInfo(p: BProc, s: PSym) =
if {optStackTrace, optEndb} * p.options != {optStackTrace, optEndb}: return
proc localDebugInfo(p: BProc, s: PSym) =
if {optStackTrace, optEndb} * p.options != {optStackTrace, optEndb}: return
# XXX work around a bug: No type information for open arrays possible:
if skipTypes(s.typ, abstractVar).kind in {tyOpenArray, tyVarargs}: return
var a = con("&", s.loc.r)
@ -379,7 +383,7 @@ proc localDebugInfo(p: BProc, s: PSym) =
inc p.blocks[p.blocks.len-1].frameLen
proc localVarDecl(p: BProc; s: PSym): PRope =
if s.loc.k == locNone:
if s.loc.k == locNone:
fillLoc(s.loc, locLocalVar, s.typ, mangleName(s), OnStack)
if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy)
result = getTypeDesc(p.module, s.loc.t)
@ -406,22 +410,22 @@ include ccgthreadvars
proc varInDynamicLib(m: BModule, sym: PSym)
proc mangleDynLibProc(sym: PSym): PRope
proc assignGlobalVar(p: BProc, s: PSym) =
if s.loc.k == locNone:
proc assignGlobalVar(p: BProc, s: PSym) =
if s.loc.k == locNone:
fillLoc(s.loc, locGlobalVar, s.typ, mangleName(s), OnHeap)
if lfDynamicLib in s.loc.flags:
var q = findPendingModule(p.module, s)
if q != nil and not containsOrIncl(q.declaredThings, s.id):
if q != nil and not containsOrIncl(q.declaredThings, s.id):
varInDynamicLib(q, s)
else:
s.loc.r = mangleDynLibProc(s)
return
useHeader(p.module, s)
if lfNoDecl in s.loc.flags: return
if sfThread in s.flags:
if sfThread in s.flags:
declareThreadVar(p.module, s, sfImportc in s.flags)
else:
else:
var decl: PRope = nil
var td = getTypeDesc(p.module, s.loc.t)
if s.constraint.isNil:
@ -437,25 +441,25 @@ proc assignGlobalVar(p: BProc, s: PSym) =
# fixes tests/run/tzeroarray:
resetLoc(p, s.loc)
if p.module.module.options * {optStackTrace, optEndb} ==
{optStackTrace, optEndb}:
appcg(p.module, p.module.s[cfsDebugInit],
"#dbgRegisterGlobal($1, &$2, $3);$n",
[makeCString(normalize(s.owner.name.s & '.' & s.name.s)),
{optStackTrace, optEndb}:
appcg(p.module, p.module.s[cfsDebugInit],
"#dbgRegisterGlobal($1, &$2, $3);$n",
[makeCString(normalize(s.owner.name.s & '.' & s.name.s)),
s.loc.r, genTypeInfo(p.module, s.typ)])
proc assignParam(p: BProc, s: PSym) =
proc assignParam(p: BProc, s: PSym) =
assert(s.loc.r != nil)
localDebugInfo(p, s)
proc fillProcLoc(sym: PSym) =
if sym.loc.k == locNone:
proc fillProcLoc(sym: PSym) =
if sym.loc.k == locNone:
fillLoc(sym.loc, locProc, sym.typ, mangleName(sym), OnStack)
proc getLabel(p: BProc): TLabel =
proc getLabel(p: BProc): TLabel =
inc(p.labels)
result = con("LA", toRope(p.labels))
proc fixLabel(p: BProc, labl: TLabel) =
proc fixLabel(p: BProc, labl: TLabel) =
lineF(p, cpsStmts, "$1: ;$n", [labl])
proc genVarPrototype(m: BModule, sym: PSym)
@ -487,12 +491,12 @@ include ccgcalls, "ccgstmts.nim", "ccgexprs.nim"
proc isGetProcAddr(lib: PLib): bool =
let n = lib.path
result = n.kind in nkCallKinds and n.typ != nil and
result = n.kind in nkCallKinds and n.typ != nil and
n.typ.kind in {tyPointer, tyProc}
proc loadDynamicLib(m: BModule, lib: PLib) =
proc loadDynamicLib(m: BModule, lib: PLib) =
assert(lib != nil)
if not lib.generated:
if not lib.generated:
lib.generated = true
var tmp = getGlobalTempName()
assert(lib.name == nil)
@ -504,14 +508,14 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
if gVerbosity >= 2:
msgWriteln("Dependency: " & lib.path.strVal)
var loadlib: PRope = nil
for i in countup(0, high(s)):
for i in countup(0, high(s)):
inc(m.labels)
if i > 0: app(loadlib, "||")
appcg(m, loadlib, "($1 = #nimLoadLibrary((#NimStringDesc*) &$2))$n",
appcg(m, loadlib, "($1 = #nimLoadLibrary((#NimStringDesc*) &$2))$n",
[tmp, getStrLit(m, s[i])])
appcg(m, m.s[cfsDynLibInit],
"if (!($1)) #nimLoadLibraryError((#NimStringDesc*) &$2);$n",
[loadlib, getStrLit(m, lib.path.strVal)])
appcg(m, m.s[cfsDynLibInit],
"if (!($1)) #nimLoadLibraryError((#NimStringDesc*) &$2);$n",
[loadlib, getStrLit(m, lib.path.strVal)])
else:
var p = newProc(nil, m)
p.options = p.options - {optStackTrace, optEndb}
@ -520,20 +524,20 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
app(m.s[cfsVars], p.s(cpsLocals))
app(m.s[cfsDynLibInit], p.s(cpsInit))
app(m.s[cfsDynLibInit], p.s(cpsStmts))
appcg(m, m.s[cfsDynLibInit],
"if (!($1 = #nimLoadLibrary($2))) #nimLoadLibraryError($2);$n",
appcg(m, m.s[cfsDynLibInit],
"if (!($1 = #nimLoadLibrary($2))) #nimLoadLibraryError($2);$n",
[tmp, rdLoc(dest)])
if lib.name == nil: internalError("loadDynamicLib")
proc mangleDynLibProc(sym: PSym): PRope =
if sfCompilerProc in sym.flags:
if sfCompilerProc in sym.flags:
# NOTE: sym.loc.r is the external name!
result = toRope(sym.name.s)
else:
result = ropef("Dl_$1", [toRope(sym.id)])
proc symInDynamicLib(m: BModule, sym: PSym) =
proc symInDynamicLib(m: BModule, sym: PSym) =
var lib = sym.annex
let isCall = isGetProcAddr(lib)
var extname = sym.loc.r
@ -565,13 +569,13 @@ proc symInDynamicLib(m: BModule, sym: PSym) =
else:
internalError(sym.info, "wrong index: " & idx)
else:
appcg(m, m.s[cfsDynLibInit],
"\t$1 = ($2) #nimGetProcAddr($3, $4);$n",
[tmp, getTypeDesc(m, sym.typ),
appcg(m, m.s[cfsDynLibInit],
"\t$1 = ($2) #nimGetProcAddr($3, $4);$n",
[tmp, getTypeDesc(m, sym.typ),
lib.name, makeCString(ropeToStr(extname))])
appf(m.s[cfsVars], "$2 $1;$n", [sym.loc.r, getTypeDesc(m, sym.loc.t)])
proc varInDynamicLib(m: BModule, sym: PSym) =
proc varInDynamicLib(m: BModule, sym: PSym) =
var lib = sym.annex
var extname = sym.loc.r
loadDynamicLib(m, lib)
@ -579,9 +583,9 @@ proc varInDynamicLib(m: BModule, sym: PSym) =
var tmp = mangleDynLibProc(sym)
sym.loc.r = tmp # from now on we only need the internal name
inc(m.labels, 2)
appcg(m, m.s[cfsDynLibInit],
"$1 = ($2*) #nimGetProcAddr($3, $4);$n",
[tmp, getTypeDesc(m, sym.typ),
appcg(m, m.s[cfsDynLibInit],
"$1 = ($2*) #nimGetProcAddr($3, $4);$n",
[tmp, getTypeDesc(m, sym.typ),
lib.name, makeCString(ropeToStr(extname))])
appf(m.s[cfsVars], "$2* $1;$n",
[sym.loc.r, getTypeDesc(m, sym.loc.t)])
@ -590,9 +594,9 @@ proc symInDynamicLibPartial(m: BModule, sym: PSym) =
sym.loc.r = mangleDynLibProc(sym)
sym.typ.sym = nil # generate a new name
proc cgsym(m: BModule, name: string): PRope =
proc cgsym(m: BModule, name: string): PRope =
var sym = magicsys.getCompilerProc(name)
if sym != nil:
if sym != nil:
case sym.kind
of skProc, skMethod, skConverter, skIterators: genProc(m, sym)
of skVar, skResult, skLet: genVarPrototype(m, sym)
@ -604,18 +608,18 @@ proc cgsym(m: BModule, name: string): PRope =
# we're picky here for the system module too:
rawMessage(errSystemNeeds, name)
result = sym.loc.r
proc generateHeaders(m: BModule) =
app(m.s[cfsHeaders], tnl & "#include \"nimbase.h\"" & tnl)
var it = PStrEntry(m.headerFiles.head)
while it != nil:
if it.data[0] notin {'\"', '<'}:
if it.data[0] notin {'\"', '<'}:
appf(m.s[cfsHeaders], "$N#include \"$1\"$N", [toRope(it.data)])
else:
appf(m.s[cfsHeaders], "$N#include $1$N", [toRope(it.data)])
it = PStrEntry(it.next)
proc retIsNotVoid(s: PSym): bool =
proc retIsNotVoid(s: PSym): bool =
result = (s.typ.sons[0] != nil) and not isInvalidReturnType(s.typ.sons[0])
proc initFrame(p: BProc, procname, filename: PRope): PRope =
@ -663,11 +667,11 @@ proc genProcAux(m: BModule, prc: PSym) =
else:
fillResult(res)
assignParam(p, res)
if skipTypes(res.typ, abstractInst).kind == tyArray:
if skipTypes(res.typ, abstractInst).kind == tyArray:
incl(res.loc.flags, lfIndirect)
res.loc.s = OnUnknown
for i in countup(1, sonsLen(prc.typ.n) - 1):
for i in countup(1, sonsLen(prc.typ.n) - 1):
var param = prc.typ.n.sons[i].sym
if param.typ.isCompileTimeOnly: continue
assignParam(p, param)
@ -682,11 +686,11 @@ proc genProcAux(m: BModule, prc: PSym) =
else:
generatedProc = rfmt(nil, "$N$1 {$N", header)
app(generatedProc, initGCFrame(p))
if optStackTrace in prc.options:
if optStackTrace in prc.options:
app(generatedProc, p.s(cpsLocals))
var procname = makeCString(prc.name.s)
app(generatedProc, initFrame(p, procname, prc.info.quotedFilename))
else:
else:
app(generatedProc, p.s(cpsLocals))
if optProfiler in prc.options:
# invoke at proc entry for recursion:
@ -706,12 +710,12 @@ proc crossesCppBoundary(m: BModule; sym: PSym): bool {.inline.} =
sfCompileToCpp notin sym.getModule().flags and
gCmd != cmdCompileToCpp
proc genProcPrototype(m: BModule, sym: PSym) =
proc genProcPrototype(m: BModule, sym: PSym) =
useHeader(m, sym)
if lfNoDecl in sym.loc.flags: return
if lfNoDecl in sym.loc.flags: return
if lfDynamicLib in sym.loc.flags:
if getModule(sym).id != m.module.id and
not containsOrIncl(m.declaredThings, sym.id):
not containsOrIncl(m.declaredThings, sym.id):
app(m.s[cfsVars], rfmt(nil, "extern $1 $2;$n",
getTypeDesc(m, sym.loc.t), mangleDynLibProc(sym)))
elif not containsOrIncl(m.declaredProtos, sym.id):
@ -722,13 +726,13 @@ proc genProcPrototype(m: BModule, sym: PSym) =
header.app(" __attribute__((naked))")
app(m.s[cfsProcHeaders], rfmt(nil, "$1;$n", header))
proc genProcNoForward(m: BModule, prc: PSym) =
proc genProcNoForward(m: BModule, prc: PSym) =
fillProcLoc(prc)
useHeader(m, prc)
if lfImportCompilerProc in prc.loc.flags:
# dependency to a compilerproc:
discard cgsym(m, prc.name.s)
return
return
genProcPrototype(m, prc)
if lfNoDecl in prc.loc.flags: discard
elif prc.typ.callConv == ccInline:
@ -738,13 +742,13 @@ proc genProcNoForward(m: BModule, prc: PSym) =
if not containsOrIncl(m.declaredThings, prc.id): genProcAux(m, prc)
elif lfDynamicLib in prc.loc.flags:
var q = findPendingModule(m, prc)
if q != nil and not containsOrIncl(q.declaredThings, prc.id):
if q != nil and not containsOrIncl(q.declaredThings, prc.id):
symInDynamicLib(q, prc)
else:
symInDynamicLibPartial(m, prc)
elif sfImportc notin prc.flags:
var q = findPendingModule(m, prc)
if q != nil and not containsOrIncl(q.declaredThings, prc.id):
if q != nil and not containsOrIncl(q.declaredThings, prc.id):
genProcAux(q, prc)
proc requestConstImpl(p: BProc, sym: PSym) =
@ -770,7 +774,7 @@ proc requestConstImpl(p: BProc, sym: PSym) =
proc isActivated(prc: PSym): bool = prc.typ != nil
proc genProc(m: BModule, prc: PSym) =
proc genProc(m: BModule, prc: PSym) =
if sfBorrow in prc.flags or not isActivated(prc): return
fillProcLoc(prc)
if sfForward in prc.flags: addForwardedProc(m, prc)
@ -780,19 +784,19 @@ proc genProc(m: BModule, prc: PSym) =
generatedHeader != nil and lfNoDecl notin prc.loc.flags:
genProcPrototype(generatedHeader, prc)
if prc.typ.callConv == ccInline:
if not containsOrIncl(generatedHeader.declaredThings, prc.id):
if not containsOrIncl(generatedHeader.declaredThings, prc.id):
genProcAux(generatedHeader, prc)
proc genVarPrototypeAux(m: BModule, sym: PSym) =
proc genVarPrototypeAux(m: BModule, sym: PSym) =
assert(sfGlobal in sym.flags)
useHeader(m, sym)
fillLoc(sym.loc, locGlobalVar, sym.typ, mangleName(sym), OnHeap)
if (lfNoDecl in sym.loc.flags) or containsOrIncl(m.declaredThings, sym.id):
return
if sym.owner.id != m.module.id:
if (lfNoDecl in sym.loc.flags) or containsOrIncl(m.declaredThings, sym.id):
return
if sym.owner.id != m.module.id:
# else we already have the symbol generated!
assert(sym.loc.r != nil)
if sfThread in sym.flags:
if sfThread in sym.flags:
declareThreadVar(m, sym, true)
else:
app(m.s[cfsVars], "extern ")
@ -838,7 +842,7 @@ proc genFilenames(m: BModule): PRope =
result.appf("dbgRegisterFilename($1);$N", fileInfos[i].projPath.makeCString)
proc genMainProc(m: BModule) =
const
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.
@ -859,7 +863,7 @@ proc genMainProc(m: BModule) =
MainProcs =
"\tNimMain();$N"
MainProcsWithResult =
MainProcs & "\treturn nim_program_result;$N"
@ -880,7 +884,7 @@ proc genMainProc(m: BModule) =
"char** cmdLine;$N" &
"char** gEnv;$N" &
NimMainBody
PosixCMain =
"int main(int argc, char** args, char** env) {$N" &
"\tcmdLine = args;$N" &
@ -888,20 +892,20 @@ proc genMainProc(m: BModule) =
"\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 = "N_LIB_EXPORT " & NimMainBody
WinCDllMain =
@ -911,7 +915,7 @@ proc genMainProc(m: BModule) =
"\treturn 1;$N}$N$N"
PosixNimDllMain = WinNimDllMain
PosixCDllMain =
"void NIM_POSIX_INIT NimMainInit(void) {$N" &
MainProcs &
@ -919,11 +923,11 @@ proc genMainProc(m: BModule) =
var nimMain, otherMain: TFormatStr
if platform.targetOS == osWindows and
gGlobalOptions * {optGenGuiApp, optGenDynLib} != {}:
if optGenGuiApp in gGlobalOptions:
gGlobalOptions * {optGenGuiApp, optGenDynLib} != {}:
if optGenGuiApp in gGlobalOptions:
nimMain = WinNimMain
otherMain = WinCMain
else:
else:
nimMain = WinNimDllMain
otherMain = WinCDllMain
discard lists.includeStr(m.headerFiles, "<windows.h>")
@ -939,7 +943,7 @@ proc genMainProc(m: BModule) =
if gBreakpoints != nil: discard cgsym(m, "dbgRegisterBreakpoint")
if optEndb in gOptions:
gBreakpoints.app(m.genFilenames)
let initStackBottomCall =
if platform.targetOS == osStandalone: "".toRope
else: ropecg(m, "\t#initStackBottomWith((void *)&inner);$N")
@ -964,11 +968,11 @@ proc getSomeInitName(m: PSym, suffix: string): PRope =
result.app "_"
result.app m.name.s
result.app suffix
proc getInitName(m: PSym): PRope = getSomeInitName(m, "Init")
proc getDatInitName(m: PSym): PRope = getSomeInitName(m, "DatInit")
proc registerModuleToMain(m: PSym) =
proc registerModuleToMain(m: PSym) =
var
init = m.getInitName
datInit = m.getDatInitName
@ -981,19 +985,19 @@ proc registerModuleToMain(m: PSym) =
app(mainModInit, initCall)
else:
app(otherModsInit, initCall)
proc genInitCode(m: BModule) =
proc genInitCode(m: BModule) =
var initname = getInitName(m.module)
var prc = ropef("NIM_EXTERNC N_NOINLINE(void, $1)(void) {$N", [initname])
if m.typeNodes > 0:
appcg(m, m.s[cfsTypeInit1], "static #TNimNode $1[$2];$n",
if m.typeNodes > 0:
appcg(m, m.s[cfsTypeInit1], "static #TNimNode $1[$2];$n",
[m.typeNodesName, toRope(m.typeNodes)])
if m.nimTypes > 0:
appcg(m, m.s[cfsTypeInit1], "static #TNimType $1[$2];$n",
if m.nimTypes > 0:
appcg(m, m.s[cfsTypeInit1], "static #TNimType $1[$2];$n",
[m.nimTypesName, toRope(m.nimTypes)])
app(prc, initGCFrame(m.initProc))
app(prc, genSectionStart(cpsLocals))
app(prc, m.preInitProc.s(cpsLocals))
app(prc, m.initProc.s(cpsLocals))
@ -1009,7 +1013,7 @@ proc genInitCode(m: BModule) =
app(prc, initFrame(m.initProc, procname, m.module.info.quotedFilename))
else:
app(prc, ~"\tTFrame F; F.len = 0;$N")
app(prc, genSectionStart(cpsInit))
app(prc, m.preInitProc.s(cpsInit))
app(prc, m.initProc.s(cpsInit))
@ -1033,27 +1037,27 @@ proc genInitCode(m: BModule) =
app(prc, genSectionStart(i))
app(prc, m.s[i])
app(prc, genSectionEnd(i))
appf(prc, "}$N$N")
# 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
# not support. So we add it to another special section: ``cfsInitProc``
app(m.s[cfsInitProc], prc)
for i, el in pairs(m.extensionLoaders):
if el != nil:
let ex = ropef("N_NIMCALL(void, nimLoadProcs$1)(void) {$2}$N$N",
(i.ord - '0'.ord).toRope, el)
app(m.s[cfsInitProc], ex)
proc genModule(m: BModule, cfile: string): PRope =
proc genModule(m: BModule, cfile: string): PRope =
result = getFileHeader(cfile)
result.app(genMergeInfo(m))
generateHeaders(m)
generateThreadLocalStorage(m)
for i in countup(cfsHeaders, cfsProcs):
for i in countup(cfsHeaders, cfsProcs):
app(result, genSectionStart(i))
app(result, m.s[i])
app(result, genSectionEnd(i))
@ -1069,7 +1073,7 @@ proc newPostInitProc(m: BModule): BProc =
# little hack so that unique temporaries are generated:
result.labels = 200_000
proc initProcOptions(m: BModule): TOptions =
proc initProcOptions(m: BModule): TOptions =
if sfSystemModule in m.module.flags: gOptions-{optStackTrace} else: gOptions
proc rawNewModule(module: PSym, filename: string): BModule =
@ -1124,11 +1128,11 @@ proc resetModule*(m: BModule) =
m.typeNodes = 0
m.nimTypes = 0
nullify m.extensionLoaders
# indicate that this is now cached module
# the cache will be invalidated by nullifying gModules
m.fromCache = true
# we keep only the "merge info" information for the module
# and the properties that can't change:
# m.filename
@ -1155,11 +1159,11 @@ proc newModule(module: PSym): BModule =
growCache gModules, module.position
gModules[module.position] = result
if (optDeadCodeElim in gGlobalOptions):
if (sfDeadCodeElim in module.flags):
if (optDeadCodeElim in gGlobalOptions):
if (sfDeadCodeElim in module.flags):
internalError("added pending module twice: " & module.filename)
proc myOpen(module: PSym): PPassContext =
proc myOpen(module: PSym): PPassContext =
result = newModule(module)
if optGenIndex in gGlobalOptions and generatedHeader == nil:
let f = if headerFile.len > 0: headerFile else: gProjectFull
@ -1175,12 +1179,12 @@ proc writeHeader(m: BModule) =
generateHeaders(m)
generateThreadLocalStorage(m)
for i in countup(cfsHeaders, cfsProcs):
for i in countup(cfsHeaders, cfsProcs):
app(result, genSectionStart(i))
app(result, m.s[i])
app(result, genSectionEnd(i))
app(result, m.s[cfsInitProc])
if optGenDynLib in gGlobalOptions:
result.app("N_LIB_IMPORT ")
result.appf("N_CDECL(void, NimMain)(void);$n")
@ -1200,20 +1204,20 @@ proc myOpenCached(module: PSym, rd: PRodReader): PPassContext =
readMergeInfo(getCFile(m), m)
result = m
proc myProcess(b: PPassContext, n: PNode): PNode =
proc myProcess(b: PPassContext, n: PNode): PNode =
result = n
if b == nil or passes.skipCodegen(n): return
var m = BModule(b)
m.initProc.options = initProcOptions(m)
genStmts(m.initProc, n)
proc finishModule(m: BModule) =
proc finishModule(m: BModule) =
var i = 0
while i <= high(m.forwardedProcs):
while i <= high(m.forwardedProcs):
# Note: ``genProc`` may add to ``m.forwardedProcs``, so we cannot use
# a ``for`` loop here
var prc = m.forwardedProcs[i]
if sfForward in prc.flags:
if sfForward in prc.flags:
internalError(prc.info, "still forwarded: " & prc.name.s)
genProcNoForward(m, prc)
inc(i)
@ -1221,13 +1225,13 @@ proc finishModule(m: BModule) =
dec(gForwardedProcsCounter, i)
setLen(m.forwardedProcs, 0)
proc shouldRecompile(code: PRope, cfile: string): bool =
proc shouldRecompile(code: PRope, cfile: string): bool =
result = true
if optForceFullMake notin gGlobalOptions:
var objFile = toObjFile(cfile)
if writeRopeIfNotEqual(code, cfile): return
if writeRopeIfNotEqual(code, cfile): return
if existsFile(objFile) and os.fileNewer(objFile, cfile): result = false
else:
else:
writeRope(code, cfile)
# We need 2 different logics here: pending modules (including
@ -1240,15 +1244,15 @@ proc writeModule(m: BModule, pending: bool) =
# generate code for the init statements of the module:
var cfile = getCFile(m)
var cfilenoext = changeFileExt(cfile, "")
if not m.fromCache or optForceFullMake in gGlobalOptions:
genInitCode(m)
finishTypeDescriptions(m)
if sfMainModule in m.module.flags:
if sfMainModule in m.module.flags:
# generate main file:
app(m.s[cfsProcHeaders], mainModProcs)
generateThreadVarsSize(m)
var code = genModule(m, cfile)
when hasTinyCBackend:
if gCmd == cmdRun:
@ -1269,13 +1273,13 @@ proc writeModule(m: BModule, pending: bool) =
# ``system.c`` but then compilation fails due to an error. This means
# that ``system.o`` is missing, so we need to call the C compiler for it:
addFileToCompile(cfile)
addFileToLink(cfilenoext)
proc updateCachedModule(m: BModule) =
let cfile = getCFile(m)
let cfilenoext = changeFileExt(cfile, "")
if mergeRequired(m) and sfMainModule notin m.module.flags:
mergeFiles(cfile, m)
genInitCode(m)
@ -1286,17 +1290,17 @@ proc updateCachedModule(m: BModule) =
addFileToLink(cfilenoext)
proc myClose(b: PPassContext, n: PNode): PNode =
proc myClose(b: PPassContext, n: PNode): PNode =
result = n
if b == nil or passes.skipCodegen(n): return
if b == nil or passes.skipCodegen(n): return
var m = BModule(b)
if n != nil:
if n != nil:
m.initProc.options = initProcOptions(m)
genStmts(m.initProc, n)
# cached modules need to registered too:
# cached modules need to registered too:
registerModuleToMain(m.module)
if sfMainModule in m.module.flags:
if sfMainModule in m.module.flags:
m.objHasKidsValid = true
var disp = generateMethodDispatchers()
for i in 0..sonsLen(disp)-1: genProcAux(m, disp.sons[i].sym)