Files
swift-mirror/lib/SILOptimizer/Analysis/DestructorAnalysis.cpp
Arnold Schwaighofer 7a251af60c AccessEnforcement: Fix analysis to include mayReleases as potentially
executing unknown code

This means we have to claw back some performance by recognizing harmless
releases.

Such as releases on types we known don't call a deinit with unknown
side-effects.

rdar://143497196
rdar://143141695
2025-02-07 15:10:13 -08:00

136 lines
4.3 KiB
C++

//===----------------------------------------------------------------------===//
//
// 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 "swift/SILOptimizer/Analysis/DestructorAnalysis.h"
#include "swift/SIL/SILInstruction.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/Decl.h"
#include "swift/AST/Module.h"
#include "swift/AST/LazyResolver.h"
#include "swift/SIL/SILModule.h"
#include "llvm/Support/Debug.h"
#define DEBUG_TYPE "destructor-analysis"
using namespace swift;
/// A type T's destructor does not store to memory if the type
/// * is a trivial builtin type like builtin float or int types
/// * is a value type with stored properties that are safe or
/// * is a value type that implements the _DestructorSafeContainer protocol and
/// whose type parameters are safe types T1...Tn.
bool DestructorAnalysis::mayStoreToMemoryOnDestruction(SILType T) {
bool IsSafe = isSafeType(T.getASTType());
LLVM_DEBUG(llvm::dbgs() << " DestructorAnalysis::"
"mayStoreToMemoryOnDestruction is"
<< (IsSafe ? " false: " : " true: "));
LLVM_DEBUG(T.getASTType()->print(llvm::errs()));
LLVM_DEBUG(llvm::errs() << "\n");
return !IsSafe;
}
bool DestructorAnalysis::cacheResult(CanType Type, bool Result) {
Cached[Type] = Result;
return Result;
}
static bool isKnownSafeStdlibContainerType(CanType Ty) {
return Ty->isArray() ||
Ty->is_ArrayBuffer() ||
Ty->is_ContiguousArrayBuffer() ||
Ty->isDictionary();
}
bool DestructorAnalysis::isSafeType(CanType Ty) {
// Don't visit types twice.
auto CachedRes = Cached.find(Ty);
if (CachedRes != Cached.end()) {
return CachedRes->second;
}
// Before we recurse mark the type as safe i.e if we see it in a recursive
// position it is safe in the absence of another fact that proves otherwise.
// We will reset this value to the correct value once we return from the
// recursion below.
cacheResult(Ty, true);
// Trivial value types.
if (Ty->is<BuiltinIntegerType>())
return cacheResult(Ty, true);
if (Ty->is<BuiltinFloatType>())
return cacheResult(Ty, true);
// A struct is safe if
// * either it implements the _DestructorSafeContainer protocol and
// all the type parameters are safe types.
// * or all stored properties are safe types.
if (auto *Struct = Ty->getStructOrBoundGenericStruct()) {
if ((implementsDestructorSafeContainerProtocol(Struct) ||
isKnownSafeStdlibContainerType(Ty)) &&
areTypeParametersSafe(Ty))
return cacheResult(Ty, true);
// Check the stored properties.
for (auto SP : Struct->getStoredProperties()) {
if (!isSafeType(SP->getInterfaceType()->getCanonicalType()))
return cacheResult(Ty, false);
}
return cacheResult(Ty, true);
}
// A tuple type is safe if its elements are safe.
if (auto Tuple = dyn_cast<TupleType>(Ty)) {
for (auto &Elt : Tuple->getElements())
if (!isSafeType(Elt.getType()->getCanonicalType()))
return cacheResult(Ty, false);
return cacheResult(Ty, true);
}
// TODO: enum types.
return cacheResult(Ty, false);
}
bool DestructorAnalysis::implementsDestructorSafeContainerProtocol(
NominalTypeDecl *NomDecl) {
ProtocolDecl *DestructorSafeContainer =
getASTContext().getProtocol(KnownProtocolKind::DestructorSafeContainer);
for (auto Proto : NomDecl->getAllProtocols())
if (Proto == DestructorSafeContainer)
return true;
return false;
}
bool DestructorAnalysis::areTypeParametersSafe(CanType Ty) {
auto BGT = dyn_cast<BoundGenericType>(Ty);
if (!BGT)
return false;
// Make sure all type parameters are safe.
for (auto TP : BGT->getGenericArgs()) {
if (!isSafeType(TP->getCanonicalType()))
return false;
}
return true;
}
ASTContext &DestructorAnalysis::getASTContext() {
return Mod->getASTContext();
}
SILAnalysis *swift::createDestructorAnalysis(SILModule *M) {
return new DestructorAnalysis(M);
}