Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 } |
| OLD | NEW |