//===--- SILGenDestructor.cpp - SILGen for destructors --------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// #include "SILGenFunction.h" #include "RValue.h" #include "ArgumentScope.h" #include "swift/AST/GenericSignature.h" #include "swift/AST/SubstitutionMap.h" #include "swift/SIL/TypeLowering.h" using namespace swift; using namespace Lowering; void SILGenFunction::emitDestroyingDestructor(DestructorDecl *dd) { MagicFunctionName = DeclName(SGM.M.getASTContext().getIdentifier("deinit")); RegularLocation Loc(dd); if (dd->isImplicit()) Loc.markAutoGenerated(); auto cd = cast(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(false, false, CleanupLocation::get(Loc)); emitProfilerIncrement(dd->getBody()); // Emit the destructor body. emitStmt(dd->getBody()); Optional 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()); SILType classTy = selfValue->getType(); if (cd->hasSuperclass()) { Type superclassTy = dd->mapTypeIntoContext(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; auto subMap = superclassTy->getContextSubstitutionMap(SGM.M.getSwiftModule(), superclass); std::tie(dtorValue, dtorTy) = emitSiblingMethodRef(cleanupLoc, baseSelf, dtorConstant, subMap); resultSelfValue = B.createApply(cleanupLoc, dtorValue.forward(*this), subMap, baseSelf); } else { resultSelfValue = selfValue; } ArgumentScope S(*this, Loc); ManagedValue borrowedValue = ManagedValue::forUnmanaged(resultSelfValue).borrow(*this, cleanupLoc); if (classTy != borrowedValue.getType()) { borrowedValue = B.createUncheckedRefCast(cleanupLoc, borrowedValue, classTy); } // Release our members. emitClassMemberDestruction(borrowedValue, cd, cleanupLoc); S.pop(); if (resultSelfValue->getType() != objectPtrTy) { resultSelfValue = B.createUncheckedRefCast(cleanupLoc, resultSelfValue, objectPtrTy); } if (resultSelfValue.getOwnershipKind() != ValueOwnershipKind::Owned) { assert(resultSelfValue.getOwnershipKind() == ValueOwnershipKind::Guaranteed); resultSelfValue = B.createUncheckedOwnershipConversion( cleanupLoc, resultSelfValue, ValueOwnershipKind::Owned); } B.createReturn(returnLoc, resultSelfValue); } void SILGenFunction::emitDeallocatingDestructor(DestructorDecl *dd) { MagicFunctionName = DeclName(SGM.M.getASTContext().getIdentifier("deinit")); // The deallocating destructor is always auto-generated. RegularLocation loc(dd); loc.markAutoGenerated(); // Emit the prolog. SILValue initialSelfValue = emitSelfDecl(dd->getImplicitSelfDecl()); // Form a reference to the destroying destructor. SILDeclRef dtorConstant(dd, SILDeclRef::Kind::Destroyer); auto classTy = initialSelfValue->getType(); auto classDecl = classTy.getASTType()->getAnyNominal(); ManagedValue dtorValue; SILType dtorTy; auto subMap = classTy.getASTType() ->getContextSubstitutionMap(SGM.M.getSwiftModule(), classDecl); std::tie(dtorValue, dtorTy) = emitSiblingMethodRef(loc, initialSelfValue, dtorConstant, subMap); // Call the destroying destructor. SILValue selfForDealloc; { FullExpr CleanupScope(Cleanups, CleanupLocation::get(loc)); ManagedValue borrowedSelf = emitManagedBeginBorrow(loc, initialSelfValue); selfForDealloc = B.createApply(loc, dtorValue.forward(*this), subMap, borrowedSelf.getUnmanagedValue()); } // Balance out the +1 from the self argument using end_lifetime. // // The issue here is that: // // 1. Self is passed into deallocating deinits at +1. // 2. Destroying deinits take in self as a +0 value that is then returned at // +1. // // This means that the lifetime of self can not be modeled statically in a // deallocating deinit without analyzing the body of the destroying deinit // (something that violates semantic sil). Thus we add an artificial destroy of // self before the actual destroy of self so that the verifier can understand // that self is being properly balanced. B.createEndLifetime(loc, initialSelfValue); // Deallocate the object. selfForDealloc = B.createUncheckedRefCast(loc, selfForDealloc, classTy); B.createDeallocRef(loc, selfForDealloc, false); emitProfilerIncrement(dd->getBody()); // Return. B.createReturn(loc, emitEmptyTuple(loc)); } void SILGenFunction::emitIVarDestroyer(SILDeclRef ivarDestroyer) { auto cd = cast(ivarDestroyer.getDecl()); RegularLocation loc(cd); loc.markAutoGenerated(); ManagedValue selfValue = ManagedValue::forUnmanaged( emitSelfDecl(cd->getDestructor()->getImplicitSelfDecl())); auto cleanupLoc = CleanupLocation::get(loc); prepareEpilog(false, false, cleanupLoc); { Scope S(*this, cleanupLoc); emitClassMemberDestruction(selfValue, cd, cleanupLoc); } B.createReturn(loc, emitEmptyTuple(loc)); emitEpilog(loc); } void SILGenFunction::emitClassMemberDestruction(ManagedValue selfValue, ClassDecl *cd, CleanupLocation cleanupLoc) { selfValue = selfValue.borrow(*this, cleanupLoc); for (VarDecl *vd : cd->getStoredProperties()) { const TypeLowering &ti = getTypeLowering(vd->getType()); if (!ti.isTrivial()) { SILValue addr = B.createRefElementAddr(cleanupLoc, selfValue.getValue(), vd, ti.getLoweredType().getAddressType()); addr = B.createBeginAccess( cleanupLoc, addr, SILAccessKind::Deinit, SILAccessEnforcement::Static, false /*noNestedConflict*/, false /*fromBuiltin*/); B.createDestroyAddr(cleanupLoc, addr); B.createEndAccess(cleanupLoc, addr, false /*is aborting*/); } } } void SILGenFunction::emitObjCDestructor(SILDeclRef dtor) { auto dd = cast(dtor.getDecl()); auto cd = cast(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(false, false, CleanupLocation::get(loc)); emitProfilerIncrement(dd->getBody()); // Emit the destructor body. emitStmt(dd->getBody()); Optional 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(getTypeExpansionContext(), 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); B.createApply(cleanupLoc, superclassDtorValue, 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)); }