MWCC/compiler_and_linker/unsorted/CABI.c

2034 lines
64 KiB
C

#include "compiler/CABI.h"
#include "compiler/CClass.h"
#include "compiler/CDecl.h"
#include "compiler/CError.h"
#include "compiler/CException.h"
#include "compiler/CExpr.h"
#include "compiler/CFunc.h"
#include "compiler/CInit.h"
#include "compiler/CInline.h"
#include "compiler/CMachine.h"
#include "compiler/CMangler.h"
#include "compiler/CParser.h"
#include "compiler/CScope.h"
#include "compiler/CSOM.h"
#include "compiler/CompilerTools.h"
#include "compiler/objects.h"
#include "compiler/scopes.h"
#include "compiler/types.h"
typedef struct OffsetList {
struct OffsetList *next;
SInt32 offset;
} OffsetList;
static OffsetList *trans_vtboffsets;
static BClassList cabi_pathroot;
static BClassList *cabi_pathcur;
static TypeClass *cabi_loop_class;
static Boolean cabi_loop_construct;
short CABI_GetStructResultArgumentIndex(TypeFunc *tfunc) {
return 0;
}
Type *CABI_GetSizeTType(void) {
return TYPE(&stunsignedlong);
}
Type *CABI_GetPtrDiffTType(void) {
return TYPE(&stsignedlong);
}
SInt16 CABI_StructSizeAlignValue(Type *type, SInt32 size) {
SInt16 align = CMach_GetTypeAlign(type);
if (align <= 1)
return 0;
else
return (align - 1) & (align - ((size & (align - 1))));
}
void CABI_ReverseBitField(TypeBitfield *tbitfield) {
UInt8 bits;
UInt8 a;
UInt8 b;
switch (tbitfield->bitfieldtype->size) {
case 1:
bits = 8;
break;
case 2:
bits = 16;
break;
case 4:
bits = 32;
break;
case 8:
bits = 64;
break;
default:
CError_FATAL(172);
}
b = tbitfield->bitlength;
a = tbitfield->offset;
tbitfield->offset = (bits - a) - b;
}
static void CABI_AllocateZeroVTablePointer(void *unk, TypeClass *tclass) {
ClassList *base;
for (base = tclass->bases; base; base = base->next) {
if (!base->is_virtual && base->base->vtable)
return;
}
tclass->size += void_ptr.size;
}
static SInt32 CABI_GetBaseSize(TypeClass *tclass) {
SInt32 size = tclass->size;
if (copts.vbase_abi_v2 && tclass->vbases)
return tclass->vbases->offset;
return size;
}
static void CABI_AllocateBases(ClassLayout *layout, TypeClass *tclass) {
Boolean flag;
TypeClass *baseclass;
ClassList *base;
VClassList *vbase;
SInt32 size;
flag = 0;
size = tclass->size;
for (base = tclass->bases; base; base = base->next) {
if (!base->is_virtual) {
baseclass = base->base;
if (!(baseclass->flags & CLASS_EMPTY)) {
base->offset = size + CMach_MemberAlignValue(TYPE(baseclass), size);
if (copts.vbase_abi_v2) {
size = base->offset + CABI_GetBaseSize(baseclass);
} else {
size = base->offset + baseclass->size;
for (vbase = baseclass->vbases; vbase; vbase = vbase->next)
size -= vbase->base->size;
}
flag = 0;
} else {
if (flag)
base->offset = ++size;
else
base->offset = size;
flag = 1;
}
}
}
tclass->size = size;
}
static void CABI_AllocateVirtualBasePointers(ClassLayout *layout, TypeClass *tclass) {
ClassList *base;
SInt32 size;
size = tclass->size;
for (base = tclass->bases; base; base = base->next) {
if (base->is_virtual) {
base->offset = size + CMach_MemberAlignValue(TYPE(&void_ptr), size);
size = base->offset + void_ptr.size;
}
}
tclass->size = size;
}
static SInt32 CABI_GetMemberOffset(TypeClass *tclass, HashNameNode *name) {
ObjMemberVar *ivar;
if (!name)
return 0;
ivar = tclass->ivars;
while (1) {
if (ivar->name == name)
return ivar->offset;
if (!(ivar = ivar->next))
CError_FATAL(362);
}
}
static void CABI_AllocateMembers(ClassLayout *layout, TypeClass *tclass) {
ObjMemberVar *ivar;
SInt32 initialSize;
SInt32 maxSize;
TypeClass *unionClass;
SInt32 unionStart;
Boolean inAnonUnion;
Boolean removeNoNameIvars;
removeNoNameIvars = 0;
initialSize = maxSize = tclass->size;
CMach_StructLayoutInitOffset(maxSize);
unionClass = NULL;
for (ivar = tclass->ivars; ivar; ivar = ivar->next) {
if (!ivar->anonunion) {
if (!(ivar->offset & 0x80000000)) {
if (tclass->mode == CLASS_MODE_UNION)
CMach_StructLayoutInitOffset(initialSize);
if (IS_TYPE_BITFIELD(ivar->type))
ivar->offset = CMach_StructLayoutBitfield(TYPE_BITFIELD(ivar->type), ivar->qual);
else
ivar->offset = CMach_StructLayoutGetOffset(ivar->type, ivar->qual);
if (tclass->mode == CLASS_MODE_UNION) {
SInt32 tmp = CMach_StructLayoutGetCurSize();
if (tmp > maxSize)
maxSize = tmp;
}
unionClass = NULL;
} else {
CError_ASSERT(412, unionClass);
ivar->offset = unionStart + CABI_GetMemberOffset(unionClass, ivar->name);
if (!inAnonUnion)
ivar->anonunion = 1;
inAnonUnion = 0;
}
if (ivar->name == no_name_node || ivar->name == NULL)
removeNoNameIvars = 1;
} else {
CError_ASSERT(422, IS_TYPE_CLASS(ivar->type));
if (tclass->mode == CLASS_MODE_UNION)
CMach_StructLayoutInitOffset(initialSize);
unionStart = CMach_StructLayoutGetOffset(ivar->type, ivar->qual);
unionClass = TYPE_CLASS(ivar->type);
inAnonUnion = 1;
if (tclass->mode == CLASS_MODE_UNION) {
SInt32 tmp = CMach_StructLayoutGetCurSize();
if (tmp > maxSize)
maxSize = tmp;
}
removeNoNameIvars = 1;
}
if (layout->vtable_ivar == ivar)
tclass->vtable->offset = ivar->offset;
}
if (removeNoNameIvars) {
ObjMemberVar **ptr = &tclass->ivars;
while (*ptr) {
if ((*ptr)->name == NULL || (*ptr)->name == no_name_node)
*ptr = (*ptr)->next;
else
ptr = &(*ptr)->next;
}
}
if (tclass->mode == CLASS_MODE_UNION)
tclass->size = maxSize;
else
tclass->size = CMach_StructLayoutGetCurSize();
if (copts.reverse_bitfields) {
for (ivar = tclass->ivars; ivar; ivar = ivar->next) {
if (IS_TYPE_BITFIELD(ivar->type))
CABI_ReverseBitField(TYPE_BITFIELD(ivar->type));
}
}
}
static void CABI_AllocateVirtualBases(ClassLayout *layout, TypeClass *tclass) {
VClassList *vbase;
SInt32 size;
size = tclass->size;
for (vbase = tclass->vbases; vbase; vbase = vbase->next) {
vbase->offset = size + CMach_MemberAlignValue(TYPE(vbase->base), size);
size = vbase->offset + CABI_GetBaseSize(vbase->base);
if (vbase->has_override)
size += CMach_MemberAlignValue(TYPE(&stunsignedlong), size) + 4;
}
tclass->size = size;
}
static Boolean CABI_FindZeroDeltaVPtr(TypeClass *tclass) {
ClassList *base;
for (base = tclass->bases; base; base = base->next) {
if (!base->is_virtual && base->base->vtable && !base->offset) {
tclass->vtable->offset = base->base->vtable->offset;
return 1;
}
}
return 0;
}
static Object *CABI_FindZeroVirtualBaseMember(TypeClass *tclass, Object *obj) {
NameSpaceObjectList *nsol;
ClassList *base;
Object *chk;
for (base = tclass->bases; base; base = base->next) {
if (!base->is_virtual && !base->offset && !base->voffset && base->base->vtable) {
for (nsol = CScope_FindName(base->base->nspace, obj->name); nsol; nsol = nsol->next) {
chk = OBJECT(nsol->object);
if (
chk->otype == OT_OBJECT &&
chk->datatype == DVFUNC &&
CClass_GetOverrideKind(TYPE_FUNC(chk->type), TYPE_FUNC(obj->type), 0) == 1
)
return chk;
}
if ((chk = CABI_FindZeroVirtualBaseMember(base->base, obj)))
return chk;
}
}
return NULL;
}
void CABI_AddVTable(TypeClass *tclass) {
tclass->vtable = galloc(sizeof(VTable));
memclrw(tclass->vtable, sizeof(VTable));
}
SInt32 CABI_GetVTableOffset(TypeClass *tclass) {
return 0;
}
static SInt32 CABI_GetBaseVTableSize(TypeClass *tclass) {
VClassList *vbase;
SInt32 size;
size = tclass->vtable->size;
for (vbase = tclass->vbases; vbase; vbase = vbase->next) {
if (vbase->base->vtable)
size -= CABI_GetBaseVTableSize(vbase->base);
}
return size;
}
static void CABI_ApplyClassFlags(Object *obj, UInt8 flags, Boolean unused) {
if (flags & CLASS_EFLAGS_INTERNAL)
obj->flags = obj->flags | OBJECT_INTERNAL;
if (flags & CLASS_EFLAGS_IMPORT)
obj->flags = obj->flags | OBJECT_IMPORT;
if (flags & CLASS_EFLAGS_EXPORT)
obj->flags = obj->flags | OBJECT_EXPORT;
}
static void CABI_AllocateVTable(ClassLayout *layout, TypeClass *tclass) {
SInt32 size;
ObjBase *objbase;
Object *obj;
ObjMemberVar *ivar;
ClassList *base;
VClassList *vbase;
int i;
size = 0;
if (!tclass->vtable) {
CABI_AddVTable(tclass);
layout->xA = layout->lex_order_count - 1;
}
if (!CABI_FindZeroDeltaVPtr(tclass)) {
ivar = galloc(sizeof(ObjMemberVar));
memclrw(ivar, sizeof(ObjMemberVar));
ivar->otype = OT_MEMBERVAR;
ivar->access = ACCESSPUBLIC;
ivar->name = vptr_name_node;
ivar->type = TYPE(&void_ptr);
layout->vtable_ivar = ivar;
for (i = layout->xA; ; i--) {
if (i < 0) {
ivar->next = tclass->ivars;
tclass->ivars = ivar;
break;
}
CError_ASSERT(666, layout->objlist[i]);
if (layout->objlist[i]->otype == OT_MEMBERVAR) {
ivar->next = OBJ_MEMBER_VAR(layout->objlist[i])->next;
OBJ_MEMBER_VAR(layout->objlist[i])->next = ivar;
break;
}
}
if (tclass->flags & (CLASS_SINGLE_OBJECT | CLASS_COM_OBJECT))
size = void_ptr.size;
else
size = 8;
} else {
layout->vtable_ivar = NULL;
}
for (base = tclass->bases; base; base = base->next) {
if (base->base->vtable && !base->is_virtual) {
base->voffset = size;
if (copts.vbase_abi_v2) {
size += CABI_GetBaseVTableSize(base->base);
} else {
size += base->base->vtable->size;
for (vbase = base->base->vbases; vbase; vbase = vbase->next) {
if (vbase->base->vtable)
size -= vbase->base->vtable->size;
}
}
}
}
for (i = 0; i < layout->lex_order_count; i++) {
CError_ASSERT(714, objbase = layout->objlist[i]);
if (objbase->otype == OT_OBJECT && OBJECT(objbase)->datatype == DVFUNC) {
TypeMemberFunc *tmethod = TYPE_METHOD(OBJECT(objbase)->type);
Object *baseobj = CABI_FindZeroVirtualBaseMember(tclass, OBJECT(objbase));
if (baseobj) {
tmethod->vtbl_index = TYPE_METHOD(baseobj->type)->vtbl_index;
} else {
tmethod->vtbl_index = size;
size += 4;
}
}
}
for (vbase = tclass->vbases; vbase; vbase = vbase->next) {
if (vbase->base->vtable) {
vbase->voffset = size;
if (copts.vbase_abi_v2)
size += CABI_GetBaseVTableSize(vbase->base);
else
size += vbase->base->vtable->size;
}
}
obj = CParser_NewCompilerDefDataObject();
CABI_ApplyClassFlags(obj, tclass->eflags, 0);
obj->name = CMangler_VTableName(tclass);
obj->type = CDecl_NewStructType(size, 4);
obj->qual = Q_CONST;
obj->nspace = tclass->nspace;
switch (tclass->action) {
case CLASS_ACTION_0:
obj->sclass = TK_STATIC;
obj->qual |= Q_20000;
break;
}
CParser_UpdateObject(obj, NULL);
tclass->vtable->object = obj;
tclass->vtable->owner = tclass;
tclass->vtable->size = size;
}
void CABI_LayoutClass(ClassLayout *layout, TypeClass *tclass) {
char saveAlignMode = copts.structalignment;
tclass->size = 0;
if (!tclass->sominfo) {
if (tclass->bases)
CABI_AllocateBases(layout, tclass);
if (tclass->flags & CLASS_HAS_VBASES)
CABI_AllocateVirtualBasePointers(layout, tclass);
if (layout->has_vtable)
CABI_AllocateVTable(layout, tclass);
CABI_AllocateMembers(layout, tclass);
if (tclass->flags & CLASS_HAS_VBASES)
CABI_AllocateVirtualBases(layout, tclass);
} else {
copts.structalignment = AlignMode2_PPC;
CABI_AllocateMembers(layout, tclass);
}
tclass->align = CMach_GetClassAlign(tclass);
if (tclass->size == 0) {
tclass->size = 1;
tclass->flags = tclass->flags | CLASS_EMPTY;
} else {
tclass->size += CABI_StructSizeAlignValue(TYPE(tclass), tclass->size);
}
tclass->flags = tclass->flags | CLASS_COMPLETED;
copts.structalignment = saveAlignMode;
}
void CABI_MakeDefaultArgConstructor(TypeClass *tclass, Object *func) {
DefArgCtorInfo *info;
Boolean saveDebugInfo;
ENodeList *copied;
ENodeList *argexprs;
FuncArg *args;
CScopeSave savedScope;
Statement firstStmt;
Statement returnStmt;
CError_FATAL(860);
if (anyerrors || func->access == ACCESSNONE)
return;
CError_ASSERT(866, info = func->u.func.defargdata);
CABI_ApplyClassFlags(func, tclass->eflags, 0);
CScope_SetFunctionScope(func, &savedScope);
CFunc_FuncGenSetup(&firstStmt, func);
saveDebugInfo = copts.filesyminfo;
copts.filesyminfo = 0;
CFunc_SetupNewFuncArgs(func, TYPE_FUNC(func->type)->args);
if (tclass->flags & CLASS_HAS_VBASES)
arguments->next->object->name = no_name_node;
firstStmt.next = &returnStmt;
memclrw(&returnStmt, sizeof(Statement));
returnStmt.type = ST_RETURN;
returnStmt.expr = lalloc(sizeof(ENode));
returnStmt.expr->type = EFUNCCALL;
returnStmt.expr->cost = 200;
returnStmt.expr->flags = 0;
returnStmt.expr->rtype = TYPE(&void_ptr);
returnStmt.expr->data.funccall.funcref = CExpr_MakeObjRefNode(info->default_func, 0);
returnStmt.expr->data.funccall.functype = TYPE_FUNC(info->default_func->type);
args = TYPE_FUNC(info->default_func->type)->args;
returnStmt.expr->data.funccall.args = lalloc(sizeof(ENodeList));
argexprs = returnStmt.expr->data.funccall.args;
argexprs->node = create_objectnode(arguments->object);
if (tclass->flags & CLASS_HAS_VBASES) {
args = args->next;
argexprs->next = lalloc(sizeof(ENodeList));
argexprs = argexprs->next;
argexprs->node = create_objectnode(arguments->next->object);
}
args = args->next;
argexprs->next = lalloc(sizeof(ENodeList));
argexprs = argexprs->next;
argexprs->node = CInline_CopyExpression(info->default_arg, CopyMode0);
while ((args = args->next) && args->dexpr) {
argexprs->next = lalloc(sizeof(ENodeList));
argexprs = argexprs->next;
argexprs->node = CInline_CopyExpression(args->dexpr, CopyMode0);
}
argexprs->next = NULL;
CFunc_CodeCleanup(&firstStmt);
CFunc_Gen(&firstStmt, func, 0);
CScope_RestoreScope(&savedScope);
copts.filesyminfo = saveDebugInfo;
func->u.func.defargdata = NULL;
}
static Object *CABI_ThisArg(void) {
CError_ASSERT(931, arguments && IS_TYPE_POINTER_ONLY(arguments->object->type));
return arguments->object;
}
ENode *CABI_MakeThisExpr(TypeClass *tclass, SInt32 offset) {
ENode *expr;
if (tclass) {
if (!tclass->sominfo) {
expr = create_objectnode(CABI_ThisArg());
if (tclass->flags & CLASS_HANDLEOBJECT)
expr = makemonadicnode(expr, EINDIRECT);
} else {
expr = CSOM_SOMSelfObjectExpr(tclass);
}
} else {
expr = create_objectnode(CABI_ThisArg());
expr->rtype = TYPE(&void_ptr);
}
if (offset)
expr = makediadicnode(expr, intconstnode(TYPE(&stunsignedlong), offset), EADD);
return expr;
}
static Object *CABI_VArg(void) {
CError_ASSERT(976, arguments && arguments->next && IS_TYPE_INT(arguments->next->object->type));
return arguments->next->object;
}
static ENode *CABI_MakeVArgExpr(void) {
return create_objectnode(CABI_VArg());
}
static ENode *CABI_MakeCopyConArgExpr(TypeClass *tclass, Boolean flag) {
ObjectList *args;
CError_ASSERT(1000, args = arguments);
CError_ASSERT(1001, args = args->next);
if (flag && (tclass->flags & CLASS_HAS_VBASES))
CError_ASSERT(1002, args = args->next);
CError_ASSERT(1003, IS_TYPE_POINTER_ONLY(args->object->type));
return create_objectnode(args->object);
}
static ENode *CABI_InitVBasePtr1(ENode *expr, TypeClass *tclass1, TypeClass *tclass2, TypeClass *tclass3, SInt32 offset) {
ClassList *base;
SInt32 newOffset;
OffsetList *list;
for (base = tclass2->bases; base; base = base->next) {
if (base->base == tclass3 && base->is_virtual) {
newOffset = offset + base->offset;
for (list = trans_vtboffsets; list; list = list->next) {
if (newOffset == list->offset)
break;
}
if (!list) {
list = lalloc(sizeof(OffsetList));
list->offset = newOffset;
list->next = trans_vtboffsets;
trans_vtboffsets = list;
expr = makediadicnode(
makemonadicnode(CABI_MakeThisExpr(NULL, newOffset), EINDIRECT),
expr,
EASS);
}
}
if (base->is_virtual)
newOffset = CClass_VirtualBaseOffset(tclass1, base->base);
else
newOffset = offset + base->offset;
expr = CABI_InitVBasePtr1(expr, tclass1, base->base, tclass3, newOffset);
}
return expr;
}
static Statement *CABI_InitVBasePtrs(Statement *stmt, TypeClass *tclass) {
ENode *expr;
VClassList *vbase;
for (vbase = tclass->vbases, trans_vtboffsets = NULL; vbase; vbase = vbase->next) {
expr = CABI_InitVBasePtr1(CABI_MakeThisExpr(NULL, vbase->offset), tclass, tclass, vbase->base, 0);
stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
stmt->expr = expr;
}
return stmt;
}
static OffsetList *CABI_GetVBasePath(TypeClass *tclass, TypeClass *baseclass) {
ClassList *base;
OffsetList *best;
OffsetList *list;
OffsetList *scan;
short bestLength;
short length;
for (base = tclass->bases; base; base = base->next) {
if (base->base == baseclass && base->is_virtual) {
best = lalloc(sizeof(OffsetList));
best->next = NULL;
best->offset = base->offset;
return best;
}
}
best = NULL;
for (base = tclass->bases; base; base = base->next) {
if ((list = CABI_GetVBasePath(base->base, baseclass))) {
for (scan = list->next, length = 1; scan; scan = scan->next)
length++;
if (base->is_virtual)
length++;
if (!best || length < bestLength) {
if (base->is_virtual) {
best = lalloc(sizeof(OffsetList));
best->next = list;
best->offset = base->offset;
} else {
best = list;
best->offset += base->offset;
}
bestLength = length;
}
}
}
return best;
}
static ENode *CABI_GetVBasePtr(TypeClass *tclass, TypeClass *baseclass) {
OffsetList *path;
ENode *expr;
CError_ASSERT(1127, path = CABI_GetVBasePath(tclass, baseclass));
expr = makemonadicnode(CABI_MakeThisExpr(NULL, path->offset), EINDIRECT);
while ((path = path->next)) {
if (path->offset)
expr = makediadicnode(expr, intconstnode(TYPE(&stunsignedlong), path->offset), EADD);
expr = makemonadicnode(expr, EINDIRECT);
}
return expr;
}
static SInt32 CABI_FindNVBase(TypeClass *tclass, TypeClass *baseclass, SInt32 offset) {
ClassList *base;
SInt32 tmp;
if (tclass == baseclass)
return offset;
for (base = tclass->bases; base; base = base->next) {
if (!base->is_virtual && (tmp = CABI_FindNVBase(base->base, baseclass, offset + base->offset)) >= 0)
return tmp;
}
return -1;
}
SInt32 CABI_GetCtorOffsetOffset(TypeClass *tclass, TypeClass *baseclass) {
SInt32 baseSize;
SInt32 size;
char saveAlignMode;
size = CABI_GetBaseSize(tclass);
if (baseclass) {
baseSize = CABI_FindNVBase(tclass, baseclass, 0);
CError_ASSERT(1178, baseSize >= 0);
size -= baseSize;
}
saveAlignMode = copts.structalignment;
if (tclass->eflags & CLASS_EFLAGS_F0)
copts.structalignment = ((tclass->eflags & CLASS_EFLAGS_F0) >> 4) - 1;
size += CMach_MemberAlignValue(TYPE(&stunsignedlong), size);
copts.structalignment = saveAlignMode;
return size;
}
static Statement *CABI_InitVBaseCtorOffsets(Statement *stmt, TypeClass *tclass) {
VClassList *vbase;
Object *tempObj;
ENode *expr;
ENode *vbaseptr;
SInt32 vboffset;
SInt32 ctorOffsetOffset;
tempObj = NULL;
for (vbase = tclass->vbases; vbase; vbase = vbase->next) {
if (vbase->has_override) {
if (!tempObj)
tempObj = create_temp_object(TYPE(&void_ptr));
vboffset = CClass_VirtualBaseOffset(tclass, vbase->base);
ctorOffsetOffset = CABI_GetCtorOffsetOffset(vbase->base, NULL);
vbaseptr = CABI_GetVBasePtr(tclass, vbase->base);
CError_ASSERT(1215, vbaseptr);
expr = makediadicnode(create_objectnode(tempObj), vbaseptr, EASS);
stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
stmt->expr = expr;
expr = makediadicnode(
create_objectnode(tempObj),
intconstnode(TYPE(&stunsignedlong), ctorOffsetOffset),
EADD);
expr = makemonadicnode(expr, EINDIRECT);
expr->rtype = TYPE(&stunsignedlong);
expr = makediadicnode(
expr,
makediadicnode(
CABI_MakeThisExpr(NULL, vboffset),
create_objectnode(tempObj),
ESUB),
EASS);
stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
stmt->expr = expr;
}
}
return stmt;
}
static Statement *CABI_InitVTablePtrs(Statement *stmt, Object *vtableObj, TypeClass *tclass, TypeClass *baseclass, SInt32 offset, SInt32 voffset) {
ClassList *base;
BClassList *orig_pathcur;
SInt32 newOffset;
SInt32 newVOffset;
OffsetList *offsetList;
SInt32 vtblOffset;
ENode *vtblExpr;
ENode *pathExpr;
BClassList path;
if (baseclass->vtable->owner == baseclass) {
vtblOffset = offset + baseclass->vtable->offset;
for (offsetList = trans_vtboffsets; offsetList; offsetList = offsetList->next) {
if (vtblOffset == offsetList->offset)
break;
}
if (!offsetList) {
offsetList = lalloc(sizeof(OffsetList));
offsetList->offset = vtblOffset;
offsetList->next = trans_vtboffsets;
trans_vtboffsets = offsetList;
vtblExpr = create_objectrefnode(vtableObj);
vtblExpr->rtype = TYPE(&void_ptr);
if ((vtblOffset = voffset + CABI_GetVTableOffset(baseclass)))
vtblExpr = makediadicnode(vtblExpr, intconstnode(TYPE(&stunsignedlong), vtblOffset), EADD);
pathExpr = CClass_AccessPathCast(&cabi_pathroot, CABI_MakeThisExpr(tclass, 0), 0);
if (baseclass->vtable->offset && !canadd(pathExpr, baseclass->vtable->offset)) {
pathExpr = makediadicnode(pathExpr, intconstnode(TYPE(&stunsignedlong), baseclass->vtable->offset), EADD);
optimizecomm(pathExpr);
}
stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
stmt->expr = makediadicnode(makemonadicnode(pathExpr, EINDIRECT), vtblExpr, EASS);
}
}
for (base = baseclass->bases; base; base = base->next) {
if (base->base->vtable) {
orig_pathcur = cabi_pathcur;
cabi_pathcur->next = &path;
path.next = NULL;
path.type = TYPE(base->base);
cabi_pathcur = &path;
if (base->is_virtual) {
newOffset = CClass_VirtualBaseOffset(tclass, base->base);
newVOffset = CClass_VirtualBaseVTableOffset(tclass, base->base);
} else {
newOffset = offset + base->offset;
newVOffset = voffset + base->voffset;
}
stmt = CABI_InitVTablePtrs(stmt, vtableObj, tclass, base->base, newOffset, newVOffset);
cabi_pathcur = orig_pathcur;
}
}
return stmt;
}
static Boolean CABI_IsOperatorNew(ObjBase *obj) {
return
obj->otype == OT_OBJECT &&
IS_TYPE_FUNC(OBJECT(obj)->type) &&
TYPE_FUNC(OBJECT(obj)->type)->args &&
TYPE_FUNC(OBJECT(obj)->type)->args->type == CABI_GetSizeTType() &&
!TYPE_FUNC(OBJECT(obj)->type)->args->next;
}
Object *CABI_ConstructorCallsNew(TypeClass *tclass) {
NameSpaceObjectList *nsol;
NameResult pr;
if (!tclass->sominfo && (tclass->flags & CLASS_HANDLEOBJECT)) {
if (CScope_FindClassMemberObject(tclass, &pr, CMangler_OperatorName(TK_NEW))) {
if (pr.obj_10) {
if (CABI_IsOperatorNew(pr.obj_10))
return OBJECT(pr.obj_10);
} else {
for (nsol = pr.nsol_14; nsol; nsol = nsol->next) {
if (CABI_IsOperatorNew(nsol->object))
return OBJECT(nsol->object);
}
}
}
return newh_func;
}
return NULL;
}
void CABI_TransConstructor(Object *obj, Statement *firstStmt, TypeClass *tclass, TransConstructorCallback callback, Boolean has_try) {
Statement *stmt;
Object *tmpfunc;
Object *tmpfunc2;
CLabel *label;
ENode *expr;
ClassList *base;
VClassList *vbase;
ObjMemberVar *ivar;
Type *type;
CtorChain *chain;
Boolean errorflag;
stmt = firstStmt;
if ((tmpfunc = CABI_ConstructorCallsNew(tclass))) {
label = newlabel();
stmt = CFunc_InsertStatement(ST_IFGOTO, firstStmt);
stmt->expr = CABI_MakeThisExpr(NULL, 0);
stmt->label = label;
expr = makediadicnode(
CABI_MakeThisExpr(NULL, 0),
funccallexpr(tmpfunc, intconstnode(CABI_GetSizeTType(), tclass->size), NULL, NULL, NULL),
EASS);
stmt = CFunc_InsertStatement(ST_IFGOTO, stmt);
stmt->expr = expr;
stmt->label = label;
stmt = CFunc_InsertStatement(ST_RETURN, stmt);
stmt->expr = NULL;
stmt = CFunc_InsertStatement(ST_LABEL, stmt);
stmt->label = label;
label->stmt = stmt;
}
if (has_try) {
for (stmt = firstStmt; ; stmt = stmt->next) {
CError_ASSERT(1408, stmt);
if (stmt->type == ST_BEGINCATCH)
break;
}
}
if (!tclass->sominfo) {
if (tclass->flags & CLASS_HAS_VBASES) {
label = newlabel();
stmt = CFunc_InsertStatement(ST_IFGOTO, stmt);
stmt->expr = CExpr_New_EEQU_Node(CABI_MakeVArgExpr(), intconstnode(TYPE(&stsignedshort), 0));
stmt->label = label;
stmt = CABI_InitVBasePtrs(stmt, tclass);
for (vbase = tclass->vbases; vbase; vbase = vbase->next) {
if (!callback) {
for (chain = ctor_chain; chain; chain = chain->next) {
if (chain->what == CtorChain_VBase && chain->u.vbase == vbase)
break;
}
if (chain) {
stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
stmt->expr = chain->objexpr;
} else {
expr = CClass_DefaultConstructorCall(
vbase->base,
tclass,
CABI_MakeThisExpr(NULL, vbase->offset),
0, 1, 1, &errorflag);
if (expr) {
stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
stmt->expr = expr;
} else if (errorflag) {
CError_Error(CErrorStr213, tclass, 0, vbase->base, 0);
}
}
} else {
stmt = callback(stmt, tclass, vbase->base, vbase->offset, 1);
}
if ((tmpfunc = CClass_Destructor(vbase->base)))
CExcept_RegisterMember(stmt, CABI_ThisArg(), vbase->offset, tmpfunc, CABI_VArg(), 0);
}
stmt = CFunc_InsertStatement(ST_LABEL, stmt);
stmt->label = label;
label->stmt = stmt;
}
for (base = tclass->bases; base; base = base->next) {
if (base->is_virtual)
continue;
if (!callback) {
for (chain = ctor_chain; chain; chain = chain->next) {
if (chain->what == CtorChain_Base && chain->u.base == base)
break;
}
if (chain) {
stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
stmt->expr = chain->objexpr;
} else {
expr = CClass_DefaultConstructorCall(
base->base,
tclass,
CABI_MakeThisExpr(NULL, base->offset),
0, 1, 0, &errorflag);
if (expr) {
stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
stmt->expr = expr;
} else if (errorflag) {
CError_Error(CErrorStr213, tclass, 0, base->base, 0);
}
}
} else {
stmt = callback(stmt, tclass, base->base, base->offset, 1);
}
if ((tmpfunc = CClass_Destructor(base->base)))
CExcept_RegisterMember(stmt, CABI_ThisArg(), base->offset, tmpfunc, NULL, 0);
}
if (tclass->vtable && tclass->vtable->object && tclass->vtable->owner == tclass) {
cabi_pathroot.next = NULL;
cabi_pathroot.type = TYPE(tclass);
cabi_pathcur = &cabi_pathroot;
trans_vtboffsets = NULL;
stmt = CABI_InitVTablePtrs(stmt, tclass->vtable->object, tclass, tclass, 0, 0);
}
}
if (!tclass->sominfo && (tclass->flags & CLASS_FLAGS_8000))
stmt = CABI_InitVBaseCtorOffsets(stmt, tclass);
if (!callback) {
for (ivar = tclass->ivars; ivar; ivar = ivar->next) {
for (chain = ctor_chain; chain; chain = chain->next) {
if (chain->what == CtorChain_MemberVar && chain->u.membervar == ivar) {
if (IS_TYPE_ARRAY(ivar->type))
chain = NULL;
break;
}
}
if (chain) {
stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
stmt->expr = chain->objexpr;
type = ivar->type;
switch (type->type) {
case TYPEARRAY:
do {
type = TPTR_TARGET(type);
} while (IS_TYPE_ARRAY(type));
if (IS_TYPE_CLASS(type)) {
if ((tmpfunc = CClass_Destructor(TYPE_CLASS(type)))) {
CError_ASSERT(1560, type->size);
CExcept_RegisterMemberArray(
stmt,
CABI_ThisArg(),
ivar->offset,
tmpfunc,
ivar->type->size / type->size,
type->size);
}
}
break;
case TYPECLASS:
if ((tmpfunc = CClass_Destructor(TYPE_CLASS(type)))) {
CExcept_RegisterMember(
stmt,
CABI_ThisArg(),
ivar->offset,
tmpfunc,
NULL,
1);
}
break;
}
} else {
type = ivar->type;
switch (type->type) {
case TYPEARRAY:
do {
type = TPTR_TARGET(type);
} while (IS_TYPE_ARRAY(type));
if (IS_TYPE_CLASS(type) && CClass_Constructor(TYPE_CLASS(type))) {
if (
(tmpfunc = CClass_DefaultConstructor(TYPE_CLASS(type))) ||
(tmpfunc = CClass_DummyDefaultConstructor(TYPE_CLASS(type)))
)
{
tmpfunc2 = CClass_Destructor(TYPE_CLASS(type));
if (tmpfunc2)
tmpfunc2 = CABI_GetDestructorObject(tmpfunc2, 1);
stmt = CInit_ConstructClassArray(
stmt,
TYPE_CLASS(type),
tmpfunc,
tmpfunc2,
CABI_MakeThisExpr(tclass, ivar->offset),
ivar->type->size / type->size);
if (tmpfunc2)
CExcept_RegisterMemberArray(
stmt,
CABI_ThisArg(),
ivar->offset,
tmpfunc2,
ivar->type->size / type->size,
type->size);
} else {
CError_Error(CErrorStr214, tclass, 0, ivar->name->name);
}
}
break;
case TYPECLASS:
expr = CClass_DefaultConstructorCall(
TYPE_CLASS(type),
NULL,
CABI_MakeThisExpr(tclass, ivar->offset),
1, 1, 0, &errorflag);
if (expr) {
stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
stmt->expr = expr;
} else if (errorflag) {
CError_Error(CErrorStr214, tclass, 0, ivar->name->name);
}
if ((tmpfunc = CClass_Destructor(TYPE_CLASS(type)))) {
if (!expr) {
stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
stmt->expr = nullnode();
}
CExcept_RegisterMember(
stmt,
CABI_ThisArg(),
ivar->offset,
tmpfunc,
NULL,
1);
}
break;
}
}
}
} else {
stmt = callback(stmt, tclass, NULL, 0, 1);
}
if (!tclass->sominfo) {
for (stmt = firstStmt->next; stmt; stmt = stmt->next) {
if (stmt->type == ST_RETURN) {
CError_ASSERT(1661, !stmt->expr);
stmt->expr = CABI_MakeThisExpr(NULL, 0);
}
}
}
}
void CABI_MakeDefaultConstructor(TypeClass *tclass, Object *func) {
Boolean saveDebugInfo;
CScopeSave savedScope;
Statement firstStmt;
Statement returnStmt;
if (anyerrors || func->access == ACCESSNONE)
return;
CABI_ApplyClassFlags(func, tclass->eflags, 0);
CScope_SetFunctionScope(func, &savedScope);
CFunc_FuncGenSetup(&firstStmt, func);
saveDebugInfo = copts.filesyminfo;
copts.filesyminfo = 0;
CFunc_SetupNewFuncArgs(func, TYPE_FUNC(func->type)->args);
ctor_chain = NULL;
if (tclass->flags & CLASS_HAS_VBASES)
arguments->next->object->name = CParser_GetUniqueName();
firstStmt.next = &returnStmt;
memclrw(&returnStmt, sizeof(Statement));
returnStmt.type = ST_RETURN;
CABI_TransConstructor(func, &firstStmt, tclass, NULL, 0);
CFunc_CodeCleanup(&firstStmt);
CFunc_Gen(&firstStmt, func, 0);
CScope_RestoreScope(&savedScope);
copts.filesyminfo = saveDebugInfo;
}
static ENode *CABI_AssignObject(TypeClass *tclass, ENode *expr1, ENode *expr2) {
Object *assignfunc;
FuncArg *arg;
assignfunc = CClass_AssignmentOperator(tclass);
if (!assignfunc) {
expr1 = makemonadicnode(expr1, EINDIRECT);
expr1->rtype = TYPE(tclass);
return makediadicnode(expr1, expr2, EASS);
}
CError_ASSERT(1731,
IS_TYPE_FUNC(assignfunc->type) &&
(arg = TYPE_FUNC(assignfunc->type)->args) &&
(arg = arg->next));
expr2 = argumentpromotion(expr2, arg->type, arg->qual, 1);
return funccallexpr(assignfunc, expr1, expr2, NULL, NULL);
}
static Type *CABI_FindIntegralSizeType(SInt32 size) {
if (stunsignedchar.size == size)
return TYPE(&stunsignedchar);
if (stunsignedshort.size == size)
return TYPE(&stunsignedshort);
if (stunsignedint.size == size)
return TYPE(&stunsignedint);
if (stunsignedlong.size == size)
return TYPE(&stunsignedlong);
if (stunsignedlonglong.size == size)
return TYPE(&stunsignedlonglong);
CError_FATAL(1756);
return NULL;
}
#ifdef __MWERKS__
#pragma options align=mac68k
#endif
typedef struct CopyRegion {
struct CopyRegion *next;
Type *type;
SInt32 start;
SInt32 end;
Boolean flag;
} CopyRegion;
#ifdef __MWERKS__
#pragma options align=reset
#endif
static CopyRegion *CABI_AppendCopyRegion(CopyRegion *regions, Type *type, SInt32 start, Boolean flag) {
CopyRegion *region;
SInt32 end;
if (IS_TYPE_BITFIELD(type))
type = TYPE_BITFIELD(type)->bitfieldtype;
end = start + type->size;
if (flag) {
for (region = regions; region; region = region->next) {
if (region->flag) {
if (region->start <= start && region->end >= end)
return regions;
if (region->start >= start && region->end <= end) {
region->type = type;
region->start = start;
region->end = end;
for (region = region->next; region; region = region->next) {
if (region->start >= start && region->end <= end)
region->end = region->start;
}
return regions;
}
}
}
}
if (regions) {
region = regions;
while (region->next)
region = region->next;
region->next = lalloc(sizeof(CopyRegion));
region = region->next;
} else {
regions = lalloc(sizeof(CopyRegion));
region = regions;
}
region->next = NULL;
region->type = type;
region->start = start;
region->end = end;
region->flag = flag;
return regions;
}
static ENode *CABI_ClassInitLoopCallBack(ENode *var1, ENode *var2) {
ENodeList *list;
var2 = makemonadicnode(var2, EINDIRECT);
var2->rtype = TYPE(cabi_loop_class);
if (cabi_loop_construct) {
list = lalloc(sizeof(ENodeList));
memclrw(list, sizeof(ENodeList));
list->node = var2;
return CExpr_ConstructObject(cabi_loop_class, var1, list, 1, 1, 0, 1, 1);
} else {
return CABI_AssignObject(cabi_loop_class, var1, var2);
}
}
static Statement *CABI_CopyConAssignCB(Statement *stmt, TypeClass *tclass, TypeClass *baseclass, SInt32 offset, Boolean flag) {
ENode *expr;
ENode *expr2;
ENode *startExpr;
ENode *endExpr;
ENodeList *list;
ObjMemberVar *ivar;
CopyRegion *regions;
Type *type;
SInt32 i;
SInt32 count;
Boolean isFlagNotSet;
Object *tmpfunc;
if (baseclass) {
if (baseclass->flags & CLASS_EMPTY) {
if (
(flag && !CClass_CopyConstructor(baseclass)) ||
(!flag && !CClass_AssignmentOperator(baseclass))
)
return stmt;
}
expr = CABI_MakeCopyConArgExpr(tclass, flag);
expr->rtype = TYPE(baseclass);
expr->data.monadic = CClass_DirectBasePointerCast(expr->data.monadic, tclass, baseclass);
stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
if (flag) {
list = lalloc(sizeof(ENodeList));
list->next = NULL;
list->node = expr;
stmt->expr = CExpr_ConstructObject(
baseclass,
CABI_MakeThisExpr(NULL, offset),
list,
1, 0, 0, 0, 1);
} else {
stmt->expr = CABI_AssignObject(
baseclass,
CClass_DirectBasePointerCast(CABI_MakeThisExpr(NULL, 0), tclass, baseclass),
expr);
}
} else {
isFlagNotSet = !flag;
for (ivar = tclass->ivars, regions = NULL; ivar; ivar = ivar->next) {
if (ivar->name == vptr_name_node)
continue;
type = ivar->type;
if (isFlagNotSet) {
if (CParser_IsConst(type, ivar->qual) || IS_TYPE_REFERENCE(type) != 0) {
CError_Error(CErrorStr387, tclass, 0);
isFlagNotSet = 0;
}
}
switch (type->type) {
case TYPEARRAY:
while (IS_TYPE_ARRAY(type))
type = TPTR_TARGET(type);
if (!IS_TYPE_CLASS(type)) {
regions = CABI_AppendCopyRegion(regions, ivar->type, ivar->offset, 1);
break;
}
case TYPECLASS:
if (flag) {
if (CClass_CopyConstructor(TYPE_CLASS(type)) || CClass_CopyConstructor(TYPE_CLASS(type))) {
regions = CABI_AppendCopyRegion(regions, ivar->type, ivar->offset, 0);
break;
}
} else {
if (CClass_AssignmentOperator(TYPE_CLASS(type))) {
regions = CABI_AppendCopyRegion(regions, ivar->type, ivar->offset, 0);
break;
}
}
default:
regions = CABI_AppendCopyRegion(regions, ivar->type, ivar->offset, 1);
}
}
for (; regions; regions = regions->next) {
if (regions->start >= regions->end)
continue;
type = regions->type;
expr = CABI_MakeCopyConArgExpr(tclass, flag);
expr->rtype = type;
if (!canadd(expr->data.monadic, regions->start)) {
expr->data.monadic = makediadicnode(
expr->data.monadic,
intconstnode(TYPE(&stunsignedlong), regions->start),
EADD);
optimizecomm(expr->data.monadic);
}
if (!regions->flag) {
if (IS_TYPE_ARRAY(type)) {
while (IS_TYPE_ARRAY(type))
type = TPTR_TARGET(type);
CError_ASSERT(1966, IS_TYPE_CLASS(type));
if (type->size) {
count = regions->type->size / type->size;
if (count > 4) {
startExpr = CABI_MakeThisExpr(tclass, regions->start);
endExpr = CABI_MakeThisExpr(tclass, regions->start + regions->type->size);
expr = CABI_MakeCopyConArgExpr(tclass, flag)->data.monadic;
if (!canadd(expr, regions->start)) {
expr = makediadicnode(
expr,
intconstnode(TYPE(&stunsignedlong), regions->start),
EADD);
optimizecomm(expr);
}
cabi_loop_class = TYPE_CLASS(type);
cabi_loop_construct = flag;
stmt = CFunc_GenerateLoop(
stmt,
CDecl_NewPointerType(type),
startExpr,
endExpr,
intconstnode(TYPE(&stunsignedlong), type->size),
expr,
CABI_ClassInitLoopCallBack);
} else {
for (i = 0, offset = regions->start; i < count; i++, offset += type->size) {
expr = CABI_MakeCopyConArgExpr(tclass, flag);
expr->rtype = type;
if (!canadd(expr->data.monadic, offset)) {
expr->data.monadic = makediadicnode(
expr->data.monadic,
intconstnode(TYPE(&stunsignedlong), offset),
EADD);
optimizecomm(expr->data.monadic);
}
stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
if (flag) {
list = lalloc(sizeof(ENodeList));
memclrw(list, sizeof(ENodeList));
list->node = expr;
stmt->expr = CExpr_ConstructObject(
TYPE_CLASS(type),
CABI_MakeThisExpr(tclass, offset),
list,
1, 1, 0, 1, 1);
} else {
stmt->expr = CABI_AssignObject(
TYPE_CLASS(type),
CABI_MakeThisExpr(tclass, offset),
expr);
}
}
}
if (flag && (tmpfunc = CClass_Destructor(TYPE_CLASS(type))))
CExcept_RegisterMemberArray(stmt, CABI_ThisArg(), regions->start, tmpfunc, count, type->size);
}
} else {
CError_ASSERT(2027, IS_TYPE_CLASS(type));
stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
if (flag) {
list = lalloc(sizeof(ENodeList));
memclrw(list, sizeof(ENodeList));
list->node = expr;
stmt->expr = CExpr_ConstructObject(
TYPE_CLASS(type),
CABI_MakeThisExpr(tclass, regions->start),
list,
1, 1, 0, 1, 1);
if ((tmpfunc = CClass_Destructor(TYPE_CLASS(type))))
CExcept_RegisterMember(stmt, CABI_ThisArg(), regions->start, tmpfunc, NULL, 1);
} else {
stmt->expr = CABI_AssignObject(
TYPE_CLASS(type),
CABI_MakeThisExpr(tclass, regions->start),
expr);
}
}
} else {
if (IS_TYPE_ARRAY(type)) {
if (type->size > 1 && ((regions->start & 1) || (type->size & 1))) {
stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
stmt->expr = funccallexpr(
copy_func,
CABI_MakeThisExpr(tclass, regions->start),
getnodeaddress(expr, 0),
intconstnode(CABI_GetSizeTType(), type->size),
NULL);
continue;
}
type = CDecl_NewStructType(type->size, CMach_GetTypeAlign(type));
expr->rtype = type;
}
expr2 = makemonadicnode(CABI_MakeThisExpr(tclass, regions->start), EINDIRECT);
expr2->rtype = type;
stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
stmt->expr = makediadicnode(expr2, expr, EASS);
}
}
}
return stmt;
}
void CABI_MakeDefaultCopyConstructor(TypeClass *tclass, Object *func) {
Boolean saveDebugInfo;
CScopeSave savedScope;
Statement firstStmt;
Statement returnStmt;
if (anyerrors || func->access == ACCESSNONE)
return;
CABI_ApplyClassFlags(func, tclass->eflags, 0);
CScope_SetFunctionScope(func, &savedScope);
CFunc_FuncGenSetup(&firstStmt, func);
saveDebugInfo = copts.filesyminfo;
copts.filesyminfo = 0;
CFunc_SetupNewFuncArgs(func, TYPE_FUNC(func->type)->args);
ctor_chain = NULL;
if (tclass->flags & CLASS_HAS_VBASES)
arguments->next->object->name = CParser_GetUniqueName();
firstStmt.next = &returnStmt;
memclrw(&returnStmt, sizeof(Statement));
returnStmt.type = ST_RETURN;
CABI_TransConstructor(func, &firstStmt, tclass, CABI_CopyConAssignCB, 0);
CFunc_CodeCleanup(&firstStmt);
CFunc_Gen(&firstStmt, func, 0);
CScope_RestoreScope(&savedScope);
copts.filesyminfo = saveDebugInfo;
}
void CABI_MakeDefaultAssignmentOperator(TypeClass *tclass, Object *func) {
Boolean saveDebugInfo;
Statement *stmt;
ClassList *base;
VClassList *vbase;
ENode *expr1;
ENode *expr2;
CScopeSave savedScope;
Statement firstStmt;
if (anyerrors || func->access == ACCESSNONE)
return;
CABI_ApplyClassFlags(func, tclass->eflags, 0);
CScope_SetFunctionScope(func, &savedScope);
CFunc_FuncGenSetup(&firstStmt, func);
saveDebugInfo = copts.filesyminfo;
copts.filesyminfo = 0;
CFunc_SetupNewFuncArgs(func, TYPE_FUNC(func->type)->args);
stmt = curstmt;
if (tclass->mode == CLASS_MODE_UNION) {
expr1 = makemonadicnode(CABI_MakeThisExpr(tclass, 0), EINDIRECT);
expr1->rtype = TYPE(tclass);
expr2 = CABI_MakeCopyConArgExpr(tclass, 0);
expr2->rtype = TYPE(tclass);
stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
stmt->expr = makediadicnode(expr1, expr2, EASS);
} else {
for (vbase = tclass->vbases; vbase; vbase = vbase->next) {
stmt = CABI_CopyConAssignCB(stmt, tclass, vbase->base, vbase->offset, 0);
}
for (base = tclass->bases; base; base = base->next) {
if (!base->is_virtual)
stmt = CABI_CopyConAssignCB(stmt, tclass, base->base, base->offset, 0);
}
stmt = CABI_CopyConAssignCB(stmt, tclass, NULL, 0, 0);
}
stmt = CFunc_InsertStatement(ST_RETURN, stmt);
stmt->expr = CABI_MakeThisExpr(NULL, 0);
CFunc_CodeCleanup(&firstStmt);
CFunc_Gen(&firstStmt, func, 0);
CScope_RestoreScope(&savedScope);
copts.filesyminfo = saveDebugInfo;
}
static Statement *CABI_DestroyMembers(Statement *stmt, ObjMemberVar *ivars, TypeClass *tclass) {
Type *type;
Object *dtor;
ENode *expr;
for (; ivars; ivars = ivars->next) {
type = ivars->type;
if (IS_TYPE_ARRAY(type)) {
while (IS_TYPE_ARRAY(type))
type = TPTR_TARGET(type);
if (IS_TYPE_CLASS(type) && (dtor = CClass_Destructor(TYPE_CLASS(type)))) {
dtor = CABI_GetDestructorObject(dtor, 1);
stmt = CABI_DestroyMembers(stmt, ivars->next, tclass);
expr = create_objectrefnode(dtor);
expr->flags = expr->flags | ENODE_FLAG_80;
stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
stmt->expr = funccallexpr(
darr_func,
CABI_MakeThisExpr(tclass, ivars->offset),
expr,
intconstnode(TYPE(&stsignedlong), type->size),
intconstnode(TYPE(&stsignedlong), ivars->type->size / type->size)
);
return stmt;
}
} else {
if (IS_TYPE_CLASS(type) && (dtor = CClass_Destructor(TYPE_CLASS(type)))) {
stmt = CABI_DestroyMembers(stmt, ivars->next, tclass);
stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
stmt->expr = CABI_DestroyObject(
dtor,
CABI_MakeThisExpr(tclass, ivars->offset),
CABIDestroy1,
1,
0
);
return stmt;
}
}
}
return stmt;
}
static Statement *CABI_DestroyBases(Statement *stmt, ClassList *bases) {
ClassList *base;
Object *dtor;
SInt32 count;
SInt32 i;
base = bases;
count = 0;
while (base) {
base = base->next;
count++;
}
while (count > 0) {
base = bases;
i = count;
while (i-- > 1)
base = base->next;
if (!base->is_virtual && (dtor = CClass_Destructor(base->base))) {
stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
stmt->expr = CABI_DestroyObject(
dtor,
CABI_MakeThisExpr(NULL, base->offset),
CABIDestroy0,
1,
0);
}
count--;
}
return stmt;
}
static Statement *CABI_DestroyVBases(Statement *stmt, VClassList *vbases) {
Object *dtor;
for (; vbases; vbases = vbases->next) {
if ((dtor = CClass_Destructor(vbases->base))) {
stmt = CABI_DestroyVBases(stmt, vbases->next);
stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
stmt->expr = CABI_DestroyObject(
dtor,
CABI_MakeThisExpr(NULL, vbases->offset),
CABIDestroy0,
1,
0);
break;
}
}
return stmt;
}
void CABI_TransDestructor(Object *obj1, Object *obj2, Statement *stmt, TypeClass *tclass, CABIDestroyMode mode) {
CLabel *label2;
Boolean flag29;
CLabel *label;
Statement *scan;
Boolean flag25;
Boolean flag24;
Boolean flag23;
CLabel *label3;
Object *dealloc;
Boolean deallocFlag;
if (tclass->sominfo) {
flag24 = 0;
flag25 = 0;
flag29 = 0;
flag23 = 1;
} else {
flag24 = 1;
flag23 = 1;
flag25 = 1;
flag29 = 1;
}
label = newlabel();
for (scan = stmt; scan; scan = scan->next) {
if (scan->type == ST_RETURN) {
CError_ASSERT(2329, !scan->expr);
scan->type = ST_GOTO;
scan->label = label;
}
if (scan->next && scan->next->type == ST_RETURN && !scan->next->next) {
CError_ASSERT(2334, !scan->next->expr);
scan->next = NULL;
break;
}
}
scan = stmt;
if (flag29) {
label2 = newlabel();
scan = CFunc_InsertStatement(ST_IFNGOTO, scan);
scan->expr = CABI_MakeThisExpr(NULL, 0);
scan->label = label2;
}
if (flag25 && tclass->vtable && tclass->vtable->object && tclass->vtable->owner == tclass) {
cabi_pathroot.next = NULL;
cabi_pathroot.type = TYPE(tclass);
cabi_pathcur = &cabi_pathroot;
trans_vtboffsets = NULL;
scan = CABI_InitVTablePtrs(scan, tclass->vtable->object, tclass, tclass, 0, 0);
}
if (!tclass->sominfo && (tclass->flags & CLASS_FLAGS_8000))
CABI_InitVBaseCtorOffsets(scan, tclass);
scan = stmt;
while (scan->next)
scan = scan->next;
scan = CFunc_InsertStatement(ST_LABEL, scan);
scan->label = label;
scan->dobjstack = NULL;
label->stmt = scan;
if (flag23 && !(tclass->flags & CLASS_HANDLEOBJECT))
scan = CABI_DestroyMembers(scan, tclass->ivars, tclass);
if (flag25 && tclass->bases)
scan = CABI_DestroyBases(scan, tclass->bases);
if (flag24 && (tclass->flags & CLASS_HAS_VBASES)) {
label3 = newlabel();
scan = CFunc_InsertStatement(ST_IFNGOTO, scan);
scan->expr = CABI_MakeVArgExpr();
scan->label = label3;
scan = CABI_DestroyVBases(scan, tclass->vbases);
scan = CFunc_InsertStatement(ST_LABEL, scan);
scan->label = label3;
label3->stmt = scan;
}
if (flag29) {
scan = CFunc_InsertStatement(ST_IFGOTO, scan);
scan->expr = CExpr_New_ELESSEQU_Node(CABI_MakeVArgExpr(), intconstnode(TYPE(&stsignedshort), 0));
scan->label = label2;
scan = CFunc_InsertStatement(ST_EXPRESSION, scan);
dealloc = CParser_FindDeallocationObject(TYPE(tclass), NULL, 0, 0, &deallocFlag);
if (deallocFlag) {
scan->expr = funccallexpr(
dealloc,
CABI_MakeThisExpr(NULL, 0),
intconstnode(CABI_GetSizeTType(), tclass->size),
NULL,
NULL);
} else {
scan->expr = funccallexpr(dealloc, CABI_MakeThisExpr(NULL, 0), NULL, NULL, NULL);
}
scan = CFunc_InsertStatement(ST_LABEL, scan);
scan->label = label2;
label2->stmt = scan;
}
scan = CFunc_InsertStatement(ST_RETURN, scan);
if (tclass->sominfo)
scan->expr = NULL;
else
scan->expr = CABI_MakeThisExpr(NULL, 0);
}
void CABI_MakeDefaultDestructor(TypeClass *tclass, Object *func) {
Boolean saveDebugInfo;
CScopeSave savedScope;
Statement firstStmt;
Statement returnStmt;
if (anyerrors || func->access == ACCESSNONE)
return;
CABI_ApplyClassFlags(func, tclass->eflags, 0);
CScope_SetFunctionScope(func, &savedScope);
CFunc_FuncGenSetup(&firstStmt, func);
saveDebugInfo = copts.filesyminfo;
copts.filesyminfo = 0;
CFunc_SetupNewFuncArgs(func, TYPE_FUNC(func->type)->args);
firstStmt.next = &returnStmt;
memclrw(&returnStmt, sizeof(Statement));
returnStmt.type = ST_RETURN;
CFunc_CodeCleanup(&firstStmt);
CABI_TransDestructor(func, func, &firstStmt, tclass, CABIDestroy0);
CFunc_Gen(&firstStmt, func, 0);
CScope_RestoreScope(&savedScope);
copts.filesyminfo = saveDebugInfo;
}
static void CABI_CreateLayeredDestructor(TypeClass *tclass, Object *obj1, Object *func, CABIDestroyMode mode) {
Boolean saveDebugInfo;
CScopeSave savedScope;
Statement firstStmt;
Statement returnStmt;
CError_FATAL(2524);
CScope_SetFunctionScope(func, &savedScope);
CFunc_FuncGenSetup(&firstStmt, func);
saveDebugInfo = copts.filesyminfo;
copts.filesyminfo = 0;
CFunc_SetupNewFuncArgs(func, TYPE_FUNC(func->type)->args);
firstStmt.next = &returnStmt;
memclrw(&returnStmt, sizeof(Statement));
returnStmt.type = ST_RETURN;
CFunc_CodeCleanup(&firstStmt);
CABI_TransDestructor(obj1, func, &firstStmt, tclass, mode);
CFunc_Gen(&firstStmt, func, 0);
CScope_RestoreScope(&savedScope);
copts.filesyminfo = saveDebugInfo;
}
void CABI_MakeLayeredDestructor(TypeClass *tclass, Object *func) {
Object *dtor;
CABIDestroyMode mode;
CError_FATAL(2557);
if (anyerrors || func->access == ACCESSNONE)
return;
if ((dtor = CClass_Destructor(tclass))) {
if (CABI_GetDestructorObject(dtor, CABIDestroy0) == func)
mode = CABIDestroy0;
else if (CABI_GetDestructorObject(dtor, CABIDestroy2) == func)
mode = CABIDestroy2;
else if (CABI_GetDestructorObject(dtor, CABIDestroy3) == func)
mode = CABIDestroy3;
else if (CABI_GetDestructorObject(dtor, CABIDestroy1) == func)
mode = CABIDestroy1;
else
CError_FATAL(2567);
}
CABI_CreateLayeredDestructor(tclass, dtor, func, mode);
}
Object *CABI_GetDestructorObject(Object *obj, CABIDestroyMode mode) {
return obj;
}
static void CABI_AddLayeredDestructor(TypeClass *tclass, Object *dtor, HashNameNode *name, Boolean is_virtual) {
Object *func;
CError_FATAL(2667);
func = CParser_NewFunctionObject(NULL);
func->nspace = dtor->nspace;
func->name = name;
func->type = TYPE(CDecl_MakeDefaultDtorType(tclass, is_virtual));
func->qual = Q_20000 | Q_MANGLE_NAME;
func->qual |= Q_INLINE;
CABI_ApplyClassFlags(func, tclass->eflags, 1);
CError_ASSERT(2678, IS_TYPE_FUNC(func->type));
TYPE_FUNC(func->type)->flags |= FUNC_AUTO_GENERATED;
if (dtor->datatype == DVFUNC) {
func->datatype = DVFUNC;
CMangler_GetLinkName(func);
func->datatype = DFUNC;
}
CScope_AddObject(func->nspace, func->name, OBJ_BASE(func));
}
void CABI_AddLayeredDestructors(TypeClass *tclass) {
Object *dtor;
CError_FATAL(2707);
if ((dtor = CClass_Destructor(tclass))) {
CABI_AddLayeredDestructor(tclass, dtor, CMangler_DeleteDtorName(), 1);
CABI_AddLayeredDestructor(tclass, dtor, CMangler_SDeleteDtorName(), 1);
if (tclass->vbases)
CABI_AddLayeredDestructor(tclass, dtor, CMangler_VBaseDtorName(), 0);
}
}
ENode *CABI_DestroyObject(Object *dtor, ENode *objexpr, CABIDestroyMode mode, Boolean flag1, Boolean flag2) {
ENode *expr;
short arg;
ENodeList *list;
switch (mode) {
case CABIDestroy2:
case CABIDestroy3:
if (flag2)
arg = 1;
else
arg = -1;
break;
case CABIDestroy1:
arg = -1;
break;
case CABIDestroy0:
arg = 0;
break;
default:
CError_FATAL(2786);
}
expr = lalloc(sizeof(ENode));
expr->type = EFUNCCALL;
expr->cost = 200;
expr->flags = 0;
expr->rtype = &stvoid;
expr->data.funccall.funcref = create_objectrefnode(dtor);
if (flag1)
expr->data.funccall.funcref->flags = expr->data.funccall.funcref->flags | ENODE_FLAG_80;
expr->data.funccall.functype = TYPE_FUNC(dtor->type);
dtor->flags = dtor->flags | OBJECT_USED;
list = lalloc(sizeof(ENodeList));
list->node = objexpr;
expr->data.funccall.args = list;
list->next = lalloc(sizeof(ENodeList));
list = list->next;
list->next = NULL;
list->node = intconstnode(TYPE(&stsignedshort), arg);
return expr;
}