| 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 part of native; | 5 part of native; |
| 6 | 6 |
| 7 /** | 7 /** |
| 8 * This could be an abstract class but we use it as a stub for the dart_backend. | 8 * This could be an abstract class but we use it as a stub for the dart_backend. |
| 9 */ | 9 */ |
| 10 class NativeEnqueuer { | 10 class NativeEnqueuer { |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 113 processSubclassesOfNativeClasses(libraries); | 113 processSubclassesOfNativeClasses(libraries); |
| 114 if (!enableLiveTypeAnalysis) { | 114 if (!enableLiveTypeAnalysis) { |
| 115 nativeClasses.forEach((c) => enqueueClass(c, 'forced')); | 115 nativeClasses.forEach((c) => enqueueClass(c, 'forced')); |
| 116 flushQueue(); | 116 flushQueue(); |
| 117 } | 117 } |
| 118 } | 118 } |
| 119 | 119 |
| 120 void processNativeClassesInLibrary(LibraryElement library) { | 120 void processNativeClassesInLibrary(LibraryElement library) { |
| 121 // Use implementation to ensure the inclusion of injected members. | 121 // Use implementation to ensure the inclusion of injected members. |
| 122 library.implementation.forEachLocalMember((Element element) { | 122 library.implementation.forEachLocalMember((Element element) { |
| 123 if (element.isClass && element.isNative) { | 123 if (element.isClass && backend.isNative(element)) { |
| 124 processNativeClass(element); | 124 processNativeClass(element); |
| 125 } | 125 } |
| 126 }); | 126 }); |
| 127 } | 127 } |
| 128 | 128 |
| 129 void processNativeClass(ClassElement classElement) { | 129 void processNativeClass(ClassElement classElement) { |
| 130 nativeClasses.add(classElement); | 130 nativeClasses.add(classElement); |
| 131 unusedClasses.add(classElement); | 131 unusedClasses.add(classElement); |
| 132 // Resolve class to ensure the class has valid inheritance info. | 132 // Resolve class to ensure the class has valid inheritance info. |
| 133 classElement.ensureResolved(resolution); | 133 classElement.ensureResolved(resolution); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 155 } | 155 } |
| 156 } | 156 } |
| 157 }); | 157 }); |
| 158 }); | 158 }); |
| 159 | 159 |
| 160 // Resolve all the native classes and any classes that might extend them in | 160 // Resolve all the native classes and any classes that might extend them in |
| 161 // [potentialExtends], and then check that the properly resolved class is in | 161 // [potentialExtends], and then check that the properly resolved class is in |
| 162 // fact a subclass of a native class. | 162 // fact a subclass of a native class. |
| 163 | 163 |
| 164 ClassElement nativeSuperclassOf(ClassElement classElement) { | 164 ClassElement nativeSuperclassOf(ClassElement classElement) { |
| 165 if (classElement.isNative) return classElement; | 165 if (backend.isNative(classElement)) return classElement; |
| 166 if (classElement.superclass == null) return null; | 166 if (classElement.superclass == null) return null; |
| 167 return nativeSuperclassOf(classElement.superclass); | 167 return nativeSuperclassOf(classElement.superclass); |
| 168 } | 168 } |
| 169 | 169 |
| 170 void walkPotentialSubclasses(ClassElement element) { | 170 void walkPotentialSubclasses(ClassElement element) { |
| 171 if (nativeClassesAndSubclasses.contains(element)) return; | 171 if (nativeClassesAndSubclasses.contains(element)) return; |
| 172 element.ensureResolved(resolution); | 172 element.ensureResolved(resolution); |
| 173 ClassElement nativeSuperclass = nativeSuperclassOf(element); | 173 ClassElement nativeSuperclass = nativeSuperclassOf(element); |
| 174 if (nativeSuperclass != null) { | 174 if (nativeSuperclass != null) { |
| 175 nativeClassesAndSubclasses.add(element); | 175 nativeClassesAndSubclasses.add(element); |
| 176 if (!element.isNative) { | 176 if (!backend.isNative(element)) { |
| 177 nonNativeSubclasses.putIfAbsent(nativeSuperclass, | 177 nonNativeSubclasses.putIfAbsent(nativeSuperclass, |
| 178 () => new Set<ClassElement>()) | 178 () => new Set<ClassElement>()) |
| 179 .add(element); | 179 .add(element); |
| 180 } | 180 } |
| 181 Set<ClassElement> potentialSubclasses = potentialExtends[element.name]; | 181 Set<ClassElement> potentialSubclasses = potentialExtends[element.name]; |
| 182 if (potentialSubclasses != null) { | 182 if (potentialSubclasses != null) { |
| 183 potentialSubclasses.forEach(walkPotentialSubclasses); | 183 potentialSubclasses.forEach(walkPotentialSubclasses); |
| 184 } | 184 } |
| 185 } | 185 } |
| 186 } | 186 } |
| (...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 343 | 343 |
| 344 if (firstTime) { | 344 if (firstTime) { |
| 345 queue.add(onFirstNativeClass); | 345 queue.add(onFirstNativeClass); |
| 346 } | 346 } |
| 347 } | 347 } |
| 348 | 348 |
| 349 registerElement(Element element) { | 349 registerElement(Element element) { |
| 350 reporter.withCurrentElement(element, () { | 350 reporter.withCurrentElement(element, () { |
| 351 if (element.isFunction || element.isGetter || element.isSetter) { | 351 if (element.isFunction || element.isGetter || element.isSetter) { |
| 352 handleMethodAnnotations(element); | 352 handleMethodAnnotations(element); |
| 353 if (element.isNative) { | 353 if (backend.isNative(element)) { |
| 354 registerMethodUsed(element); | 354 registerMethodUsed(element); |
| 355 } | 355 } |
| 356 } else if (element.isField) { | 356 } else if (element.isField) { |
| 357 handleFieldAnnotations(element); | 357 handleFieldAnnotations(element); |
| 358 if (element.isNative) { | 358 if (backend.isNative(element)) { |
| 359 registerFieldLoad(element); | 359 registerFieldLoad(element); |
| 360 registerFieldStore(element); | 360 registerFieldStore(element); |
| 361 } | 361 } |
| 362 } | 362 } |
| 363 }); | 363 }); |
| 364 } | 364 } |
| 365 | 365 |
| 366 handleFieldAnnotations(Element element) { | 366 handleFieldAnnotations(Element element) { |
| 367 if (element.enclosingElement.isNative) { | 367 if (backend.isNative(element.enclosingElement)) { |
| 368 // Exclude non-instance (static) fields - they not really native and are | 368 // Exclude non-instance (static) fields - they not really native and are |
| 369 // compiled as isolate globals. Access of a property of a constructor | 369 // compiled as isolate globals. Access of a property of a constructor |
| 370 // function or a non-method property in the prototype chain, must be coded | 370 // function or a non-method property in the prototype chain, must be coded |
| 371 // using a JS-call. | 371 // using a JS-call. |
| 372 if (element.isInstanceMember) { | 372 if (element.isInstanceMember) { |
| 373 setNativeName(element); | 373 setNativeName(element); |
| 374 } | 374 } |
| 375 } | 375 } |
| 376 } | 376 } |
| 377 | 377 |
| 378 handleMethodAnnotations(Element method) { | 378 handleMethodAnnotations(Element method) { |
| 379 if (isNativeMethod(method)) { | 379 if (isNativeMethod(method)) { |
| 380 if (method.isStatic) { | 380 if (method.isStatic) { |
| 381 setNativeNameForStaticMethod(method); | 381 setNativeNameForStaticMethod(method); |
| 382 } else { | 382 } else { |
| 383 setNativeName(method); | 383 setNativeName(method); |
| 384 } | 384 } |
| 385 } | 385 } |
| 386 } | 386 } |
| 387 | 387 |
| 388 /// Sets the native name of [element], either from an annotation, or | 388 /// Sets the native name of [element], either from an annotation, or |
| 389 /// defaulting to the Dart name. | 389 /// defaulting to the Dart name. |
| 390 void setNativeName(ElementX element) { | 390 void setNativeName(MemberElement element) { |
| 391 String name = findJsNameFromAnnotation(element); | 391 String name = findJsNameFromAnnotation(element); |
| 392 if (name == null) name = element.name; | 392 if (name == null) name = element.name; |
| 393 element.setNative(name); | 393 backend.setNativeMemberName(element, name); |
| 394 } | 394 } |
| 395 | 395 |
| 396 /// Sets the native name of the static native method [element], using the | 396 /// Sets the native name of the static native method [element], using the |
| 397 /// following rules: | 397 /// following rules: |
| 398 /// 1. If [element] has a @JSName annotation that is an identifier, qualify | 398 /// 1. If [element] has a @JSName annotation that is an identifier, qualify |
| 399 /// that identifier to the @Native name of the enclosing class | 399 /// that identifier to the @Native name of the enclosing class |
| 400 /// 2. If [element] has a @JSName annotation that is not an identifier, | 400 /// 2. If [element] has a @JSName annotation that is not an identifier, |
| 401 /// use the declared @JSName as the expression | 401 /// use the declared @JSName as the expression |
| 402 /// 3. If [element] does not have a @JSName annotation, qualify the name of | 402 /// 3. If [element] does not have a @JSName annotation, qualify the name of |
| 403 /// the method with the @Native name of the enclosing class. | 403 /// the method with the @Native name of the enclosing class. |
| 404 void setNativeNameForStaticMethod(ElementX element) { | 404 void setNativeNameForStaticMethod(MethodElement element) { |
| 405 String name = findJsNameFromAnnotation(element); | 405 String name = findJsNameFromAnnotation(element); |
| 406 if (name == null) name = element.name; | 406 if (name == null) name = element.name; |
| 407 if (isIdentifier(name)) { | 407 if (isIdentifier(name)) { |
| 408 List<String> nativeNames = nativeTagsOfClassRaw(element.enclosingClass); | 408 List<String> nativeNames = |
| 409 backend.getNativeTagsOfClassRaw(element.enclosingClass); |
| 409 if (nativeNames.length != 1) { | 410 if (nativeNames.length != 1) { |
| 410 reporter.internalError(element, | 411 reporter.internalError(element, |
| 411 'Unable to determine a native name for the enclosing class, ' | 412 'Unable to determine a native name for the enclosing class, ' |
| 412 'options: $nativeNames'); | 413 'options: $nativeNames'); |
| 413 } | 414 } |
| 414 element.setNative('${nativeNames[0]}.$name'); | 415 backend.setNativeMemberName(element, '${nativeNames[0]}.$name'); |
| 415 } else { | 416 } else { |
| 416 element.setNative(name); | 417 backend.setNativeMemberName(element, name); |
| 417 } | 418 } |
| 418 } | 419 } |
| 419 | 420 |
| 420 bool isIdentifier(String s) => _identifier.hasMatch(s); | 421 bool isIdentifier(String s) => _identifier.hasMatch(s); |
| 421 | 422 |
| 422 bool isNativeMethod(FunctionElementX element) { | 423 bool isNativeMethod(FunctionElementX element) { |
| 423 if (!element.library.canUseNative) return false; | 424 if (!backend.canLibraryUseNative(element.library)) return false; |
| 424 // Native method? | 425 // Native method? |
| 425 return reporter.withCurrentElement(element, () { | 426 return reporter.withCurrentElement(element, () { |
| 426 Node node = element.parseNode(resolution.parsing); | 427 Node node = element.parseNode(resolution.parsing); |
| 427 if (node is! FunctionExpression) return false; | 428 if (node is! FunctionExpression) return false; |
| 428 FunctionExpression functionExpression = node; | 429 FunctionExpression functionExpression = node; |
| 429 node = functionExpression.body; | 430 node = functionExpression.body; |
| 430 Token token = node.getBeginToken(); | 431 Token token = node.getBeginToken(); |
| 431 if (identical(token.stringValue, 'native')) return true; | 432 if (identical(token.stringValue, 'native')) return true; |
| 432 return false; | 433 return false; |
| 433 }); | 434 }); |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 538 | 539 |
| 539 Map<String, ClassElement> tagOwner = new Map<String, ClassElement>(); | 540 Map<String, ClassElement> tagOwner = new Map<String, ClassElement>(); |
| 540 | 541 |
| 541 NativeResolutionEnqueuer(Enqueuer world, Compiler compiler) | 542 NativeResolutionEnqueuer(Enqueuer world, Compiler compiler) |
| 542 : super(world, compiler, compiler.enableNativeLiveTypeAnalysis); | 543 : super(world, compiler, compiler.enableNativeLiveTypeAnalysis); |
| 543 | 544 |
| 544 void processNativeClass(ClassElement classElement) { | 545 void processNativeClass(ClassElement classElement) { |
| 545 super.processNativeClass(classElement); | 546 super.processNativeClass(classElement); |
| 546 | 547 |
| 547 // Js Interop interfaces do not have tags. | 548 // Js Interop interfaces do not have tags. |
| 548 if (classElement.isJsInterop) return; | 549 if (backend.isJsInterop(classElement)) return; |
| 549 // Since we map from dispatch tags to classes, a dispatch tag must be used | 550 // Since we map from dispatch tags to classes, a dispatch tag must be used |
| 550 // on only one native class. | 551 // on only one native class. |
| 551 for (String tag in nativeTagsOfClass(classElement)) { | 552 for (String tag in backend.getNativeTagsOfClass(classElement)) { |
| 552 ClassElement owner = tagOwner[tag]; | 553 ClassElement owner = tagOwner[tag]; |
| 553 if (owner != null) { | 554 if (owner != null) { |
| 554 if (owner != classElement) { | 555 if (owner != classElement) { |
| 555 reporter.internalError( | 556 reporter.internalError( |
| 556 classElement, "Tag '$tag' already in use by '${owner.name}'"); | 557 classElement, "Tag '$tag' already in use by '${owner.name}'"); |
| 557 } | 558 } |
| 558 } else { | 559 } else { |
| 559 tagOwner[tag] = classElement; | 560 tagOwner[tag] = classElement; |
| 560 } | 561 } |
| 561 } | 562 } |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 641 } | 642 } |
| 642 | 643 |
| 643 processClass(ClassElement classElement, cause) { | 644 processClass(ClassElement classElement, cause) { |
| 644 super.processClass(classElement, cause); | 645 super.processClass(classElement, cause); |
| 645 // Add the information that this class is a subtype of its supertypes. The | 646 // Add the information that this class is a subtype of its supertypes. The |
| 646 // code emitter and the ssa builder use that information. | 647 // code emitter and the ssa builder use that information. |
| 647 addSubtypes(classElement, emitter.nativeEmitter); | 648 addSubtypes(classElement, emitter.nativeEmitter); |
| 648 } | 649 } |
| 649 | 650 |
| 650 void addSubtypes(ClassElement cls, NativeEmitter emitter) { | 651 void addSubtypes(ClassElement cls, NativeEmitter emitter) { |
| 651 if (!cls.isNative) return; | 652 if (!backend.isNative(cls)) return; |
| 652 if (doneAddSubtypes.contains(cls)) return; | 653 if (doneAddSubtypes.contains(cls)) return; |
| 653 doneAddSubtypes.add(cls); | 654 doneAddSubtypes.add(cls); |
| 654 | 655 |
| 655 // Walk the superclass chain since classes on the superclass chain might not | 656 // Walk the superclass chain since classes on the superclass chain might not |
| 656 // be instantiated (abstract or simply unused). | 657 // be instantiated (abstract or simply unused). |
| 657 addSubtypes(cls.superclass, emitter); | 658 addSubtypes(cls.superclass, emitter); |
| 658 | 659 |
| 659 for (DartType type in cls.allSupertypes) { | 660 for (DartType type in cls.allSupertypes) { |
| 660 List<Element> subtypes = emitter.subtypes.putIfAbsent( | 661 List<Element> subtypes = emitter.subtypes.putIfAbsent( |
| 661 type.element, | 662 type.element, |
| 662 () => <ClassElement>[]); | 663 () => <ClassElement>[]); |
| 663 subtypes.add(cls); | 664 subtypes.add(cls); |
| 664 } | 665 } |
| 665 | 666 |
| 666 // Skip through all the mixin applications in the super class | 667 // Skip through all the mixin applications in the super class |
| 667 // chain. That way, the direct subtypes set only contain the | 668 // chain. That way, the direct subtypes set only contain the |
| 668 // natives classes. | 669 // natives classes. |
| 669 ClassElement superclass = cls.superclass; | 670 ClassElement superclass = cls.superclass; |
| 670 while (superclass != null && superclass.isMixinApplication) { | 671 while (superclass != null && superclass.isMixinApplication) { |
| 671 assert(!superclass.isNative); | 672 assert(!backend.isNative(superclass)); |
| 672 superclass = superclass.superclass; | 673 superclass = superclass.superclass; |
| 673 } | 674 } |
| 674 | 675 |
| 675 List<Element> directSubtypes = emitter.directSubtypes.putIfAbsent( | 676 List<Element> directSubtypes = emitter.directSubtypes.putIfAbsent( |
| 676 superclass, | 677 superclass, |
| 677 () => <ClassElement>[]); | 678 () => <ClassElement>[]); |
| 678 directSubtypes.add(cls); | 679 directSubtypes.add(cls); |
| 679 } | 680 } |
| 680 | 681 |
| 681 void logSummary(log(message)) { | 682 void logSummary(log(message)) { |
| 682 log('Compiled ${registeredClasses.length} native classes, ' | 683 log('Compiled ${registeredClasses.length} native classes, ' |
| 683 '${unusedClasses.length} native classes omitted.'); | 684 '${unusedClasses.length} native classes omitted.'); |
| 684 } | 685 } |
| 685 } | 686 } |
| OLD | NEW |