C++ support: codegen generates C++'s references and avoids copies

This commit is contained in:
Araq 2015-02-03 13:21:05 +01:00
commit e75e421912
7 changed files with 156 additions and 101 deletions

View file

@ -161,7 +161,13 @@ proc mapType(typ: PType): TCTypeKind =
proc mapReturnType(typ: PType): TCTypeKind =
if skipTypes(typ, typedescInst).kind == tyArray: result = ctPtr
else: result = mapType(typ)
proc isImportedType(t: PType): bool =
result = t.sym != nil and sfImportc in t.sym.flags
proc isImportedCppType(t: PType): bool =
result = t.sym != nil and sfInfixCall in t.sym.flags
proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope
proc needsComplexAssignment(typ: PType): bool =
result = containsGarbageCollectedRef(typ)
@ -170,19 +176,20 @@ proc isObjLackingTypeField(typ: PType): bool {.inline.} =
result = (typ.kind == tyObject) and ((tfFinal in typ.flags) and
(typ.sons[0] == nil) or isPureObject(typ))
proc isInvalidReturnType(rettype: PType): bool =
proc isInvalidReturnType(rettype: PType): bool =
# Arrays and sets cannot be returned by a C procedure, because C is
# such a poor programming language.
# We exclude records with refs too. This enhances efficiency and
# is necessary for proper code generation of assignments.
if rettype == nil: result = true
else:
else:
case mapType(rettype)
of ctArray:
of ctArray:
result = not (skipTypes(rettype, typedescInst).kind in
{tyVar, tyRef, tyPtr})
of ctStruct:
let t = skipTypes(rettype, typedescInst)
if rettype.isImportedCppType or t.isImportedCppType: return false
result = needsComplexAssignment(t) or
(t.kind == tyObject and not isObjLackingTypeField(t))
else: result = false
@ -297,12 +304,6 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var PRope,
else: app(params, ")")
params = con("(", params)
proc isImportedType(t: PType): bool =
result = t.sym != nil and sfImportc in t.sym.flags
proc isImportedCppType(t: PType): bool =
result = t.sym != nil and sfInfixCall in t.sym.flags
proc typeNameOrLiteral(t: PType, literal: string): PRope =
if (t.sym != nil) and (sfImportc in t.sym.flags) and (t.sym.magic == mNone):
result = getTypeName(t)
@ -421,14 +422,18 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
if accessExpr != nil: ae = ropef("$1.$2", [accessExpr, sname])
else: ae = sname
fillLoc(field.loc, locField, field.typ, ae, OnUnknown)
let fieldType = field.loc.t.skipTypes(abstractInst)
if fieldType.kind == tyArray and tfUncheckedArray in fieldType.flags:
appf(result, "$1 $2[SEQ_DECL_SIZE];$n",
[getTypeDescAux(m, fieldType.elemType, check), sname])
else:
# don't use fieldType here because we need the
# tyGenericInst for C++ template support
appf(result, "$1 $2;$n", [getTypeDescAux(m, field.loc.t, check), sname])
# for importcpp'ed objects, we only need to set field.loc, but don't
# have to recurse via 'getTypeDescAux'. And not doing so prevents problems
# with heavily templatized C++ code:
if not isImportedCppType(rectype):
let fieldType = field.loc.t.skipTypes(abstractInst)
if fieldType.kind == tyArray and tfUncheckedArray in fieldType.flags:
appf(result, "$1 $2[SEQ_DECL_SIZE];$n",
[getTypeDescAux(m, fieldType.elemType, check), sname])
else:
# don't use fieldType here because we need the
# tyGenericInst for C++ template support
appf(result, "$1 $2;$n", [getTypeDescAux(m, field.loc.t, check), sname])
else: internalError(n.info, "genRecordFieldsAux()")
proc getRecordFields(m: BModule, typ: PType, check: var IntSet): PRope =
@ -493,13 +498,15 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope =
if t.sym != nil: useHeader(m, t.sym)
result = getTypePre(m, t)
if result != nil: return
if containsOrIncl(check, t.id):
if containsOrIncl(check, t.id):
if isImportedCppType(typ) or isImportedCppType(t): return
internalError("cannot generate C type for: " & typeToString(typ))
# XXX: this BUG is hard to fix -> we need to introduce helper structs,
# but determining when this needs to be done is hard. We should split
# C type generation into an analysis and a code generation phase somehow.
case t.kind
of tyRef, tyPtr, tyVar:
let star = if t.kind == tyVar and compileToCpp(m): "&" else: "*"
var et = t.lastSon
var etB = et.skipTypes(abstractInst)
if etB.kind in {tyArrayConstr, tyArray, tyOpenArray, tyVarargs}:
@ -510,12 +517,12 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope =
case etB.kind
of tyObject, tyTuple:
if isImportedCppType(etB) and et.kind == tyGenericInst:
result = con(getTypeDescAux(m, et, check), "*")
result = con(getTypeDescAux(m, et, check), star)
else:
# no restriction! We have a forward declaration for structs
let x = getUniqueType(etB)
let name = getTypeForward(m, x)
result = con(name, "*")
result = con(name, star)
idTablePut(m.typeCache, t, result)
pushType(m, x)
of tySequence:
@ -527,7 +534,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope =
pushType(m, x)
else:
# else we have a strong dependency :-(
result = con(getTypeDescAux(m, et, check), "*")
result = con(getTypeDescAux(m, et, check), star)
idTablePut(m.typeCache, t, result)
of tyOpenArray, tyVarargs:
result = con(getTypeDescAux(m, t.sons[0], check), "*")
@ -696,16 +703,7 @@ proc getNimNode(m: BModule): PRope =
result = ropef("$1[$2]", [m.typeNodesName, toRope(m.typeNodes)])
inc(m.typeNodes)
when false:
proc getNimType(m: BModule): PRope =
result = ropef("$1[$2]", [m.nimTypesName, toRope(m.nimTypes)])
inc(m.nimTypes)
proc allocMemTI(m: BModule, typ: PType, name: PRope) =
var tmp = getNimType(m)
appf(m.s[cfsTypeInit2], "$2 = &$1;$n", [tmp, name])
proc genTypeInfoAuxBase(m: BModule, typ: PType, name, base: PRope) =
proc genTypeInfoAuxBase(m: BModule; typ, origType: PType; name, base: PRope) =
var nimtypeKind: int
#allocMemTI(m, typ, name)
if isObjLackingTypeField(typ):
@ -715,6 +713,7 @@ proc genTypeInfoAuxBase(m: BModule, typ: PType, name, base: PRope) =
var size: PRope
if tfIncompleteStruct in typ.flags: size = toRope"void*"
elif m.compileToCpp: size = getTypeDesc(m, origType)
else: size = getTypeDesc(m, typ)
appf(m.s[cfsTypeInit3],
"$1.size = sizeof($2);$n" & "$1.kind = $3;$n" & "$1.base = $4;$n",
@ -730,13 +729,13 @@ proc genTypeInfoAuxBase(m: BModule, typ: PType, name, base: PRope) =
appf(m.s[cfsVars], "TNimType $1; /* $2 */$n",
[name, toRope(typeToString(typ))])
proc genTypeInfoAux(m: BModule, typ: PType, name: PRope) =
proc genTypeInfoAux(m: BModule, typ, origType: PType, name: PRope) =
var base: PRope
if (sonsLen(typ) > 0) and (typ.sons[0] != nil):
base = genTypeInfo(m, typ.sons[0])
else:
base = toRope("0")
genTypeInfoAuxBase(m, typ, name, base)
genTypeInfoAuxBase(m, typ, origType, name, base)
proc discriminatorTableName(m: BModule, objtype: PType, d: PSym): PRope =
# bugfix: we need to search the type that contains the discriminator:
@ -814,11 +813,12 @@ proc genObjectFields(m: BModule, typ: PType, n: PNode, expr: PRope) =
field.loc.r, genTypeInfo(m, field.typ), makeCString(field.name.s)])
else: internalError(n.info, "genObjectFields")
proc genObjectInfo(m: BModule, typ: PType, name: PRope) =
if typ.kind == tyObject: genTypeInfoAux(m, typ, name)
else: genTypeInfoAuxBase(m, typ, name, toRope("0"))
proc genObjectInfo(m: BModule, typ, origType: PType, name: PRope) =
if typ.kind == tyObject: genTypeInfoAux(m, typ, origType, name)
else: genTypeInfoAuxBase(m, typ, origType, name, toRope("0"))
var tmp = getNimNode(m)
genObjectFields(m, typ, typ.n, tmp)
if not isImportedCppType(typ):
genObjectFields(m, typ, typ.n, tmp)
appf(m.s[cfsTypeInit3], "$1.node = &$2;$n", [name, tmp])
var t = typ.sons[0]
while t != nil:
@ -827,7 +827,7 @@ proc genObjectInfo(m: BModule, typ: PType, name: PRope) =
t = t.sons[0]
proc genTupleInfo(m: BModule, typ: PType, name: PRope) =
genTypeInfoAuxBase(m, typ, name, toRope("0"))
genTypeInfoAuxBase(m, typ, typ, name, toRope("0"))
var expr = getNimNode(m)
var length = sonsLen(typ)
if length > 0:
@ -854,7 +854,7 @@ proc genEnumInfo(m: BModule, typ: PType, name: PRope) =
# optimizations here: The ``typ`` field is never set, as it is redundant
# anyway. We generate a cstring array and a loop over it. Exceptional
# positions will be reset after the loop.
genTypeInfoAux(m, typ, name)
genTypeInfoAux(m, typ, typ, name)
var nodePtrs = getTempName()
var length = sonsLen(typ.n)
appf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n",
@ -894,13 +894,13 @@ proc genEnumInfo(m: BModule, typ: PType, name: PRope) =
proc genSetInfo(m: BModule, typ: PType, name: PRope) =
assert(typ.sons[0] != nil)
genTypeInfoAux(m, typ, name)
genTypeInfoAux(m, typ, typ, name)
var tmp = getNimNode(m)
appf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 0;$n" & "$3.node = &$1;$n",
[tmp, toRope(firstOrd(typ)), name])
proc genArrayInfo(m: BModule, typ: PType, name: PRope) =
genTypeInfoAuxBase(m, typ, name, genTypeInfo(m, typ.sons[1]))
genTypeInfoAuxBase(m, typ, typ, name, genTypeInfo(m, typ.sons[1]))
proc fakeClosureType(owner: PSym): PType =
# we generate the same RTTI as for a tuple[pointer, ref tuple[]]
@ -946,23 +946,23 @@ proc genTypeInfo(m: BModule, t: PType): PRope =
case t.kind
of tyEmpty: result = toRope"0"
of tyPointer, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64, tyVar:
genTypeInfoAuxBase(m, t, result, toRope"0")
genTypeInfoAuxBase(m, t, t, result, toRope"0")
of tyProc:
if t.callConv != ccClosure:
genTypeInfoAuxBase(m, t, result, toRope"0")
genTypeInfoAuxBase(m, t, t, result, toRope"0")
else:
genTupleInfo(m, fakeClosureType(t.owner), result)
of tySequence, tyRef:
genTypeInfoAux(m, t, result)
genTypeInfoAux(m, t, t, result)
if gSelectedGC >= gcMarkAndSweep:
let markerProc = genTraverseProc(m, t, tiNew)
appf(m.s[cfsTypeInit3], "$1.marker = $2;$n", [result, markerProc])
of tyPtr, tyRange: genTypeInfoAux(m, t, result)
of tyPtr, tyRange: genTypeInfoAux(m, t, t, result)
of tyArrayConstr, tyArray: genArrayInfo(m, t, result)
of tySet: genSetInfo(m, t, result)
of tyEnum: genEnumInfo(m, t, result)
of tyObject: genObjectInfo(m, t, result)
of tyTuple:
of tyObject: genObjectInfo(m, t, origType, result)
of tyTuple:
# if t.n != nil: genObjectInfo(m, t, result)
# else:
# BUGFIX: use consistently RTTI without proper field names; otherwise