Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(97)

Side by Side Diff: pkg/compiler/lib/src/native/enqueue.dart

Issue 2779003002: Move collection of native classes from NativeEnqueuerBase to NativeResolutionEnqueuer (Closed)
Patch Set: Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | tests/compiler/dart2js/inference/inference_test_helper.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 import 'package:front_end/src/fasta/scanner.dart' show BeginGroupToken, Token;
6 import 'package:front_end/src/fasta/scanner.dart' as Tokens show EOF_TOKEN;
7
5 import '../common.dart'; 8 import '../common.dart';
6 import '../common/backend_api.dart' show ForeignResolver; 9 import '../common/backend_api.dart';
7 import '../common/resolution.dart' show Resolution; 10 import '../common/resolution.dart' show Resolution;
8 import '../compiler.dart' show Compiler; 11 import '../compiler.dart' show Compiler;
9 import '../constants/values.dart';
10 import '../common_elements.dart' show CommonElements; 12 import '../common_elements.dart' show CommonElements;
11 import '../elements/elements.dart'; 13 import '../elements/elements.dart';
12 import '../elements/entities.dart'; 14 import '../elements/entities.dart';
13 import '../elements/modelx.dart' show FunctionElementX;
14 import '../elements/resolution_types.dart'; 15 import '../elements/resolution_types.dart';
15 import '../elements/types.dart'; 16 import '../elements/types.dart';
16 import '../js_backend/backend_helpers.dart' show BackendHelpers; 17 import '../js_backend/backend_helpers.dart' show BackendHelpers;
17 import '../js_backend/backend_usage.dart' show BackendUsageBuilder; 18 import '../js_backend/backend_usage.dart' show BackendUsageBuilder;
18 import '../js_backend/js_backend.dart'; 19 import '../js_backend/js_backend.dart';
19 import '../js_backend/native_data.dart' show NativeBasicDataBuilder; 20 import '../js_backend/native_data.dart' show NativeBasicData, NativeData;
20 import '../js_emitter/js_emitter.dart' show CodeEmitterTask, NativeEmitter; 21 import '../js_emitter/js_emitter.dart' show CodeEmitterTask, NativeEmitter;
21 import 'package:front_end/src/fasta/scanner.dart' show BeginGroupToken, Token;
22 import 'package:front_end/src/fasta/scanner.dart' as Tokens show EOF_TOKEN;
23 import '../tree/tree.dart';
24 import '../universe/use.dart' show StaticUse, TypeUse; 22 import '../universe/use.dart' show StaticUse, TypeUse;
25 import '../universe/world_impact.dart' 23 import '../universe/world_impact.dart'
26 show WorldImpact, WorldImpactBuilder, WorldImpactBuilderImpl; 24 show WorldImpact, WorldImpactBuilder, WorldImpactBuilderImpl;
27 import 'behavior.dart'; 25 import 'behavior.dart';
28 26
29 /** 27 /**
30 * This could be an abstract class but we use it as a stub for the dart_backend. 28 * This could be an abstract class but we use it as a stub for the dart_backend.
31 */ 29 */
32 class NativeEnqueuer { 30 class NativeEnqueuer {
33 /// Called when a [type] has been instantiated natively. 31 /// Called when a [type] has been instantiated natively.
34 void onInstantiatedType(InterfaceType type) {} 32 void onInstantiatedType(InterfaceType type) {}
35 33
36 /// Initial entry point to native enqueuer. 34 /// Initial entry point to native enqueuer.
37 WorldImpact processNativeClasses(Iterable<LibraryElement> libraries) => 35 WorldImpact processNativeClasses(Iterable<LibraryElement> libraries) =>
38 const WorldImpact(); 36 const WorldImpact();
39 37
40 /// Registers the [nativeBehavior]. Adds the liveness of its instantiated 38 /// Registers the [nativeBehavior]. Adds the liveness of its instantiated
41 /// types to the world. 39 /// types to the world.
42 void registerNativeBehavior( 40 void registerNativeBehavior(
43 WorldImpactBuilder impactBuilder, NativeBehavior nativeBehavior, cause) {} 41 WorldImpactBuilder impactBuilder, NativeBehavior nativeBehavior, cause) {}
44 42
45 /// Returns whether native classes are being used. 43 /// Returns whether native classes are being used.
46 bool get hasInstantiatedNativeClasses => false; 44 bool get hasInstantiatedNativeClasses => false;
47 45
48 /// Emits a summary information using the [log] function. 46 /// Emits a summary information using the [log] function.
49 void logSummary(log(message)) {} 47 void logSummary(log(message)) {}
50 } 48 }
51 49
52 abstract class NativeEnqueuerBase implements NativeEnqueuer { 50 abstract class NativeEnqueuerBase implements NativeEnqueuer {
Johnni Winther 2017/03/28 09:30:28 Weird diff. Code is moved from NativeEnqueuerBase
51 final Set<ClassElement> _registeredClasses = new Set<ClassElement>();
52 final Set<ClassElement> _unusedClasses = new Set<ClassElement>();
53
54 bool get hasInstantiatedNativeClasses => !_registeredClasses.isEmpty;
55
56 final Compiler _compiler;
57 final bool enableLiveTypeAnalysis;
58
59 /// Subclasses of [NativeEnqueuerBase] are constructed by the backend.
60 NativeEnqueuerBase(this._compiler, this.enableLiveTypeAnalysis);
61
62 JavaScriptBackend get _backend => _compiler.backend;
63 BackendHelpers get _helpers => _backend.helpers;
64 Resolution get _resolution => _compiler.resolution;
65
66 DiagnosticReporter get _reporter => _compiler.reporter;
67 CommonElements get _commonElements => _compiler.commonElements;
68
69 NativeBasicData get _nativeBasicData => _backend.nativeBasicData;
70
71 BackendClasses get _backendClasses => _backend.backendClasses;
72
73 void onInstantiatedType(InterfaceType type) {
74 if (_unusedClasses.remove(type.element)) {
75 _registeredClasses.add(type.element);
76 }
77 }
78
79 /// Register [classes] as natively instantiated in [impactBuilder].
80 void _registerTypeUses(
81 WorldImpactBuilder impactBuilder, Set<ClassElement> classes, cause) {
82 for (ClassElement cls in classes) {
83 if (!_unusedClasses.contains(cls)) {
84 // No need to add [classElement] to [impactBuilder]: it has already been
85 // instantiated and we don't track origins of native instantiations
86 // precisely.
87 continue;
88 }
89 cls.ensureResolved(_resolution);
90 impactBuilder
91 .registerTypeUse(new TypeUse.nativeInstantiation(cls.rawType));
92 }
93 }
94
95 void registerNativeBehavior(
96 WorldImpactBuilder impactBuilder, NativeBehavior nativeBehavior, cause) {
97 _processNativeBehavior(impactBuilder, nativeBehavior, cause);
98 }
99
100 void _processNativeBehavior(
101 WorldImpactBuilder impactBuilder, NativeBehavior behavior, cause) {
102 void registerInstantiation(ResolutionInterfaceType type) {
103 impactBuilder.registerTypeUse(new TypeUse.nativeInstantiation(type));
104 }
105
106 int unusedBefore = _unusedClasses.length;
107 Set<ClassElement> matchingClasses = new Set<ClassElement>();
108 for (var type in behavior.typesInstantiated) {
109 if (type is SpecialType) {
110 if (type == SpecialType.JsObject) {
111 registerInstantiation(_commonElements.objectType);
112 }
113 continue;
114 }
115 if (type is ResolutionInterfaceType) {
116 if (type == _commonElements.numType) {
117 registerInstantiation(_commonElements.doubleType);
118 registerInstantiation(_commonElements.intType);
119 } else if (type == _commonElements.intType ||
120 type == _commonElements.doubleType ||
121 type == _commonElements.stringType ||
122 type == _commonElements.nullType ||
123 type == _commonElements.boolType ||
124 type.asInstanceOf(_backendClasses.listClass) != null) {
125 registerInstantiation(type);
126 }
127 // TODO(johnniwinther): Improve spec string precision to handle type
128 // arguments and implements relations that preserve generics. Currently
129 // we cannot distinguish between `List`, `List<dynamic>`, and
130 // `List<int>` and take all to mean `List<E>`; in effect not including
131 // any native subclasses of generic classes.
132 // TODO(johnniwinther,sra): Find and replace uses of `List` with the
133 // actual implementation classes such as `JSArray` et al.
134 matchingClasses
135 .addAll(_findUnusedClassesMatching((ClassElement nativeClass) {
136 ResolutionInterfaceType nativeType = nativeClass.thisType;
137 ResolutionInterfaceType specType = type.element.thisType;
138 return _compiler.types.isSubtype(nativeType, specType);
139 }));
140 } else if (type.isDynamic) {
141 matchingClasses.addAll(_unusedClasses);
142 } else {
143 assert(type is ResolutionVoidType);
144 }
145 }
146 if (matchingClasses.isNotEmpty && _registeredClasses.isEmpty) {
147 matchingClasses.addAll(_onFirstNativeClass(impactBuilder));
148 }
149 _registerTypeUses(impactBuilder, matchingClasses, cause);
150
151 // Give an info so that library developers can compile with -v to find why
152 // all the native classes are included.
153 if (unusedBefore > 0 && unusedBefore == matchingClasses.length) {
154 _reporter.log('All native types marked as used due to $cause.');
155 }
156 }
157
158 Iterable<ClassElement> _findUnusedClassesMatching(
159 bool predicate(classElement)) {
160 return _unusedClasses.where(predicate);
161 }
162
163 void _registerBackendUse(FunctionEntity element) {}
164
165 Iterable<ClassElement> _onFirstNativeClass(WorldImpactBuilder impactBuilder) {
166 void staticUse(FunctionEntity element) {
167 impactBuilder.registerStaticUse(new StaticUse.implicitInvoke(element));
168 _registerBackendUse(element);
169 }
170
171 staticUse(_helpers.defineProperty);
172 staticUse(_helpers.toStringForNativeObject);
173 staticUse(_helpers.hashCodeForNativeObject);
174 staticUse(_helpers.closureConverter);
175 return _findNativeExceptions();
176 }
177
178 Iterable<ClassElement> _findNativeExceptions() {
179 return _findUnusedClassesMatching((classElement) {
180 // TODO(sra): Annotate exception classes in dart:html.
181 String name = classElement.name;
182 if (name.contains('Exception')) return true;
183 if (name.contains('Error')) return true;
184 return false;
185 });
186 }
187 }
188
189 class NativeResolutionEnqueuer extends NativeEnqueuerBase {
53 /// The set of all native classes. Each native class is in [nativeClasses] 190 /// The set of all native classes. Each native class is in [nativeClasses]
54 /// and exactly one of [unusedClasses] and [registeredClasses]. 191 /// and exactly one of [unusedClasses] and [registeredClasses].
55 final Set<ClassElement> _nativeClasses = new Set<ClassElement>(); 192 final Set<ClassElement> _nativeClasses = new Set<ClassElement>();
56 193
57 final Set<ClassElement> _registeredClasses = new Set<ClassElement>(); 194 Map<String, ClassElement> tagOwner = new Map<String, ClassElement>();
58 final Set<ClassElement> _unusedClasses = new Set<ClassElement>(); 195
59 196 NativeResolutionEnqueuer(Compiler compiler)
60 bool get hasInstantiatedNativeClasses => !_registeredClasses.isEmpty; 197 : super(compiler, compiler.options.enableNativeLiveTypeAnalysis);
61 198
62 final Set<ClassElement> nativeClassesAndSubclasses = new Set<ClassElement>(); 199 BackendUsageBuilder get _backendUsageBuilder => _backend.backendUsageBuilder;
63 200
64 final Compiler compiler; 201 void _registerBackendUse(FunctionEntity element) {
65 final bool enableLiveTypeAnalysis; 202 _backendUsageBuilder.registerBackendFunctionUse(element);
66 203 _backendUsageBuilder.registerGlobalFunctionDependency(element);
67 /// Subclasses of [NativeEnqueuerBase] are constructed by the backend.
68 NativeEnqueuerBase(Compiler compiler, this.enableLiveTypeAnalysis)
69 : this.compiler = compiler;
70
71 JavaScriptBackend get backend => compiler.backend;
72 BackendHelpers get helpers => backend.helpers;
73 Resolution get resolution => compiler.resolution;
74
75 DiagnosticReporter get reporter => compiler.reporter;
76 CommonElements get commonElements => compiler.commonElements;
77
78 void onInstantiatedType(ResolutionInterfaceType type) {
79 if (_unusedClasses.remove(type.element)) {
80 _registeredClasses.add(type.element);
81 }
82 } 204 }
83 205
84 WorldImpact processNativeClasses(Iterable<LibraryElement> libraries) { 206 WorldImpact processNativeClasses(Iterable<LibraryElement> libraries) {
85 WorldImpactBuilderImpl impactBuilder = new WorldImpactBuilderImpl(); 207 WorldImpactBuilderImpl impactBuilder = new WorldImpactBuilderImpl();
86 _processNativeClasses(impactBuilder, libraries); 208 Set<ClassElement> nativeClasses = new Set<ClassElement>();
87 return impactBuilder; 209 libraries.forEach((l) => _processNativeClassesInLibrary(l, nativeClasses));
88 } 210 if (_helpers.isolateHelperLibrary != null) {
89 211 _processNativeClassesInLibrary(
90 void _processNativeClasses( 212 _helpers.isolateHelperLibrary, nativeClasses);
91 WorldImpactBuilder impactBuilder, Iterable<LibraryElement> libraries) { 213 }
92 libraries.forEach(processNativeClassesInLibrary); 214 _processSubclassesOfNativeClasses(libraries, nativeClasses);
93 if (helpers.isolateHelperLibrary != null) { 215 _nativeClasses.addAll(nativeClasses);
94 processNativeClassesInLibrary(helpers.isolateHelperLibrary); 216 _unusedClasses.addAll(nativeClasses);
95 }
96 processSubclassesOfNativeClasses(libraries);
97 if (!enableLiveTypeAnalysis) { 217 if (!enableLiveTypeAnalysis) {
98 _registerTypeUses(impactBuilder, _nativeClasses, 'forced'); 218 _registerTypeUses(impactBuilder, _nativeClasses, 'forced');
99 } 219 }
100 } 220 return impactBuilder;
101 221 }
102 void processNativeClassesInLibrary(LibraryElement library) { 222
223 void _processNativeClassesInLibrary(
224 LibraryElement library, Set<ClassElement> nativeClasses) {
103 // Use implementation to ensure the inclusion of injected members. 225 // Use implementation to ensure the inclusion of injected members.
104 library.implementation.forEachLocalMember((Element element) { 226 library.implementation.forEachLocalMember((Element element) {
105 if (element.isClass) { 227 if (element.isClass) {
106 ClassElement cls = element; 228 ClassElement cls = element;
107 if (backend.nativeBasicData.isNativeClass(cls)) { 229 if (_nativeBasicData.isNativeClass(cls)) {
108 processNativeClass(element); 230 _processNativeClass(element, nativeClasses);
109 } 231 }
110 } 232 }
111 }); 233 });
112 } 234 }
113 235
114 void processNativeClass(ClassElement classElement) { 236 void _processNativeClass(
115 _nativeClasses.add(classElement); 237 ClassElement classElement, Set<ClassElement> nativeClasses) {
116 _unusedClasses.add(classElement); 238 nativeClasses.add(classElement);
117 // Resolve class to ensure the class has valid inheritance info. 239 // Resolve class to ensure the class has valid inheritance info.
118 classElement.ensureResolved(resolution); 240 classElement.ensureResolved(_resolution);
119 } 241 // Js Interop interfaces do not have tags.
120 242 if (_nativeBasicData.isJsInteropClass(classElement)) return;
121 void processSubclassesOfNativeClasses(Iterable<LibraryElement> libraries) { 243 // Since we map from dispatch tags to classes, a dispatch tag must be used
244 // on only one native class.
245 for (String tag in _nativeBasicData.getNativeTagsOfClass(classElement)) {
246 ClassElement owner = tagOwner[tag];
247 if (owner != null) {
248 if (owner != classElement) {
249 _reporter.internalError(
250 classElement, "Tag '$tag' already in use by '${owner.name}'");
251 }
252 } else {
253 tagOwner[tag] = classElement;
254 }
255 }
256 }
257
258 void _processSubclassesOfNativeClasses(
259 Iterable<LibraryElement> libraries, Set<ClassElement> nativeClasses) {
260 Set<ClassElement> nativeClassesAndSubclasses = new Set<ClassElement>();
122 // Collect potential subclasses, e.g. 261 // Collect potential subclasses, e.g.
123 // 262 //
124 // class B extends foo.A {} 263 // class B extends foo.A {}
125 // 264 //
126 // String "A" has a potential subclass B. 265 // String "A" has a potential subclass B.
127 266
128 var potentialExtends = new Map<String, Set<ClassElement>>(); 267 var potentialExtends = new Map<String, Set<ClassElement>>();
129 268
130 libraries.forEach((library) { 269 libraries.forEach((library) {
131 library.implementation.forEachLocalMember((element) { 270 library.implementation.forEachLocalMember((element) {
132 if (element.isClass) { 271 if (element.isClass) {
133 String extendsName = findExtendsNameOfClass(element); 272 String extendsName = _findExtendsNameOfClass(element);
134 if (extendsName != null) { 273 if (extendsName != null) {
135 Set<ClassElement> potentialSubclasses = potentialExtends 274 Set<ClassElement> potentialSubclasses = potentialExtends
136 .putIfAbsent(extendsName, () => new Set<ClassElement>()); 275 .putIfAbsent(extendsName, () => new Set<ClassElement>());
137 potentialSubclasses.add(element); 276 potentialSubclasses.add(element);
138 } 277 }
139 } 278 }
140 }); 279 });
141 }); 280 });
142 281
143 // Resolve all the native classes and any classes that might extend them in 282 // Resolve all the native classes and any classes that might extend them in
144 // [potentialExtends], and then check that the properly resolved class is in 283 // [potentialExtends], and then check that the properly resolved class is in
145 // fact a subclass of a native class. 284 // fact a subclass of a native class.
146 285
147 ClassElement nativeSuperclassOf(ClassElement classElement) { 286 ClassElement nativeSuperclassOf(ClassElement classElement) {
148 if (backend.nativeBasicData.isNativeClass(classElement)) 287 if (_nativeBasicData.isNativeClass(classElement)) return classElement;
149 return classElement;
150 if (classElement.superclass == null) return null; 288 if (classElement.superclass == null) return null;
151 return nativeSuperclassOf(classElement.superclass); 289 return nativeSuperclassOf(classElement.superclass);
152 } 290 }
153 291
154 void walkPotentialSubclasses(ClassElement element) { 292 void walkPotentialSubclasses(ClassElement element) {
155 if (nativeClassesAndSubclasses.contains(element)) return; 293 if (nativeClassesAndSubclasses.contains(element)) return;
156 element.ensureResolved(resolution); 294 element.ensureResolved(_resolution);
157 ClassElement nativeSuperclass = nativeSuperclassOf(element); 295 ClassElement nativeSuperclass = nativeSuperclassOf(element);
158 if (nativeSuperclass != null) { 296 if (nativeSuperclass != null) {
159 nativeClassesAndSubclasses.add(element); 297 nativeClassesAndSubclasses.add(element);
160 Set<ClassElement> potentialSubclasses = potentialExtends[element.name]; 298 Set<ClassElement> potentialSubclasses = potentialExtends[element.name];
161 if (potentialSubclasses != null) { 299 if (potentialSubclasses != null) {
162 potentialSubclasses.forEach(walkPotentialSubclasses); 300 potentialSubclasses.forEach(walkPotentialSubclasses);
163 } 301 }
164 } 302 }
165 } 303 }
166 304
167 _nativeClasses.forEach(walkPotentialSubclasses); 305 nativeClasses.forEach(walkPotentialSubclasses);
168 306 nativeClasses.addAll(nativeClassesAndSubclasses);
169 _nativeClasses.addAll(nativeClassesAndSubclasses);
170 _unusedClasses.addAll(nativeClassesAndSubclasses);
171 } 307 }
172 308
173 /** 309 /**
174 * Returns the source string of the class named in the extends clause, or 310 * Returns the source string of the class named in the extends clause, or
175 * `null` if there is no extends clause. 311 * `null` if there is no extends clause.
176 */ 312 */
177 String findExtendsNameOfClass(ClassElement classElement) { 313 String _findExtendsNameOfClass(ClassElement classElement) {
178 if (classElement.isResolved) { 314 if (classElement.isResolved) {
179 ClassElement superClass = classElement.superclass; 315 ClassElement superClass = classElement.superclass;
180 while (superClass != null) { 316 while (superClass != null) {
181 if (!superClass.isUnnamedMixinApplication) { 317 if (!superClass.isUnnamedMixinApplication) {
182 return superClass.name; 318 return superClass.name;
183 } 319 }
184 superClass = superClass.superclass; 320 superClass = superClass.superclass;
185 } 321 }
186 return null; 322 return null;
187 } 323 }
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
228 token = token.next; 364 token = token.next;
229 if (token.stringValue != '.') break; 365 if (token.stringValue != '.') break;
230 token = token.next; 366 token = token.next;
231 if (!token.isIdentifier()) return null; 367 if (!token.isIdentifier()) return null;
232 id = token; 368 id = token;
233 } 369 }
234 // Should be at '{', 'with', 'implements', '<' or 'native'. 370 // Should be at '{', 'with', 'implements', '<' or 'native'.
235 return id.lexeme; 371 return id.lexeme;
236 } 372 }
237 373
238 return reporter.withCurrentElement(classElement, () { 374 return _reporter.withCurrentElement(classElement, () {
239 return scanForExtendsName(classElement.position); 375 return scanForExtendsName(classElement.position);
240 }); 376 });
241 } 377 }
242 378
243 /// Register [classes] as natively instantiated in [impactBuilder].
244 void _registerTypeUses(
245 WorldImpactBuilder impactBuilder, Set<ClassElement> classes, cause) {
246 for (ClassElement cls in classes) {
247 if (!_unusedClasses.contains(cls)) {
248 // No need to add [classElement] to [impactBuilder]: it has already been
249 // instantiated and we don't track origins of native instantiations
250 // precisely.
251 continue;
252 }
253 cls.ensureResolved(resolution);
254 impactBuilder
255 .registerTypeUse(new TypeUse.nativeInstantiation(cls.rawType));
256 }
257 }
258
259 void registerNativeBehavior(
260 WorldImpactBuilder impactBuilder, NativeBehavior nativeBehavior, cause) {
261 _processNativeBehavior(impactBuilder, nativeBehavior, cause);
262 }
263
264 void _processNativeBehavior(
265 WorldImpactBuilder impactBuilder, NativeBehavior behavior, cause) {
266 void registerInstantiation(ResolutionInterfaceType type) {
267 impactBuilder.registerTypeUse(new TypeUse.nativeInstantiation(type));
268 }
269
270 int unusedBefore = _unusedClasses.length;
271 Set<ClassElement> matchingClasses = new Set<ClassElement>();
272 for (var type in behavior.typesInstantiated) {
273 if (type is SpecialType) {
274 if (type == SpecialType.JsObject) {
275 registerInstantiation(compiler.commonElements.objectType);
276 }
277 continue;
278 }
279 if (type is ResolutionInterfaceType) {
280 if (type == commonElements.numType) {
281 registerInstantiation(commonElements.doubleType);
282 registerInstantiation(commonElements.intType);
283 } else if (type == commonElements.intType ||
284 type == commonElements.doubleType ||
285 type == commonElements.stringType ||
286 type == commonElements.nullType ||
287 type == commonElements.boolType ||
288 type.asInstanceOf(backend.backendClasses.listClass) != null) {
289 registerInstantiation(type);
290 }
291 // TODO(johnniwinther): Improve spec string precision to handle type
292 // arguments and implements relations that preserve generics. Currently
293 // we cannot distinguish between `List`, `List<dynamic>`, and
294 // `List<int>` and take all to mean `List<E>`; in effect not including
295 // any native subclasses of generic classes.
296 // TODO(johnniwinther,sra): Find and replace uses of `List` with the
297 // actual implementation classes such as `JSArray` et al.
298 matchingClasses
299 .addAll(_findUnusedClassesMatching((ClassElement nativeClass) {
300 ResolutionInterfaceType nativeType = nativeClass.thisType;
301 ResolutionInterfaceType specType = type.element.thisType;
302 return compiler.types.isSubtype(nativeType, specType);
303 }));
304 } else if (type.isDynamic) {
305 matchingClasses.addAll(_unusedClasses);
306 } else {
307 assert(type is ResolutionVoidType);
308 }
309 }
310 if (matchingClasses.isNotEmpty && _registeredClasses.isEmpty) {
311 matchingClasses.addAll(_onFirstNativeClass(impactBuilder));
312 }
313 _registerTypeUses(impactBuilder, matchingClasses, cause);
314
315 // Give an info so that library developers can compile with -v to find why
316 // all the native classes are included.
317 if (unusedBefore > 0 && unusedBefore == matchingClasses.length) {
318 reporter.log('All native types marked as used due to $cause.');
319 }
320 }
321
322 Iterable<ClassElement> _findUnusedClassesMatching(
323 bool predicate(classElement)) {
324 return _unusedClasses.where(predicate);
325 }
326
327 void registerBackendUse(MethodElement element) {}
328
329 Iterable<ClassElement> _onFirstNativeClass(WorldImpactBuilder impactBuilder) {
330 void staticUse(MethodElement element) {
331 impactBuilder.registerStaticUse(new StaticUse.implicitInvoke(element));
332 registerBackendUse(element);
333 }
334
335 staticUse(helpers.defineProperty);
336 staticUse(helpers.toStringForNativeObject);
337 staticUse(helpers.hashCodeForNativeObject);
338 staticUse(helpers.closureConverter);
339 return _findNativeExceptions();
340 }
341
342 Iterable<ClassElement> _findNativeExceptions() {
343 return _findUnusedClassesMatching((classElement) {
344 // TODO(sra): Annotate exception classes in dart:html.
345 String name = classElement.name;
346 if (name.contains('Exception')) return true;
347 if (name.contains('Error')) return true;
348 return false;
349 });
350 }
351 }
352
353 class NativeResolutionEnqueuer extends NativeEnqueuerBase {
354 Map<String, ClassElement> tagOwner = new Map<String, ClassElement>();
355
356 NativeResolutionEnqueuer(Compiler compiler)
357 : super(compiler, compiler.options.enableNativeLiveTypeAnalysis);
358
359 BackendUsageBuilder get _backendUsageBuilder => backend.backendUsageBuilder;
360
361 void registerBackendUse(MethodElement element) {
362 _backendUsageBuilder.registerBackendFunctionUse(element);
363 _backendUsageBuilder.registerGlobalFunctionDependency(element);
364 }
365
366 void processNativeClass(ClassElement classElement) {
367 super.processNativeClass(classElement);
368
369 // Js Interop interfaces do not have tags.
370 if (backend.nativeBasicData.isJsInteropClass(classElement)) return;
371 // Since we map from dispatch tags to classes, a dispatch tag must be used
372 // on only one native class.
373 for (String tag
374 in backend.nativeBasicData.getNativeTagsOfClass(classElement)) {
375 ClassElement owner = tagOwner[tag];
376 if (owner != null) {
377 if (owner != classElement) {
378 reporter.internalError(
379 classElement, "Tag '$tag' already in use by '${owner.name}'");
380 }
381 } else {
382 tagOwner[tag] = classElement;
383 }
384 }
385 }
386
387 void logSummary(log(message)) { 379 void logSummary(log(message)) {
388 log('Resolved ${_registeredClasses.length} native elements used, ' 380 log('Resolved ${_registeredClasses.length} native elements used, '
389 '${_unusedClasses.length} native elements dead.'); 381 '${_unusedClasses.length} native elements dead.');
390 } 382 }
391 } 383 }
392 384
393 class NativeCodegenEnqueuer extends NativeEnqueuerBase { 385 class NativeCodegenEnqueuer extends NativeEnqueuerBase {
394 final CodeEmitterTask emitter; 386 final CodeEmitterTask emitter;
395 387
396 final Set<ClassElement> doneAddSubtypes = new Set<ClassElement>(); 388 final Set<ClassElement> doneAddSubtypes = new Set<ClassElement>();
397 389
398 final NativeResolutionEnqueuer _resolutionEnqueuer; 390 final NativeResolutionEnqueuer _resolutionEnqueuer;
399 391
400 NativeCodegenEnqueuer( 392 NativeCodegenEnqueuer(
401 Compiler compiler, this.emitter, this._resolutionEnqueuer) 393 Compiler compiler, this.emitter, this._resolutionEnqueuer)
402 : super(compiler, compiler.options.enableNativeLiveTypeAnalysis); 394 : super(compiler, compiler.options.enableNativeLiveTypeAnalysis) {}
403 395
404 void _processNativeClasses( 396 NativeData get _nativeData => _backend.nativeData;
405 WorldImpactBuilder impactBuilder, Iterable<LibraryElement> libraries) { 397
406 super._processNativeClasses(impactBuilder, libraries); 398 WorldImpact processNativeClasses(Iterable<LibraryElement> libraries) {
399 WorldImpactBuilderImpl impactBuilder = new WorldImpactBuilderImpl();
400 _unusedClasses.addAll(_resolutionEnqueuer._nativeClasses);
401
402 if (!enableLiveTypeAnalysis) {
403 _registerTypeUses(
404 impactBuilder, _resolutionEnqueuer._nativeClasses, 'forced');
405 }
407 406
408 // HACK HACK - add all the resolved classes. 407 // HACK HACK - add all the resolved classes.
409 Set<ClassElement> matchingClasses = new Set<ClassElement>(); 408 Set<ClassElement> matchingClasses = new Set<ClassElement>();
410 for (final classElement in _resolutionEnqueuer._registeredClasses) { 409 for (final classElement in _resolutionEnqueuer._registeredClasses) {
411 if (_unusedClasses.contains(classElement)) { 410 if (_unusedClasses.contains(classElement)) {
412 matchingClasses.add(classElement); 411 matchingClasses.add(classElement);
413 } 412 }
414 } 413 }
415 if (matchingClasses.isNotEmpty && _registeredClasses.isEmpty) { 414 if (matchingClasses.isNotEmpty && _registeredClasses.isEmpty) {
416 matchingClasses.addAll(_onFirstNativeClass(impactBuilder)); 415 matchingClasses.addAll(_onFirstNativeClass(impactBuilder));
417 } 416 }
418 _registerTypeUses(impactBuilder, matchingClasses, 'was resolved'); 417 _registerTypeUses(impactBuilder, matchingClasses, 'was resolved');
418 return impactBuilder;
419 } 419 }
420 420
421 void _registerTypeUses( 421 void _registerTypeUses(
422 WorldImpactBuilder impactBuilder, Set<ClassElement> classes, cause) { 422 WorldImpactBuilder impactBuilder, Set<ClassElement> classes, cause) {
423 super._registerTypeUses(impactBuilder, classes, cause); 423 super._registerTypeUses(impactBuilder, classes, cause);
424 424
425 for (ClassElement classElement in classes) { 425 for (ClassElement classElement in classes) {
426 // Add the information that this class is a subtype of its supertypes. The 426 // Add the information that this class is a subtype of its supertypes. The
427 // code emitter and the ssa builder use that information. 427 // code emitter and the ssa builder use that information.
428 _addSubtypes(classElement, emitter.nativeEmitter); 428 _addSubtypes(classElement, emitter.nativeEmitter);
429 } 429 }
430 } 430 }
431 431
432 void _addSubtypes(ClassElement cls, NativeEmitter emitter) { 432 void _addSubtypes(ClassElement cls, NativeEmitter emitter) {
433 if (!backend.nativeData.isNativeClass(cls)) return; 433 if (!_nativeData.isNativeClass(cls)) return;
434 if (doneAddSubtypes.contains(cls)) return; 434 if (doneAddSubtypes.contains(cls)) return;
435 doneAddSubtypes.add(cls); 435 doneAddSubtypes.add(cls);
436 436
437 // Walk the superclass chain since classes on the superclass chain might not 437 // Walk the superclass chain since classes on the superclass chain might not
438 // be instantiated (abstract or simply unused). 438 // be instantiated (abstract or simply unused).
439 _addSubtypes(cls.superclass, emitter); 439 _addSubtypes(cls.superclass, emitter);
440 440
441 for (ResolutionInterfaceType type in cls.allSupertypes) { 441 for (ResolutionInterfaceType type in cls.allSupertypes) {
442 List<ClassEntity> subtypes = 442 List<ClassEntity> subtypes =
443 emitter.subtypes.putIfAbsent(type.element, () => <ClassEntity>[]); 443 emitter.subtypes.putIfAbsent(type.element, () => <ClassEntity>[]);
444 subtypes.add(cls); 444 subtypes.add(cls);
445 } 445 }
446 446
447 // Skip through all the mixin applications in the super class 447 // Skip through all the mixin applications in the super class
448 // chain. That way, the direct subtypes set only contain the 448 // chain. That way, the direct subtypes set only contain the
449 // natives classes. 449 // natives classes.
450 ClassElement superclass = cls.superclass; 450 ClassElement superclass = cls.superclass;
451 while (superclass != null && superclass.isMixinApplication) { 451 while (superclass != null && superclass.isMixinApplication) {
452 assert(!backend.nativeData.isNativeClass(superclass)); 452 assert(!_nativeData.isNativeClass(superclass));
453 superclass = superclass.superclass; 453 superclass = superclass.superclass;
454 } 454 }
455 455
456 List<ClassEntity> directSubtypes = 456 List<ClassEntity> directSubtypes =
457 emitter.directSubtypes.putIfAbsent(superclass, () => <ClassEntity>[]); 457 emitter.directSubtypes.putIfAbsent(superclass, () => <ClassEntity>[]);
458 directSubtypes.add(cls); 458 directSubtypes.add(cls);
459 } 459 }
460 460
461 void logSummary(log(message)) { 461 void logSummary(log(message)) {
462 log('Compiled ${_registeredClasses.length} native classes, ' 462 log('Compiled ${_registeredClasses.length} native classes, '
463 '${_unusedClasses.length} native classes omitted.'); 463 '${_unusedClasses.length} native classes omitted.');
464 } 464 }
465 } 465 }
OLDNEW
« no previous file with comments | « no previous file | tests/compiler/dart2js/inference/inference_test_helper.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698