mirror of https://git.wuffs.org/MWCC
2029 lines
63 KiB
C
2029 lines
63 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->unkB;
|
|
a = tbitfield->unkA;
|
|
tbitfield->unkA = (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(DeclE *decle, 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_FLAGS_1000)) {
|
|
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(DeclE *decle, 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(DeclE *decle, 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_1)
|
|
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_1) {
|
|
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_1)
|
|
CMach_StructLayoutInitOffset(initialSize);
|
|
|
|
unionStart = CMach_StructLayoutGetOffset(ivar->type, ivar->qual);
|
|
unionClass = TYPE_CLASS(ivar->type);
|
|
inAnonUnion = 1;
|
|
|
|
if (tclass->mode == CLASS_MODE_1) {
|
|
SInt32 tmp = CMach_StructLayoutGetCurSize();
|
|
if (tmp > maxSize)
|
|
maxSize = tmp;
|
|
}
|
|
|
|
removeNoNameIvars = 1;
|
|
}
|
|
|
|
if (decle->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_1)
|
|
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(DeclE *decle, 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 |= OBJECT_FLAGS_10;
|
|
if (flags & CLASS_EFLAGS_IMPORT)
|
|
obj->flags |= OBJECT_FLAGS_20;
|
|
if (flags & CLASS_EFLAGS_EXPORT)
|
|
obj->flags |= OBJECT_FLAGS_40;
|
|
}
|
|
|
|
static void CABI_AllocateVTable(DeclE *decle, TypeClass *tclass) {
|
|
SInt32 size;
|
|
ObjBase *objbase;
|
|
Object *obj;
|
|
ObjMemberVar *ivar;
|
|
ClassList *base;
|
|
VClassList *vbase;
|
|
int i;
|
|
|
|
size = 0;
|
|
|
|
if (!tclass->vtable) {
|
|
CABI_AddVTable(tclass);
|
|
decle->xA = decle->x8 - 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);
|
|
decle->vtable_ivar = ivar;
|
|
|
|
for (i = decle->xA; ; i--) {
|
|
if (i < 0) {
|
|
ivar->next = tclass->ivars;
|
|
tclass->ivars = ivar;
|
|
break;
|
|
}
|
|
|
|
CError_ASSERT(666, decle->objlist[i]);
|
|
|
|
if (decle->objlist[i]->otype == OT_MEMBERVAR) {
|
|
ivar->next = OBJ_MEMBER_VAR(decle->objlist[i])->next;
|
|
OBJ_MEMBER_VAR(decle->objlist[i])->next = ivar;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (tclass->flags & (CLASS_FLAGS_10 | CLASS_FLAGS_2000))
|
|
size = void_ptr.size;
|
|
else
|
|
size = 8;
|
|
} else {
|
|
decle->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 < decle->x8; i++) {
|
|
CError_ASSERT(714, objbase = decle->objlist[i]);
|
|
|
|
if (objbase->otype == OT_OBJECT && OBJECT(objbase)->datatype == DVFUNC) {
|
|
TypeMethod *tmethod = TYPE_METHOD(OBJECT(objbase)->type);
|
|
Object *baseobj = CABI_FindZeroVirtualBaseMember(tclass, OBJECT(objbase));
|
|
|
|
if (baseobj) {
|
|
tmethod->x1E = TYPE_METHOD(baseobj->type)->x1E;
|
|
} else {
|
|
tmethod->x1E = 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(DeclE *decle, TypeClass *tclass) {
|
|
char saveAlignMode = copts.align_mode;
|
|
|
|
tclass->size = 0;
|
|
if (!tclass->sominfo) {
|
|
if (tclass->bases)
|
|
CABI_AllocateBases(decle, tclass);
|
|
if (tclass->flags & CLASS_FLAGS_20)
|
|
CABI_AllocateVirtualBasePointers(decle, tclass);
|
|
if (decle->xC)
|
|
CABI_AllocateVTable(decle, tclass);
|
|
CABI_AllocateMembers(decle, tclass);
|
|
if (tclass->flags & CLASS_FLAGS_20)
|
|
CABI_AllocateVirtualBases(decle, tclass);
|
|
} else {
|
|
copts.align_mode = AlignMode2_PPC;
|
|
CABI_AllocateMembers(decle, tclass);
|
|
}
|
|
|
|
tclass->align = CMach_GetClassAlign(tclass);
|
|
if (tclass->size == 0) {
|
|
tclass->size = 1;
|
|
tclass->flags |= CLASS_FLAGS_1000;
|
|
} else {
|
|
tclass->size += CABI_StructSizeAlignValue(TYPE(tclass), tclass->size);
|
|
}
|
|
|
|
tclass->flags |= CLASS_FLAGS_2;
|
|
|
|
copts.align_mode = saveAlignMode;
|
|
}
|
|
|
|
void CABI_MakeDefaultArgConstructor(TypeClass *tclass, Object *func) {
|
|
DefArgCtorInfo *info;
|
|
Boolean saveDebugInfo;
|
|
ENodeList *copied;
|
|
FuncArg *args;
|
|
ENodeList *argexprs;
|
|
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.isGeneratingDebugInfo;
|
|
copts.isGeneratingDebugInfo = 0;
|
|
|
|
CFunc_SetupNewFuncArgs(func, TYPE_FUNC(func->type)->args);
|
|
|
|
if (tclass->flags & CLASS_FLAGS_20)
|
|
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_FLAGS_20) {
|
|
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.isGeneratingDebugInfo = 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_FLAGS_1)
|
|
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_FLAGS_20))
|
|
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.align_mode;
|
|
if (tclass->eflags & CLASS_EFLAGS_F0)
|
|
copts.align_mode = ((tclass->eflags & CLASS_EFLAGS_F0) >> 4) - 1;
|
|
size += CMach_MemberAlignValue(TYPE(&stunsignedlong), size);
|
|
copts.align_mode = 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;
|
|
CScopeParseResult pr;
|
|
|
|
if (!tclass->sominfo && (tclass->flags & CLASS_FLAGS_1)) {
|
|
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_FLAGS_20) {
|
|
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.isGeneratingDebugInfo;
|
|
copts.isGeneratingDebugInfo = 0;
|
|
|
|
CFunc_SetupNewFuncArgs(func, TYPE_FUNC(func->type)->args);
|
|
|
|
ctor_chain = NULL;
|
|
if (tclass->flags & CLASS_FLAGS_20)
|
|
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.isGeneratingDebugInfo = 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_FLAGS_1000) {
|
|
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; offset += type->size, i++) {
|
|
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.isGeneratingDebugInfo;
|
|
copts.isGeneratingDebugInfo = 0;
|
|
|
|
CFunc_SetupNewFuncArgs(func, TYPE_FUNC(func->type)->args);
|
|
|
|
ctor_chain = NULL;
|
|
if (tclass->flags & CLASS_FLAGS_20)
|
|
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.isGeneratingDebugInfo = 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.isGeneratingDebugInfo;
|
|
copts.isGeneratingDebugInfo = 0;
|
|
|
|
CFunc_SetupNewFuncArgs(func, TYPE_FUNC(func->type)->args);
|
|
|
|
stmt = curstmt;
|
|
|
|
if (tclass->mode == CLASS_MODE_1) {
|
|
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.isGeneratingDebugInfo = 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 |= 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;
|
|
|
|
for (base = bases, count = 0; base; base = base->next)
|
|
count++;
|
|
|
|
while (count > 0) {
|
|
base = bases;
|
|
for (i = 1; i < count; i++)
|
|
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_FLAGS_1))
|
|
scan = CABI_DestroyMembers(scan, tclass->ivars, tclass);
|
|
|
|
if (flag25 && tclass->bases)
|
|
scan = CABI_DestroyBases(scan, tclass->bases);
|
|
|
|
if (flag24 && (tclass->flags & CLASS_FLAGS_20)) {
|
|
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.isGeneratingDebugInfo;
|
|
copts.isGeneratingDebugInfo = 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.isGeneratingDebugInfo = 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.isGeneratingDebugInfo;
|
|
copts.isGeneratingDebugInfo = 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.isGeneratingDebugInfo = 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_80000;
|
|
func->qual |= Q_INLINE;
|
|
CABI_ApplyClassFlags(func, tclass->eflags, 1);
|
|
|
|
CError_ASSERT(2678, IS_TYPE_FUNC(func->type));
|
|
TYPE_FUNC(func->type)->flags |= FUNC_FLAGS_100;
|
|
|
|
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 |= ENODE_FLAG_80;
|
|
expr->data.funccall.functype = TYPE_FUNC(dtor->type);
|
|
dtor->flags |= OBJECT_FLAGS_UNUSED;
|
|
|
|
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;
|
|
}
|