blob: 0d373a1c10c943790002136eb719b695c955f4d8 [file] [log] [blame]
//===--- 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 "Scope.h"
#include "swift/AST/AST.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<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());
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;
SubstitutionList 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 = selfValue;
}
{
Scope S(Cleanups, cleanupLoc);
ManagedValue borrowedResultSelfValue =
emitManagedBeginBorrow(cleanupLoc, resultSelfValue);
SILValue borrowedValue = borrowedResultSelfValue.getUnmanagedValue();
if (classTy != borrowedValue->getType()) {
borrowedValue =
B.createUncheckedRefCast(cleanupLoc, borrowedValue, classTy);
}
// Release our members.
emitClassMemberDestruction(borrowedValue, cd, cleanupLoc);
}
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();
ManagedValue dtorValue;
SILType dtorTy;
SubstitutionList subs = classTy.gatherAllSubstitutions(SGM.M);
std::tie(dtorValue, dtorTy, subs)
= emitSiblingMethodRef(loc, initialSelfValue, dtorConstant, subs);
// Call the destroying destructor.
SILValue selfForDealloc;
{
FullExpr CleanupScope(Cleanups, CleanupLocation::get(loc));
ManagedValue borrowedSelf = emitManagedBeginBorrow(loc, initialSelfValue);
SILType objectPtrTy = SILType::getNativeObjectType(F.getASTContext());
selfForDealloc = B.createApply(loc, dtorValue.forward(*this),
dtorTy, objectPtrTy, subs, 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 artifical 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);
// Return.
B.createReturn(loc, emitEmptyTuple(loc));
}
void SILGenFunction::emitIVarDestroyer(SILDeclRef ivarDestroyer) {
auto cd = cast<ClassDecl>(ivarDestroyer.getDecl());
RegularLocation loc(cd);
loc.markAutoGenerated();
SILValue selfValue = emitSelfDecl(cd->getDestructor()->getImplicitSelfDecl());
auto cleanupLoc = CleanupLocation::get(loc);
prepareEpilog(TupleType::getEmpty(getASTContext()), false, cleanupLoc);
emitClassMemberDestruction(selfValue, cd, cleanupLoc);
B.createReturn(loc, emitEmptyTuple(loc));
emitEpilog(loc);
}
void SILGenFunction::emitClassMemberDestruction(SILValue selfValue,
ClassDecl *cd,
CleanupLocation cleanupLoc) {
for (VarDecl *vd : cd->getStoredProperties()) {
const TypeLowering &ti = getTypeLowering(vd->getType());
if (!ti.isTrivial()) {
SILValue addr = B.createRefElementAddr(cleanupLoc, selfValue, vd,
ti.getLoweredType().getAddressType());
B.createDestroyAddr(cleanupLoc, addr);
}
}
}
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);
SubstitutionList 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));
}