// Analyzing the body of this class destructor is valid because the object is // dead. This means that the object is never passed to objc_setAssociatedObject, // so its destructor cannot be extended at runtime. static SILFunction *getDestructor(AllocRefInst *ARI) { // We only support classes. ClassDecl *ClsDecl = ARI->getType().getClassOrBoundGenericClass(); if (!ClsDecl) return nullptr; // Look up the destructor of ClsDecl. DestructorDecl *Destructor = ClsDecl->getDestructor(); assert(Destructor && "getDestructor() should never return a nullptr."); // Find the destructor name via SILDeclRef. // FIXME: When destructors get moved into vtables, update this to use the // vtable for the class. SILDeclRef Ref(Destructor); SILFunction *Fn = ARI->getModule().lookUpFunction(Ref); if (!Fn || Fn->empty()) { DEBUG(llvm::dbgs() << " Could not find destructor.\n"); return nullptr; } DEBUG(llvm::dbgs() << " Found destructor!\n"); // If the destructor has an objc_method calling convention, we cannot // analyze it since it could be swapped out from under us at runtime. if (Fn->getRepresentation() == SILFunctionTypeRepresentation::ObjCMethod) { DEBUG(llvm::dbgs() << " Found objective-c destructor. Can't " "analyze!\n"); return nullptr; } return Fn; }
void SILGenFunction::emitDestroyingDestructor(DestructorDecl *dd) { MagicFunctionName = DeclName(SGM.M.getASTContext().getIdentifier("deinit")); RegularLocation Loc(dd); if (dd->isImplicit()) Loc.markAutoGenerated(); auto cd = cast<ClassDecl>(dd->getDeclContext()); SILValue selfValue = emitSelfDecl(dd->getImplicitSelfDecl()); // Create a basic block to jump to for the implicit destruction behavior // of releasing the elements and calling the superclass destructor. // We won't actually emit the block until we finish with the destructor body. prepareEpilog(Type(), false, CleanupLocation::get(Loc)); emitProfilerIncrement(dd->getBody()); // Emit the destructor body. emitStmt(dd->getBody()); Optional<SILValue> maybeReturnValue; SILLocation returnLoc(Loc); std::tie(maybeReturnValue, returnLoc) = emitEpilogBB(Loc); if (!maybeReturnValue) return; auto cleanupLoc = CleanupLocation::get(Loc); // If we have a superclass, invoke its destructor. SILValue resultSelfValue; SILType objectPtrTy = SILType::getNativeObjectType(F.getASTContext()); if (cd->hasSuperclass()) { Type superclassTy = ArchetypeBuilder::mapTypeIntoContext(dd, cd->getSuperclass()); ClassDecl *superclass = superclassTy->getClassOrBoundGenericClass(); auto superclassDtorDecl = superclass->getDestructor(); SILDeclRef dtorConstant = SILDeclRef(superclassDtorDecl, SILDeclRef::Kind::Destroyer); SILType baseSILTy = getLoweredLoadableType(superclassTy); SILValue baseSelf = B.createUpcast(cleanupLoc, selfValue, baseSILTy); ManagedValue dtorValue; SILType dtorTy; ArrayRef<Substitution> subs = superclassTy->gatherAllSubstitutions(SGM.M.getSwiftModule(), nullptr); std::tie(dtorValue, dtorTy, subs) = emitSiblingMethodRef(cleanupLoc, baseSelf, dtorConstant, subs); resultSelfValue = B.createApply(cleanupLoc, dtorValue.forward(*this), dtorTy, objectPtrTy, subs, baseSelf); } else { resultSelfValue = B.createUncheckedRefCast(cleanupLoc, selfValue, objectPtrTy); } // Release our members. emitClassMemberDestruction(selfValue, cd, cleanupLoc); B.createReturn(returnLoc, resultSelfValue); }
void SILGenFunction::emitObjCDestructor(SILDeclRef dtor) { auto dd = cast<DestructorDecl>(dtor.getDecl()); auto cd = cast<ClassDecl>(dd->getDeclContext()); MagicFunctionName = DeclName(SGM.M.getASTContext().getIdentifier("deinit")); RegularLocation loc(dd); if (dd->isImplicit()) loc.markAutoGenerated(); SILValue selfValue = emitSelfDecl(dd->getImplicitSelfDecl()); // Create a basic block to jump to for the implicit destruction behavior // of releasing the elements and calling the superclass destructor. // We won't actually emit the block until we finish with the destructor body. prepareEpilog(Type(), false, CleanupLocation::get(loc)); // Emit the destructor body. emitStmt(dd->getBody()); Optional<SILValue> maybeReturnValue; SILLocation returnLoc(loc); std::tie(maybeReturnValue, returnLoc) = emitEpilogBB(loc); if (!maybeReturnValue) return; auto cleanupLoc = CleanupLocation::get(loc); // Note: the ivar destroyer is responsible for destroying the // instance variables before the object is actually deallocated. // Form a reference to the superclass -dealloc. Type superclassTy = dd->mapTypeIntoContext(cd->getSuperclass()); assert(superclassTy && "Emitting Objective-C -dealloc without superclass?"); ClassDecl *superclass = superclassTy->getClassOrBoundGenericClass(); auto superclassDtorDecl = superclass->getDestructor(); SILDeclRef superclassDtor(superclassDtorDecl, SILDeclRef::Kind::Deallocator, SILDeclRef::ConstructAtBestResilienceExpansion, SILDeclRef::ConstructAtNaturalUncurryLevel, /*isForeign=*/true); auto superclassDtorType = SGM.getConstantType(superclassDtor); SILValue superclassDtorValue = B.createSuperMethod( cleanupLoc, selfValue, superclassDtor, superclassDtorType); // Call the superclass's -dealloc. SILType superclassSILTy = getLoweredLoadableType(superclassTy); SILValue superSelf = B.createUpcast(cleanupLoc, selfValue, superclassSILTy); ArrayRef<Substitution> subs = superclassTy->gatherAllSubstitutions(SGM.M.getSwiftModule(), nullptr); auto substDtorType = superclassDtorType.castTo<SILFunctionType>() ->substGenericArgs(SGM.M, subs); SILFunctionConventions dtorConv(substDtorType, SGM.M); B.createApply(cleanupLoc, superclassDtorValue, SILType::getPrimitiveObjectType(substDtorType), dtorConv.getSILResultType(), subs, superSelf); // Return. B.createReturn(returnLoc, emitEmptyTuple(cleanupLoc)); }
void SILGenFunction::emitObjCDestructor(SILDeclRef dtor) { auto dd = cast<DestructorDecl>(dtor.getDecl()); auto cd = cast<ClassDecl>(dd->getDeclContext()); MagicFunctionName = DeclName(SGM.M.getASTContext().getIdentifier("deinit")); RegularLocation loc(dd); if (dd->isImplicit()) loc.markAutoGenerated(); SILValue selfValue = emitSelfDecl(dd->getImplicitSelfDecl()); // Create a basic block to jump to for the implicit destruction behavior // of releasing the elements and calling the superclass destructor. // We won't actually emit the block until we finish with the destructor body. prepareEpilog(Type(), false, CleanupLocation::get(loc)); emitProfilerIncrement(dd->getBody()); // Emit the destructor body. emitStmt(dd->getBody()); Optional<SILValue> maybeReturnValue; SILLocation returnLoc(loc); std::tie(maybeReturnValue, returnLoc) = emitEpilogBB(loc); if (!maybeReturnValue) return; auto cleanupLoc = CleanupLocation::get(loc); // Note: the ivar destroyer is responsible for destroying the // instance variables before the object is actually deallocated. // Form a reference to the superclass -dealloc. Type superclassTy = dd->mapTypeIntoContext(cd->getSuperclass()); assert(superclassTy && "Emitting Objective-C -dealloc without superclass?"); ClassDecl *superclass = superclassTy->getClassOrBoundGenericClass(); auto superclassDtorDecl = superclass->getDestructor(); auto superclassDtor = SILDeclRef(superclassDtorDecl, SILDeclRef::Kind::Deallocator) .asForeign(); auto superclassDtorType = SGM.Types.getConstantType(superclassDtor); SILValue superclassDtorValue = B.createObjCSuperMethod( cleanupLoc, selfValue, superclassDtor, superclassDtorType); // Call the superclass's -dealloc. SILType superclassSILTy = getLoweredLoadableType(superclassTy); SILValue superSelf = B.createUpcast(cleanupLoc, selfValue, superclassSILTy); assert(superSelf.getOwnershipKind() == ValueOwnershipKind::Owned); auto subMap = superclassTy->getContextSubstitutionMap(SGM.M.getSwiftModule(), superclass); auto substDtorType = superclassDtorType.substGenericArgs(SGM.M, subMap); CanSILFunctionType substFnType = substDtorType.castTo<SILFunctionType>(); SILFunctionConventions dtorConv(substFnType, SGM.M); assert(substFnType->getSelfParameter().getConvention() == ParameterConvention::Direct_Unowned && "Objective C deinitializing destructor takes self as unowned"); B.createApply(cleanupLoc, superclassDtorValue, substDtorType, dtorConv.getSILResultType(), subMap, superSelf); // We know that the givne value came in at +1, but we pass the relevant value // as unowned to the destructor. Create a fake balance for the verifier to be // happy. B.createEndLifetime(cleanupLoc, superSelf); // Return. B.createReturn(returnLoc, emitEmptyTuple(cleanupLoc)); }