-
Notifications
You must be signed in to change notification settings - Fork 1.5k
/
type_test_registry.dart
200 lines (173 loc) · 6.83 KB
/
type_test_registry.dart
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library dart2js.js_emitter.type_test_registry;
import '../common.dart';
import '../common_elements.dart';
import '../elements/elements.dart' show MethodElement;
import '../elements/entities.dart';
import '../elements/types.dart' show DartType;
import '../elements/types.dart';
import '../js_backend/runtime_types.dart'
show
RuntimeTypesChecks,
RuntimeTypesChecksBuilder,
RuntimeTypesSubstitutions,
TypeChecks;
import '../js_backend/mirrors_data.dart';
import '../universe/world_builder.dart';
import '../world.dart' show ClosedWorld;
class TypeTestRegistry {
final ElementEnvironment _elementEnvironment;
/**
* Raw ClassElement symbols occurring in is-checks and type assertions. If the
* program contains parameterized checks `x is Set<int>` and
* `x is Set<String>` then the ClassElement `Set` will occur once in
* [checkedClasses].
*/
Set<ClassEntity> checkedClasses;
/**
* The set of function types that checked, both explicitly through tests of
* typedefs and implicitly through type annotations in checked mode.
*/
Set<FunctionType> checkedFunctionTypes;
/// After [computeNeededClasses] this set only contains classes that are only
/// used for RTI.
Set<ClassEntity> _rtiNeededClasses;
Iterable<ClassEntity> cachedClassesUsingTypeVariableTests;
Iterable<ClassEntity> get classesUsingTypeVariableTests {
if (cachedClassesUsingTypeVariableTests == null) {
cachedClassesUsingTypeVariableTests = _codegenWorldBuilder.isChecks
.where((DartType t) =>
t is TypeVariableType && t.element.typeDeclaration is ClassEntity)
.map<ClassEntity>((DartType _v) {
TypeVariableType v = _v;
return v.element.typeDeclaration;
}).toList();
}
return cachedClassesUsingTypeVariableTests;
}
final CodegenWorldBuilder _codegenWorldBuilder;
final ClosedWorld _closedWorld;
RuntimeTypesChecks _rtiChecks;
TypeTestRegistry(
this._codegenWorldBuilder, this._closedWorld, this._elementEnvironment);
RuntimeTypesChecks get rtiChecks {
assert(
_rtiChecks != null,
failedAt(NO_LOCATION_SPANNABLE,
"RuntimeTypesChecks has not been computed yet."));
return _rtiChecks;
}
Iterable<ClassEntity> get rtiNeededClasses {
assert(
_rtiNeededClasses != null,
failedAt(NO_LOCATION_SPANNABLE,
"rtiNeededClasses has not been computed yet."));
return _rtiNeededClasses;
}
/**
* Returns the classes with constructors used as a 'holder' in
* [emitRuntimeTypeSupport].
* TODO(9556): Some cases will go away when the class objects are created as
* complete. Not all classes will go away while constructors are referenced
* from type substitutions.
*/
Set<ClassEntity> computeClassesModifiedByEmitRuntimeTypeSupport() {
TypeChecks typeChecks = rtiChecks.requiredChecks;
Set<ClassEntity> result = new Set<ClassEntity>();
for (ClassEntity cls in typeChecks.classes) {
if (typeChecks[cls].isNotEmpty) result.add(cls);
}
return result;
}
void computeRtiNeededClasses(RuntimeTypesSubstitutions rtiSubstitutions,
MirrorsData mirrorsData, Iterable<MemberEntity> liveMembers) {
_rtiNeededClasses = new Set<ClassEntity>();
void addClassWithSuperclasses(ClassEntity cls) {
_rtiNeededClasses.add(cls);
for (ClassEntity superclass = _elementEnvironment.getSuperClass(cls);
superclass != null;
superclass = _elementEnvironment.getSuperClass(superclass)) {
_rtiNeededClasses.add(superclass);
}
}
void addClassesWithSuperclasses(Iterable<ClassEntity> classes) {
for (ClassEntity cls in classes) {
addClassWithSuperclasses(cls);
}
}
// 1. Add classes that are referenced by type arguments or substitutions in
// argument checks.
// TODO(karlklose): merge this case with 2 when unifying argument and
// object checks.
rtiChecks
.getRequiredArgumentClasses()
.forEach((e) => addClassWithSuperclasses(e));
// 2. Add classes that are referenced by substitutions in object checks and
// their superclasses.
TypeChecks requiredChecks =
rtiSubstitutions.computeChecks(rtiNeededClasses, checkedClasses);
Set<ClassEntity> classesUsedInSubstitutions =
rtiSubstitutions.getClassesUsedInSubstitutions(requiredChecks);
addClassesWithSuperclasses(classesUsedInSubstitutions);
// 3. Add classes that contain checked generic function types. These are
// needed to store the signature encoding.
for (FunctionType type in checkedFunctionTypes) {
ClassEntity contextClass = DartTypes.getClassContext(type);
if (contextClass != null) {
_rtiNeededClasses.add(contextClass);
}
}
bool canTearOff(MemberEntity function) {
if (!function.isFunction ||
function.isConstructor ||
function.isGetter ||
function.isSetter) {
return false;
} else if (function.isInstanceMember) {
if (!function.enclosingClass.isClosure) {
return _codegenWorldBuilder.hasInvokedGetter(function, _closedWorld);
}
}
return false;
}
bool canBeReflectedAsFunction(MemberEntity element) {
return !element.isField;
}
bool canBeReified(MemberEntity element) {
return (canTearOff(element) ||
mirrorsData.isMemberAccessibleByReflection(element));
}
// Find all types referenced from the types of elements that can be
// reflected on 'as functions'.
liveMembers.where((MemberEntity element) {
return canBeReflectedAsFunction(element) && canBeReified(element);
}).forEach((_function) {
// TODO(redemption): Support entities.
MethodElement function = _function;
FunctionType type = function.type;
for (ClassEntity cls in _rtiChecks.getReferencedClasses(type)) {
while (cls != null) {
_rtiNeededClasses.add(cls);
cls = _elementEnvironment.getSuperClass(cls);
}
}
});
}
void computeRequiredTypeChecks(RuntimeTypesChecksBuilder rtiChecksBuilder) {
assert(checkedClasses == null && checkedFunctionTypes == null);
rtiChecksBuilder.registerImplicitChecks(
_codegenWorldBuilder, classesUsingTypeVariableTests);
_rtiChecks = rtiChecksBuilder.computeRequiredChecks(_codegenWorldBuilder);
checkedClasses = new Set<ClassEntity>();
checkedFunctionTypes = new Set<FunctionType>();
_codegenWorldBuilder.isChecks.forEach((DartType t) {
if (t is InterfaceType) {
checkedClasses.add(t.element);
} else if (t is FunctionType) {
checkedFunctionTypes.add(t);
}
});
}
}