Chromium Code Reviews| Index: sdk/lib/_internal/compiler/implementation/native_handler.dart |
| diff --git a/sdk/lib/_internal/compiler/implementation/native_handler.dart b/sdk/lib/_internal/compiler/implementation/native_handler.dart |
| index ee8c27794ef7da39997b42f1e5275e55de82eb3c..124c173dd0ea642af88b82047b89608865fb6639 100644 |
| --- a/sdk/lib/_internal/compiler/implementation/native_handler.dart |
| +++ b/sdk/lib/_internal/compiler/implementation/native_handler.dart |
| @@ -35,15 +35,18 @@ class NativeEnqueuer { |
| /// Initial entry point to native enqueuer. |
| void processNativeClasses(Collection<LibraryElement> libraries) {} |
| + /// Notification of a main Enqueuer worklist element. For methods, adds |
| + /// information from metadata attributes, and computes types instantiated due |
| + /// to calling the method. |
| void registerElement(Element element) {} |
| - /// Method is a member of a native class. |
| - void registerMethod(Element method) {} |
| + /// Notification of native field. Adds information from metadata attributes. |
| + void registerField(Element field) {} |
| - /// Compute types instantiated due to getting a native field. |
| + /// Computes types instantiated due to getting a native field. |
| void registerFieldLoad(Element field) {} |
| - /// Compute types instantiated due to setting a native field. |
| + /// Computes types instantiated due to setting a native field. |
| void registerFieldStore(Element field) {} |
| /** |
| @@ -93,6 +96,7 @@ abstract class NativeEnqueuerBase implements NativeEnqueuer { |
| ClassElement _annotationCreatesClass; |
| ClassElement _annotationReturnsClass; |
| + ClassElement _annotationJsNameClass; |
| /// Subclasses of [NativeEnqueuerBase] are constructed by the backend. |
| NativeEnqueuerBase(this.world, this.compiler, this.enableLiveTypeAnalysis); |
| @@ -122,16 +126,22 @@ abstract class NativeEnqueuerBase implements NativeEnqueuer { |
| } |
| ClassElement get annotationCreatesClass { |
| - if (_annotationCreatesClass == null) findAnnotationClasses(); |
| + findAnnotationClasses(); |
| return _annotationCreatesClass; |
| } |
| ClassElement get annotationReturnsClass { |
| - if (_annotationReturnsClass == null) findAnnotationClasses(); |
| + findAnnotationClasses(); |
| return _annotationReturnsClass; |
| } |
| + ClassElement get annotationJsNameClass { |
| + findAnnotationClasses(); |
| + return _annotationJsNameClass; |
| + } |
| + |
| void findAnnotationClasses() { |
| + if (_annotationCreatesClass != null) return; |
| ClassElement find(name) { |
| Element e = compiler.findHelper(name); |
| if (e == null || e is! ClassElement) { |
| @@ -141,8 +151,41 @@ abstract class NativeEnqueuerBase implements NativeEnqueuer { |
| } |
| _annotationCreatesClass = find(const SourceString('Creates')); |
| _annotationReturnsClass = find(const SourceString('Returns')); |
| + _annotationJsNameClass = find(const SourceString('JSName')); |
| } |
| + /// Returns the JSName annotation string or `null` if no JSName annotation is |
| + /// present. |
| + String findJsNameFromAnnotation(Element element) { |
|
ahe
2012/11/29 09:19:26
This file should be deleted when we get rid of the
|
| + String name = null; |
| + ClassElement annotationClass = annotationJsNameClass; |
| + for (Link<MetadataAnnotation> link = element.metadata; |
| + !link.isEmpty; |
| + link = link.tail) { |
| + MetadataAnnotation annotation = link.head.ensureResolved(compiler); |
|
ahe
2012/11/29 09:19:26
I'm think we should make this an operation on elem
|
| + var value = annotation.value; |
| + if (value is! ConstructedConstant) continue; |
| + if (value.type is! InterfaceType) continue; |
| + if (!identical(value.type.element, annotationClass)) continue; |
| + |
| + var fields = value.fields; |
| + // TODO(sra): Better validation of the constant. |
|
ahe
2012/11/29 09:19:26
The constant will be validated in checked mode. W
|
| + if (fields.length != 1 || fields[0] is! StringConstant) { |
| + PartialMetadataAnnotation partial = annotation; |
| + compiler.cancel( |
| + 'Annotations needs one string: ${partial.parseNode(compiler)}'); |
|
ahe
2012/11/29 09:19:26
This should be:
compiler.internalError('Annotatio
sra1
2012/12/04 01:31:31
This would be sufficient for Issue 7007.
|
| + } |
| + String specString = fields[0].toDartString().slowToString(); |
| + if (name == null) { |
| + name = specString; |
| + } else { |
| + PartialMetadataAnnotation partial = annotation; |
| + compiler.cancel( |
| + 'Too many JSName annotations: ${partial.parseNode(compiler)}'); |
|
ahe
2012/11/29 09:19:26
Ditto.
|
| + } |
| + } |
| + return name; |
| + } |
| enqueueClass(ClassElement classElement, cause) { |
| assert(unusedClasses.contains(classElement)); |
| @@ -182,8 +225,15 @@ abstract class NativeEnqueuerBase implements NativeEnqueuer { |
| if (element.isFunction()) return registerMethod(element); |
| } |
| + registerField(Element element) { |
| + if (element.enclosingElement.isNative()) { |
| + setNativeName(element); |
| + } |
| + } |
| + |
| registerMethod(Element method) { |
| if (isNativeMethod(method)) { |
| + setNativeName(method); |
| processNativeBehavior( |
| NativeBehavior.ofMethod(method, compiler), |
| method); |
| @@ -191,6 +241,14 @@ abstract class NativeEnqueuerBase implements NativeEnqueuer { |
| } |
| } |
| + /// Sets the native name of [element], either from an annotation, or |
| + /// defaulting to the Dart name. |
| + void setNativeName(Element element) { |
| + String name = findJsNameFromAnnotation(element); |
| + if (name == null) name = element.name.slowToString(); |
| + element.setNative(name); |
| + } |
| + |
| bool isNativeMethod(Element element) { |
| if (!element.getLibrary().canUseNative) return false; |
| // Native method? |
| @@ -666,15 +724,15 @@ Token handleNativeFunctionBody(ElementListener listener, Token token) { |
| } |
| SourceString checkForNativeClass(ElementListener listener) { |
| - SourceString nativeName; |
| + SourceString nativeTagInfo; |
| Node node = listener.nodes.head; |
| if (node != null |
| && node.asIdentifier() != null |
| && node.asIdentifier().source.stringValue == 'native') { |
| - nativeName = node.asIdentifier().token.next.value; |
| + nativeTagInfo = node.asIdentifier().token.next.value; |
| listener.popNode(); |
| } |
| - return nativeName; |
| + return nativeTagInfo; |
| } |
| bool isOverriddenMethod(FunctionElement element, |
| @@ -693,7 +751,6 @@ final RegExp nativeRedirectionRegExp = new RegExp(r'^[a-zA-Z][a-zA-Z_$0-9]*$'); |
| void handleSsaNative(SsaBuilder builder, Expression nativeBody) { |
| Compiler compiler = builder.compiler; |
| FunctionElement element = builder.work.element; |
| - element.setNative(); |
| NativeEmitter nativeEmitter = builder.emitter.nativeEmitter; |
| // If what we're compiling is a getter named 'typeName' and the native |
| // class is named 'DOMType', we generate a call to the typeNameOf |
| @@ -723,22 +780,22 @@ void handleSsaNative(SsaBuilder builder, Expression nativeBody) { |
| } |
| // Check which pattern this native method follows: |
| - // 1) foo() native; hasBody = false, isRedirecting = false |
| - // 2) foo() native "bar"; hasBody = false, isRedirecting = true |
| - // 3) foo() native "return 42"; hasBody = true, isRedirecting = false |
| + // 1) foo() native; |
| + // hasBody = false, isRedirecting = false |
| + // 2) foo() native "bar"; |
| + // hasBody = false, isRedirecting = true, no longer supported. |
| + // 3) foo() native "return 42"; |
| + // hasBody = true, isRedirecting = false |
| bool hasBody = false; |
| - bool isRedirecting = false; |
| - String nativeMethodName = element.name.slowToString(); |
| + String nativeMethodName = element.nativeName(); |
| if (nativeBody != null) { |
| LiteralString jsCode = nativeBody.asLiteralString(); |
| String str = jsCode.dartString.slowToString(); |
| if (nativeRedirectionRegExp.hasMatch(str)) { |
| - nativeMethodName = str; |
| - isRedirecting = true; |
| - nativeEmitter.addRedirectingMethod(element, nativeMethodName); |
| - } else { |
| - hasBody = true; |
| + compiler.cancel("Deprecated syntax, use @JSName('name') instead.", |
| + node: nativeBody); |
| } |
| + hasBody = true; |
| } |
| if (!hasBody) { |