don't generate memset calls for C++ objects
This commit is contained in:
parent
ca22dfcdc2
commit
1fc590b6ea
5 changed files with 448 additions and 440 deletions
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue