-
Notifications
You must be signed in to change notification settings - Fork 10.5k
/
Copy pathDestructorAnalysis.cpp
135 lines (113 loc) · 4.28 KB
/
DestructorAnalysis.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
//===----------------------------------------------------------------------===//
//
// 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);
}