| 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 | |
| 8 import '../common.dart'; | 5 import '../common.dart'; |
| 9 import '../common/backend_api.dart'; | 6 import '../common/backend_api.dart'; |
| 10 import '../common/resolution.dart' show Resolution; | 7 import '../common/resolution.dart' show Resolution; |
| 11 import '../compiler.dart' show Compiler; | 8 import '../compiler.dart' show Compiler; |
| 12 import '../common_elements.dart' show CommonElements; | 9 import '../common_elements.dart' show CommonElements; |
| 13 import '../elements/elements.dart'; | 10 import '../elements/elements.dart'; |
| 14 import '../elements/entities.dart'; | 11 import '../elements/entities.dart'; |
| 15 import '../elements/resolution_types.dart'; | 12 import '../elements/resolution_types.dart'; |
| 16 import '../elements/types.dart'; | 13 import '../elements/types.dart'; |
| 17 import '../js_backend/backend_helpers.dart' show BackendHelpers; | 14 import '../js_backend/backend_helpers.dart' show BackendHelpers; |
| 18 import '../js_backend/backend_usage.dart' show BackendUsageBuilder; | 15 import '../js_backend/backend_usage.dart' show BackendUsageBuilder; |
| 19 import '../js_backend/js_backend.dart'; | 16 import '../js_backend/js_backend.dart'; |
| 20 import '../js_backend/native_data.dart' show NativeBasicData, NativeData; | 17 import '../js_backend/native_data.dart' show NativeBasicData, NativeData; |
| 21 import '../js_emitter/js_emitter.dart' show CodeEmitterTask, NativeEmitter; | 18 import '../js_emitter/js_emitter.dart' show CodeEmitterTask, NativeEmitter; |
| 22 import '../universe/use.dart' show StaticUse, TypeUse; | 19 import '../universe/use.dart' show StaticUse, TypeUse; |
| 23 import '../universe/world_impact.dart' | 20 import '../universe/world_impact.dart' |
| 24 show WorldImpact, WorldImpactBuilder, WorldImpactBuilderImpl; | 21 show WorldImpact, WorldImpactBuilder, WorldImpactBuilderImpl; |
| 25 import 'behavior.dart'; | 22 import 'behavior.dart'; |
| 23 import 'resolver.dart' show NativeClassResolver; |
| 26 | 24 |
| 27 /** | 25 /** |
| 28 * This could be an abstract class but we use it as a stub for the dart_backend. | 26 * This could be an abstract class but we use it as a stub for the dart_backend. |
| 29 */ | 27 */ |
| 30 class NativeEnqueuer { | 28 class NativeEnqueuer { |
| 31 /// Called when a [type] has been instantiated natively. | 29 /// Called when a [type] has been instantiated natively. |
| 32 void onInstantiatedType(InterfaceType type) {} | 30 void onInstantiatedType(InterfaceType type) {} |
| 33 | 31 |
| 34 /// Initial entry point to native enqueuer. | 32 /// Initial entry point to native enqueuer. |
| 35 WorldImpact processNativeClasses(Iterable<LibraryElement> libraries) => | 33 WorldImpact processNativeClasses(Iterable<LibraryElement> libraries) => |
| (...skipping 23 matching lines...) Expand all Loading... |
| 59 /// Subclasses of [NativeEnqueuerBase] are constructed by the backend. | 57 /// Subclasses of [NativeEnqueuerBase] are constructed by the backend. |
| 60 NativeEnqueuerBase(this._compiler, this.enableLiveTypeAnalysis); | 58 NativeEnqueuerBase(this._compiler, this.enableLiveTypeAnalysis); |
| 61 | 59 |
| 62 JavaScriptBackend get _backend => _compiler.backend; | 60 JavaScriptBackend get _backend => _compiler.backend; |
| 63 BackendHelpers get _helpers => _backend.helpers; | 61 BackendHelpers get _helpers => _backend.helpers; |
| 64 Resolution get _resolution => _compiler.resolution; | 62 Resolution get _resolution => _compiler.resolution; |
| 65 | 63 |
| 66 DiagnosticReporter get _reporter => _compiler.reporter; | 64 DiagnosticReporter get _reporter => _compiler.reporter; |
| 67 CommonElements get _commonElements => _compiler.commonElements; | 65 CommonElements get _commonElements => _compiler.commonElements; |
| 68 | 66 |
| 69 NativeBasicData get _nativeBasicData => _backend.nativeBasicData; | |
| 70 | |
| 71 BackendClasses get _backendClasses => _backend.backendClasses; | 67 BackendClasses get _backendClasses => _backend.backendClasses; |
| 72 | 68 |
| 73 void onInstantiatedType(InterfaceType type) { | 69 void onInstantiatedType(InterfaceType type) { |
| 74 if (_unusedClasses.remove(type.element)) { | 70 if (_unusedClasses.remove(type.element)) { |
| 75 _registeredClasses.add(type.element); | 71 _registeredClasses.add(type.element); |
| 76 } | 72 } |
| 77 } | 73 } |
| 78 | 74 |
| 79 /// Register [classes] as natively instantiated in [impactBuilder]. | 75 /// Register [classes] as natively instantiated in [impactBuilder]. |
| 80 void _registerTypeUses( | 76 void _registerTypeUses( |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 180 // TODO(sra): Annotate exception classes in dart:html. | 176 // TODO(sra): Annotate exception classes in dart:html. |
| 181 String name = classElement.name; | 177 String name = classElement.name; |
| 182 if (name.contains('Exception')) return true; | 178 if (name.contains('Exception')) return true; |
| 183 if (name.contains('Error')) return true; | 179 if (name.contains('Error')) return true; |
| 184 return false; | 180 return false; |
| 185 }); | 181 }); |
| 186 } | 182 } |
| 187 } | 183 } |
| 188 | 184 |
| 189 class NativeResolutionEnqueuer extends NativeEnqueuerBase { | 185 class NativeResolutionEnqueuer extends NativeEnqueuerBase { |
| 186 final NativeClassResolver _nativeClassResolver; |
| 187 |
| 190 /// The set of all native classes. Each native class is in [nativeClasses] | 188 /// The set of all native classes. Each native class is in [nativeClasses] |
| 191 /// and exactly one of [unusedClasses] and [registeredClasses]. | 189 /// and exactly one of [unusedClasses] and [registeredClasses]. |
| 192 final Set<ClassElement> _nativeClasses = new Set<ClassElement>(); | 190 final Set<ClassElement> _nativeClasses = new Set<ClassElement>(); |
| 193 | 191 |
| 194 Map<String, ClassElement> tagOwner = new Map<String, ClassElement>(); | 192 NativeResolutionEnqueuer(Compiler compiler, this._nativeClassResolver) |
| 195 | |
| 196 NativeResolutionEnqueuer(Compiler compiler) | |
| 197 : super(compiler, compiler.options.enableNativeLiveTypeAnalysis); | 193 : super(compiler, compiler.options.enableNativeLiveTypeAnalysis); |
| 198 | 194 |
| 199 BackendUsageBuilder get _backendUsageBuilder => _backend.backendUsageBuilder; | 195 BackendUsageBuilder get _backendUsageBuilder => _backend.backendUsageBuilder; |
| 200 | 196 |
| 201 void _registerBackendUse(FunctionEntity element) { | 197 void _registerBackendUse(FunctionEntity element) { |
| 202 _backendUsageBuilder.registerBackendFunctionUse(element); | 198 _backendUsageBuilder.registerBackendFunctionUse(element); |
| 203 _backendUsageBuilder.registerGlobalFunctionDependency(element); | 199 _backendUsageBuilder.registerGlobalFunctionDependency(element); |
| 204 } | 200 } |
| 205 | 201 |
| 206 WorldImpact processNativeClasses(Iterable<LibraryElement> libraries) { | 202 WorldImpact processNativeClasses(Iterable<LibraryElement> libraries) { |
| 207 WorldImpactBuilderImpl impactBuilder = new WorldImpactBuilderImpl(); | 203 WorldImpactBuilderImpl impactBuilder = new WorldImpactBuilderImpl(); |
| 208 Set<ClassElement> nativeClasses = new Set<ClassElement>(); | 204 Set<ClassElement> nativeClasses = |
| 209 libraries.forEach((l) => _processNativeClassesInLibrary(l, nativeClasses)); | 205 _nativeClassResolver.computeNativeClasses(libraries); |
| 210 if (_helpers.isolateHelperLibrary != null) { | |
| 211 _processNativeClassesInLibrary( | |
| 212 _helpers.isolateHelperLibrary, nativeClasses); | |
| 213 } | |
| 214 _processSubclassesOfNativeClasses(libraries, nativeClasses); | |
| 215 _nativeClasses.addAll(nativeClasses); | 206 _nativeClasses.addAll(nativeClasses); |
| 216 _unusedClasses.addAll(nativeClasses); | 207 _unusedClasses.addAll(nativeClasses); |
| 217 if (!enableLiveTypeAnalysis) { | 208 if (!enableLiveTypeAnalysis) { |
| 218 _registerTypeUses(impactBuilder, _nativeClasses, 'forced'); | 209 _registerTypeUses(impactBuilder, _nativeClasses, 'forced'); |
| 219 } | 210 } |
| 220 return impactBuilder; | 211 return impactBuilder; |
| 221 } | 212 } |
| 222 | 213 |
| 223 void _processNativeClassesInLibrary( | |
| 224 LibraryElement library, Set<ClassElement> nativeClasses) { | |
| 225 // Use implementation to ensure the inclusion of injected members. | |
| 226 library.implementation.forEachLocalMember((Element element) { | |
| 227 if (element.isClass) { | |
| 228 ClassElement cls = element; | |
| 229 if (_nativeBasicData.isNativeClass(cls)) { | |
| 230 _processNativeClass(element, nativeClasses); | |
| 231 } | |
| 232 } | |
| 233 }); | |
| 234 } | |
| 235 | |
| 236 void _processNativeClass( | |
| 237 ClassElement classElement, Set<ClassElement> nativeClasses) { | |
| 238 nativeClasses.add(classElement); | |
| 239 // Resolve class to ensure the class has valid inheritance info. | |
| 240 classElement.ensureResolved(_resolution); | |
| 241 // Js Interop interfaces do not have tags. | |
| 242 if (_nativeBasicData.isJsInteropClass(classElement)) return; | |
| 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>(); | |
| 261 // Collect potential subclasses, e.g. | |
| 262 // | |
| 263 // class B extends foo.A {} | |
| 264 // | |
| 265 // String "A" has a potential subclass B. | |
| 266 | |
| 267 var potentialExtends = new Map<String, Set<ClassElement>>(); | |
| 268 | |
| 269 libraries.forEach((library) { | |
| 270 library.implementation.forEachLocalMember((element) { | |
| 271 if (element.isClass) { | |
| 272 String extendsName = _findExtendsNameOfClass(element); | |
| 273 if (extendsName != null) { | |
| 274 Set<ClassElement> potentialSubclasses = potentialExtends | |
| 275 .putIfAbsent(extendsName, () => new Set<ClassElement>()); | |
| 276 potentialSubclasses.add(element); | |
| 277 } | |
| 278 } | |
| 279 }); | |
| 280 }); | |
| 281 | |
| 282 // Resolve all the native classes and any classes that might extend them in | |
| 283 // [potentialExtends], and then check that the properly resolved class is in | |
| 284 // fact a subclass of a native class. | |
| 285 | |
| 286 ClassElement nativeSuperclassOf(ClassElement classElement) { | |
| 287 if (_nativeBasicData.isNativeClass(classElement)) return classElement; | |
| 288 if (classElement.superclass == null) return null; | |
| 289 return nativeSuperclassOf(classElement.superclass); | |
| 290 } | |
| 291 | |
| 292 void walkPotentialSubclasses(ClassElement element) { | |
| 293 if (nativeClassesAndSubclasses.contains(element)) return; | |
| 294 element.ensureResolved(_resolution); | |
| 295 ClassElement nativeSuperclass = nativeSuperclassOf(element); | |
| 296 if (nativeSuperclass != null) { | |
| 297 nativeClassesAndSubclasses.add(element); | |
| 298 Set<ClassElement> potentialSubclasses = potentialExtends[element.name]; | |
| 299 if (potentialSubclasses != null) { | |
| 300 potentialSubclasses.forEach(walkPotentialSubclasses); | |
| 301 } | |
| 302 } | |
| 303 } | |
| 304 | |
| 305 nativeClasses.forEach(walkPotentialSubclasses); | |
| 306 nativeClasses.addAll(nativeClassesAndSubclasses); | |
| 307 } | |
| 308 | |
| 309 /** | |
| 310 * Returns the source string of the class named in the extends clause, or | |
| 311 * `null` if there is no extends clause. | |
| 312 */ | |
| 313 String _findExtendsNameOfClass(ClassElement classElement) { | |
| 314 if (classElement.isResolved) { | |
| 315 ClassElement superClass = classElement.superclass; | |
| 316 while (superClass != null) { | |
| 317 if (!superClass.isUnnamedMixinApplication) { | |
| 318 return superClass.name; | |
| 319 } | |
| 320 superClass = superClass.superclass; | |
| 321 } | |
| 322 return null; | |
| 323 } | |
| 324 | |
| 325 // "class B extends A ... {}" --> "A" | |
| 326 // "class B extends foo.A ... {}" --> "A" | |
| 327 // "class B<T> extends foo.A<T,T> with M1, M2 ... {}" --> "A" | |
| 328 | |
| 329 // We want to avoid calling classElement.parseNode on every class. Doing so | |
| 330 // will slightly increase parse time and size and cause compiler errors and | |
| 331 // warnings to me emitted in more unused code. | |
| 332 | |
| 333 // An alternative to this code is to extend the API of ClassElement to | |
| 334 // expose the name of the extended element. | |
| 335 | |
| 336 // Pattern match the above cases in the token stream. | |
| 337 // [abstract] class X extends [id.]* id | |
| 338 | |
| 339 Token skipTypeParameters(Token token) { | |
| 340 BeginGroupToken beginGroupToken = token; | |
| 341 Token endToken = beginGroupToken.endGroup; | |
| 342 return endToken.next; | |
| 343 //for (;;) { | |
| 344 // token = token.next; | |
| 345 // if (token.stringValue == '>') return token.next; | |
| 346 // if (token.stringValue == '<') return skipTypeParameters(token); | |
| 347 //} | |
| 348 } | |
| 349 | |
| 350 String scanForExtendsName(Token token) { | |
| 351 if (token.stringValue == 'abstract') token = token.next; | |
| 352 if (token.stringValue != 'class') return null; | |
| 353 token = token.next; | |
| 354 if (!token.isIdentifier()) return null; | |
| 355 token = token.next; | |
| 356 // class F<X extends B<X>> extends ... | |
| 357 if (token.stringValue == '<') { | |
| 358 token = skipTypeParameters(token); | |
| 359 } | |
| 360 if (token.stringValue != 'extends') return null; | |
| 361 token = token.next; | |
| 362 Token id = token; | |
| 363 while (token.kind != Tokens.EOF_TOKEN) { | |
| 364 token = token.next; | |
| 365 if (token.stringValue != '.') break; | |
| 366 token = token.next; | |
| 367 if (!token.isIdentifier()) return null; | |
| 368 id = token; | |
| 369 } | |
| 370 // Should be at '{', 'with', 'implements', '<' or 'native'. | |
| 371 return id.lexeme; | |
| 372 } | |
| 373 | |
| 374 return _reporter.withCurrentElement(classElement, () { | |
| 375 return scanForExtendsName(classElement.position); | |
| 376 }); | |
| 377 } | |
| 378 | |
| 379 void logSummary(log(message)) { | 214 void logSummary(log(message)) { |
| 380 log('Resolved ${_registeredClasses.length} native elements used, ' | 215 log('Resolved ${_registeredClasses.length} native elements used, ' |
| 381 '${_unusedClasses.length} native elements dead.'); | 216 '${_unusedClasses.length} native elements dead.'); |
| 382 } | 217 } |
| 383 } | 218 } |
| 384 | 219 |
| 385 class NativeCodegenEnqueuer extends NativeEnqueuerBase { | 220 class NativeCodegenEnqueuer extends NativeEnqueuerBase { |
| 386 final CodeEmitterTask emitter; | 221 final CodeEmitterTask _emitter; |
| 387 | 222 |
| 388 final Set<ClassElement> doneAddSubtypes = new Set<ClassElement>(); | 223 final Set<ClassElement> _doneAddSubtypes = new Set<ClassElement>(); |
| 389 | 224 |
| 390 final NativeResolutionEnqueuer _resolutionEnqueuer; | 225 final NativeResolutionEnqueuer _resolutionEnqueuer; |
| 391 | 226 |
| 392 NativeCodegenEnqueuer( | 227 NativeCodegenEnqueuer( |
| 393 Compiler compiler, this.emitter, this._resolutionEnqueuer) | 228 Compiler compiler, this._emitter, this._resolutionEnqueuer) |
| 394 : super(compiler, compiler.options.enableNativeLiveTypeAnalysis) {} | 229 : super(compiler, compiler.options.enableNativeLiveTypeAnalysis) {} |
| 395 | 230 |
| 396 NativeData get _nativeData => _backend.nativeData; | 231 NativeData get _nativeData => _backend.nativeData; |
| 397 | 232 |
| 398 WorldImpact processNativeClasses(Iterable<LibraryElement> libraries) { | 233 WorldImpact processNativeClasses(Iterable<LibraryElement> libraries) { |
| 399 WorldImpactBuilderImpl impactBuilder = new WorldImpactBuilderImpl(); | 234 WorldImpactBuilderImpl impactBuilder = new WorldImpactBuilderImpl(); |
| 400 _unusedClasses.addAll(_resolutionEnqueuer._nativeClasses); | 235 _unusedClasses.addAll(_resolutionEnqueuer._nativeClasses); |
| 401 | 236 |
| 402 if (!enableLiveTypeAnalysis) { | 237 if (!enableLiveTypeAnalysis) { |
| 403 _registerTypeUses( | 238 _registerTypeUses( |
| (...skipping 14 matching lines...) Expand all Loading... |
| 418 return impactBuilder; | 253 return impactBuilder; |
| 419 } | 254 } |
| 420 | 255 |
| 421 void _registerTypeUses( | 256 void _registerTypeUses( |
| 422 WorldImpactBuilder impactBuilder, Set<ClassElement> classes, cause) { | 257 WorldImpactBuilder impactBuilder, Set<ClassElement> classes, cause) { |
| 423 super._registerTypeUses(impactBuilder, classes, cause); | 258 super._registerTypeUses(impactBuilder, classes, cause); |
| 424 | 259 |
| 425 for (ClassElement classElement in classes) { | 260 for (ClassElement classElement in classes) { |
| 426 // Add the information that this class is a subtype of its supertypes. The | 261 // Add the information that this class is a subtype of its supertypes. The |
| 427 // code emitter and the ssa builder use that information. | 262 // code emitter and the ssa builder use that information. |
| 428 _addSubtypes(classElement, emitter.nativeEmitter); | 263 _addSubtypes(classElement, _emitter.nativeEmitter); |
| 429 } | 264 } |
| 430 } | 265 } |
| 431 | 266 |
| 432 void _addSubtypes(ClassElement cls, NativeEmitter emitter) { | 267 void _addSubtypes(ClassElement cls, NativeEmitter emitter) { |
| 433 if (!_nativeData.isNativeClass(cls)) return; | 268 if (!_nativeData.isNativeClass(cls)) return; |
| 434 if (doneAddSubtypes.contains(cls)) return; | 269 if (_doneAddSubtypes.contains(cls)) return; |
| 435 doneAddSubtypes.add(cls); | 270 _doneAddSubtypes.add(cls); |
| 436 | 271 |
| 437 // Walk the superclass chain since classes on the superclass chain might not | 272 // Walk the superclass chain since classes on the superclass chain might not |
| 438 // be instantiated (abstract or simply unused). | 273 // be instantiated (abstract or simply unused). |
| 439 _addSubtypes(cls.superclass, emitter); | 274 _addSubtypes(cls.superclass, emitter); |
| 440 | 275 |
| 441 for (ResolutionInterfaceType type in cls.allSupertypes) { | 276 for (ResolutionInterfaceType type in cls.allSupertypes) { |
| 442 List<ClassEntity> subtypes = | 277 List<ClassEntity> subtypes = |
| 443 emitter.subtypes.putIfAbsent(type.element, () => <ClassEntity>[]); | 278 emitter.subtypes.putIfAbsent(type.element, () => <ClassEntity>[]); |
| 444 subtypes.add(cls); | 279 subtypes.add(cls); |
| 445 } | 280 } |
| (...skipping 10 matching lines...) Expand all Loading... |
| 456 List<ClassEntity> directSubtypes = | 291 List<ClassEntity> directSubtypes = |
| 457 emitter.directSubtypes.putIfAbsent(superclass, () => <ClassEntity>[]); | 292 emitter.directSubtypes.putIfAbsent(superclass, () => <ClassEntity>[]); |
| 458 directSubtypes.add(cls); | 293 directSubtypes.add(cls); |
| 459 } | 294 } |
| 460 | 295 |
| 461 void logSummary(log(message)) { | 296 void logSummary(log(message)) { |
| 462 log('Compiled ${_registeredClasses.length} native classes, ' | 297 log('Compiled ${_registeredClasses.length} native classes, ' |
| 463 '${_unusedClasses.length} native classes omitted.'); | 298 '${_unusedClasses.length} native classes omitted.'); |
| 464 } | 299 } |
| 465 } | 300 } |
| OLD | NEW |