diff options
Diffstat (limited to 'compiler_and_linker/FrontEnd/C/CABI.c')
-rw-r--r-- | compiler_and_linker/FrontEnd/C/CABI.c | 2033 |
1 files changed, 2033 insertions, 0 deletions
diff --git a/compiler_and_linker/FrontEnd/C/CABI.c b/compiler_and_linker/FrontEnd/C/CABI.c new file mode 100644 index 0000000..2a88de1 --- /dev/null +++ b/compiler_and_linker/FrontEnd/C/CABI.c @@ -0,0 +1,2033 @@ +#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; +} |