| 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 '../common.dart'; | 5 import '../common.dart'; |
| 6 import '../common/backend_api.dart' show ForeignResolver; | 6 import '../common/backend_api.dart' show ForeignResolver; |
| 7 import '../common/resolution.dart' show Resolution; | 7 import '../common/resolution.dart' show Resolution; |
| 8 import '../compiler.dart' show Compiler; | 8 import '../compiler.dart' show Compiler; |
| 9 import '../constants/values.dart'; | 9 import '../constants/values.dart'; |
| 10 import '../common_elements.dart' show CommonElements; | 10 import '../common_elements.dart' show CommonElements; |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 107 } | 107 } |
| 108 processSubclassesOfNativeClasses(libraries); | 108 processSubclassesOfNativeClasses(libraries); |
| 109 if (!enableLiveTypeAnalysis) { | 109 if (!enableLiveTypeAnalysis) { |
| 110 _registerTypeUses(impactBuilder, _nativeClasses, 'forced'); | 110 _registerTypeUses(impactBuilder, _nativeClasses, 'forced'); |
| 111 } | 111 } |
| 112 } | 112 } |
| 113 | 113 |
| 114 void processNativeClassesInLibrary(LibraryElement library) { | 114 void processNativeClassesInLibrary(LibraryElement library) { |
| 115 // Use implementation to ensure the inclusion of injected members. | 115 // Use implementation to ensure the inclusion of injected members. |
| 116 library.implementation.forEachLocalMember((Element element) { | 116 library.implementation.forEachLocalMember((Element element) { |
| 117 if (element.isClass && backend.isNative(element)) { | 117 if (element.isClass) { |
| 118 processNativeClass(element); | 118 ClassElement cls = element; |
| 119 if (backend.nativeData.isNativeClass(cls)) { |
| 120 processNativeClass(element); |
| 121 } |
| 119 } | 122 } |
| 120 }); | 123 }); |
| 121 } | 124 } |
| 122 | 125 |
| 123 void processNativeClass(ClassElement classElement) { | 126 void processNativeClass(ClassElement classElement) { |
| 124 _nativeClasses.add(classElement); | 127 _nativeClasses.add(classElement); |
| 125 _unusedClasses.add(classElement); | 128 _unusedClasses.add(classElement); |
| 126 // Resolve class to ensure the class has valid inheritance info. | 129 // Resolve class to ensure the class has valid inheritance info. |
| 127 classElement.ensureResolved(resolution); | 130 classElement.ensureResolved(resolution); |
| 128 } | 131 } |
| (...skipping 18 matching lines...) Expand all Loading... |
| 147 } | 150 } |
| 148 } | 151 } |
| 149 }); | 152 }); |
| 150 }); | 153 }); |
| 151 | 154 |
| 152 // Resolve all the native classes and any classes that might extend them in | 155 // Resolve all the native classes and any classes that might extend them in |
| 153 // [potentialExtends], and then check that the properly resolved class is in | 156 // [potentialExtends], and then check that the properly resolved class is in |
| 154 // fact a subclass of a native class. | 157 // fact a subclass of a native class. |
| 155 | 158 |
| 156 ClassElement nativeSuperclassOf(ClassElement classElement) { | 159 ClassElement nativeSuperclassOf(ClassElement classElement) { |
| 157 if (backend.isNative(classElement)) return classElement; | 160 if (backend.nativeData.isNativeClass(classElement)) return classElement; |
| 158 if (classElement.superclass == null) return null; | 161 if (classElement.superclass == null) return null; |
| 159 return nativeSuperclassOf(classElement.superclass); | 162 return nativeSuperclassOf(classElement.superclass); |
| 160 } | 163 } |
| 161 | 164 |
| 162 void walkPotentialSubclasses(ClassElement element) { | 165 void walkPotentialSubclasses(ClassElement element) { |
| 163 if (nativeClassesAndSubclasses.contains(element)) return; | 166 if (nativeClassesAndSubclasses.contains(element)) return; |
| 164 element.ensureResolved(resolution); | 167 element.ensureResolved(resolution); |
| 165 ClassElement nativeSuperclass = nativeSuperclassOf(element); | 168 ClassElement nativeSuperclass = nativeSuperclassOf(element); |
| 166 if (nativeSuperclass != null) { | 169 if (nativeSuperclass != null) { |
| 167 nativeClassesAndSubclasses.add(element); | 170 nativeClassesAndSubclasses.add(element); |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 292 cls.ensureResolved(resolution); | 295 cls.ensureResolved(resolution); |
| 293 impactBuilder | 296 impactBuilder |
| 294 .registerTypeUse(new TypeUse.nativeInstantiation(cls.rawType)); | 297 .registerTypeUse(new TypeUse.nativeInstantiation(cls.rawType)); |
| 295 } | 298 } |
| 296 } | 299 } |
| 297 | 300 |
| 298 void handleFieldAnnotations(Element element) { | 301 void handleFieldAnnotations(Element element) { |
| 299 if (compiler.serialization.isDeserialized(element)) { | 302 if (compiler.serialization.isDeserialized(element)) { |
| 300 return; | 303 return; |
| 301 } | 304 } |
| 302 if (backend.isNative(element.enclosingElement)) { | 305 if (element.isInstanceMember && |
| 303 // Exclude non-instance (static) fields - they not really native and are | 306 backend.nativeData.isNativeClass(element.enclosingClass)) { |
| 304 // compiled as isolate globals. Access of a property of a constructor | 307 // Exclude non-instance (static) fields - they are not really native and |
| 308 // are compiled as isolate globals. Access of a property of a constructor |
| 305 // function or a non-method property in the prototype chain, must be coded | 309 // function or a non-method property in the prototype chain, must be coded |
| 306 // using a JS-call. | 310 // using a JS-call. |
| 307 if (element.isInstanceMember) { | 311 _setNativeName(element); |
| 308 _setNativeName(element); | |
| 309 } | |
| 310 } | 312 } |
| 311 } | 313 } |
| 312 | 314 |
| 313 void handleMethodAnnotations(Element method) { | 315 void handleMethodAnnotations(Element method) { |
| 314 if (compiler.serialization.isDeserialized(method)) { | 316 if (compiler.serialization.isDeserialized(method)) { |
| 315 return; | 317 return; |
| 316 } | 318 } |
| 317 if (isNativeMethod(method)) { | 319 if (isNativeMethod(method)) { |
| 318 if (method.isStatic) { | 320 if (method.isStatic) { |
| 319 _setNativeNameForStaticMethod(method); | 321 _setNativeNameForStaticMethod(method); |
| 320 } else { | 322 } else { |
| 321 _setNativeName(method); | 323 _setNativeName(method); |
| 322 } | 324 } |
| 323 } | 325 } |
| 324 } | 326 } |
| 325 | 327 |
| 326 /// Sets the native name of [element], either from an annotation, or | 328 /// Sets the native name of [element], either from an annotation, or |
| 327 /// defaulting to the Dart name. | 329 /// defaulting to the Dart name. |
| 328 void _setNativeName(MemberElement element) { | 330 void _setNativeName(MemberElement element) { |
| 329 String name = findJsNameFromAnnotation(element); | 331 String name = findJsNameFromAnnotation(element); |
| 330 if (name == null) name = element.name; | 332 if (name == null) name = element.name; |
| 331 backend.nativeData.setNativeMemberName(element, name); | 333 backend.nativeDataBuilder.setNativeMemberName(element, name); |
| 332 } | 334 } |
| 333 | 335 |
| 334 /// Sets the native name of the static native method [element], using the | 336 /// Sets the native name of the static native method [element], using the |
| 335 /// following rules: | 337 /// following rules: |
| 336 /// 1. If [element] has a @JSName annotation that is an identifier, qualify | 338 /// 1. If [element] has a @JSName annotation that is an identifier, qualify |
| 337 /// that identifier to the @Native name of the enclosing class | 339 /// that identifier to the @Native name of the enclosing class |
| 338 /// 2. If [element] has a @JSName annotation that is not an identifier, | 340 /// 2. If [element] has a @JSName annotation that is not an identifier, |
| 339 /// use the declared @JSName as the expression | 341 /// use the declared @JSName as the expression |
| 340 /// 3. If [element] does not have a @JSName annotation, qualify the name of | 342 /// 3. If [element] does not have a @JSName annotation, qualify the name of |
| 341 /// the method with the @Native name of the enclosing class. | 343 /// the method with the @Native name of the enclosing class. |
| 342 void _setNativeNameForStaticMethod(MethodElement element) { | 344 void _setNativeNameForStaticMethod(MethodElement element) { |
| 343 String name = findJsNameFromAnnotation(element); | 345 String name = findJsNameFromAnnotation(element); |
| 344 if (name == null) name = element.name; | 346 if (name == null) name = element.name; |
| 345 if (isIdentifier(name)) { | 347 if (isIdentifier(name)) { |
| 346 List<String> nativeNames = | 348 List<String> nativeNames = backend.nativeDataBuilder |
| 347 backend.nativeData.getNativeTagsOfClassRaw(element.enclosingClass); | 349 .getNativeTagsOfClassRaw(element.enclosingClass); |
| 348 if (nativeNames.length != 1) { | 350 if (nativeNames.length != 1) { |
| 349 reporter.internalError( | 351 reporter.internalError( |
| 350 element, | 352 element, |
| 351 'Unable to determine a native name for the enclosing class, ' | 353 'Unable to determine a native name for the enclosing class, ' |
| 352 'options: $nativeNames'); | 354 'options: $nativeNames'); |
| 353 } | 355 } |
| 354 backend.nativeData | 356 backend.nativeDataBuilder |
| 355 .setNativeMemberName(element, '${nativeNames[0]}.$name'); | 357 .setNativeMemberName(element, '${nativeNames[0]}.$name'); |
| 356 } else { | 358 } else { |
| 357 backend.nativeData.setNativeMemberName(element, name); | 359 backend.nativeDataBuilder.setNativeMemberName(element, name); |
| 358 } | 360 } |
| 359 } | 361 } |
| 360 | 362 |
| 361 bool isIdentifier(String s) => _identifier.hasMatch(s); | 363 bool isIdentifier(String s) => _identifier.hasMatch(s); |
| 362 | 364 |
| 363 bool isNativeMethod(FunctionElementX element) { | 365 bool isNativeMethod(FunctionElementX element) { |
| 364 if (!backend.canLibraryUseNative(element.library)) return false; | 366 if (!backend.canLibraryUseNative(element.library)) return false; |
| 365 // Native method? | 367 // Native method? |
| 366 return reporter.withCurrentElement(element, () { | 368 return reporter.withCurrentElement(element, () { |
| 367 Node node = element.parseNode(resolution.parsingContext); | 369 Node node = element.parseNode(resolution.parsingContext); |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 478 | 480 |
| 479 void registerBackendUse(MethodElement element) { | 481 void registerBackendUse(MethodElement element) { |
| 480 _backendUsageBuilder.registerBackendFunctionUse(element); | 482 _backendUsageBuilder.registerBackendFunctionUse(element); |
| 481 _backendUsageBuilder.registerGlobalFunctionDependency(element); | 483 _backendUsageBuilder.registerGlobalFunctionDependency(element); |
| 482 } | 484 } |
| 483 | 485 |
| 484 void processNativeClass(ClassElement classElement) { | 486 void processNativeClass(ClassElement classElement) { |
| 485 super.processNativeClass(classElement); | 487 super.processNativeClass(classElement); |
| 486 | 488 |
| 487 // Js Interop interfaces do not have tags. | 489 // Js Interop interfaces do not have tags. |
| 488 if (backend.isJsInterop(classElement)) return; | 490 if (backend.nativeData.isJsInterop(classElement)) return; |
| 489 // Since we map from dispatch tags to classes, a dispatch tag must be used | 491 // Since we map from dispatch tags to classes, a dispatch tag must be used |
| 490 // on only one native class. | 492 // on only one native class. |
| 491 for (String tag in backend.nativeData.getNativeTagsOfClass(classElement)) { | 493 for (String tag in backend.nativeData.getNativeTagsOfClass(classElement)) { |
| 492 ClassElement owner = tagOwner[tag]; | 494 ClassElement owner = tagOwner[tag]; |
| 493 if (owner != null) { | 495 if (owner != null) { |
| 494 if (owner != classElement) { | 496 if (owner != classElement) { |
| 495 reporter.internalError( | 497 reporter.internalError( |
| 496 classElement, "Tag '$tag' already in use by '${owner.name}'"); | 498 classElement, "Tag '$tag' already in use by '${owner.name}'"); |
| 497 } | 499 } |
| 498 } else { | 500 } else { |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 581 super._registerTypeUses(impactBuilder, classes, cause); | 583 super._registerTypeUses(impactBuilder, classes, cause); |
| 582 | 584 |
| 583 for (ClassElement classElement in classes) { | 585 for (ClassElement classElement in classes) { |
| 584 // Add the information that this class is a subtype of its supertypes. The | 586 // Add the information that this class is a subtype of its supertypes. The |
| 585 // code emitter and the ssa builder use that information. | 587 // code emitter and the ssa builder use that information. |
| 586 _addSubtypes(classElement, emitter.nativeEmitter); | 588 _addSubtypes(classElement, emitter.nativeEmitter); |
| 587 } | 589 } |
| 588 } | 590 } |
| 589 | 591 |
| 590 void _addSubtypes(ClassElement cls, NativeEmitter emitter) { | 592 void _addSubtypes(ClassElement cls, NativeEmitter emitter) { |
| 591 if (!backend.isNative(cls)) return; | 593 if (!backend.nativeData.isNativeClass(cls)) return; |
| 592 if (doneAddSubtypes.contains(cls)) return; | 594 if (doneAddSubtypes.contains(cls)) return; |
| 593 doneAddSubtypes.add(cls); | 595 doneAddSubtypes.add(cls); |
| 594 | 596 |
| 595 // Walk the superclass chain since classes on the superclass chain might not | 597 // Walk the superclass chain since classes on the superclass chain might not |
| 596 // be instantiated (abstract or simply unused). | 598 // be instantiated (abstract or simply unused). |
| 597 _addSubtypes(cls.superclass, emitter); | 599 _addSubtypes(cls.superclass, emitter); |
| 598 | 600 |
| 599 for (ResolutionInterfaceType type in cls.allSupertypes) { | 601 for (ResolutionInterfaceType type in cls.allSupertypes) { |
| 600 List<ClassEntity> subtypes = | 602 List<ClassEntity> subtypes = |
| 601 emitter.subtypes.putIfAbsent(type.element, () => <ClassEntity>[]); | 603 emitter.subtypes.putIfAbsent(type.element, () => <ClassEntity>[]); |
| 602 subtypes.add(cls); | 604 subtypes.add(cls); |
| 603 } | 605 } |
| 604 | 606 |
| 605 // Skip through all the mixin applications in the super class | 607 // Skip through all the mixin applications in the super class |
| 606 // chain. That way, the direct subtypes set only contain the | 608 // chain. That way, the direct subtypes set only contain the |
| 607 // natives classes. | 609 // natives classes. |
| 608 ClassElement superclass = cls.superclass; | 610 ClassElement superclass = cls.superclass; |
| 609 while (superclass != null && superclass.isMixinApplication) { | 611 while (superclass != null && superclass.isMixinApplication) { |
| 610 assert(!backend.isNative(superclass)); | 612 assert(!backend.nativeData.isNativeClass(superclass)); |
| 611 superclass = superclass.superclass; | 613 superclass = superclass.superclass; |
| 612 } | 614 } |
| 613 | 615 |
| 614 List<ClassEntity> directSubtypes = | 616 List<ClassEntity> directSubtypes = |
| 615 emitter.directSubtypes.putIfAbsent(superclass, () => <ClassEntity>[]); | 617 emitter.directSubtypes.putIfAbsent(superclass, () => <ClassEntity>[]); |
| 616 directSubtypes.add(cls); | 618 directSubtypes.add(cls); |
| 617 } | 619 } |
| 618 | 620 |
| 619 void logSummary(log(message)) { | 621 void logSummary(log(message)) { |
| 620 log('Compiled ${_registeredClasses.length} native classes, ' | 622 log('Compiled ${_registeredClasses.length} native classes, ' |
| 621 '${_unusedClasses.length} native classes omitted.'); | 623 '${_unusedClasses.length} native classes omitted.'); |
| 622 } | 624 } |
| 623 } | 625 } |
| OLD | NEW |