#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; }