Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(552)

Side by Side Diff: sdk/lib/_internal/compiler/implementation/native_handler.dart

Issue 11416257: Revert "Add @JSName annotation for native fields and methods." (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, 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 library native; 5 library native;
6 6
7 import 'dart:uri'; 7 import 'dart:uri';
8 import 'dart2jslib.dart' hide SourceString; 8 import 'dart2jslib.dart' hide SourceString;
9 import 'elements/elements.dart'; 9 import 'elements/elements.dart';
10 import 'js_backend/js_backend.dart'; 10 import 'js_backend/js_backend.dart';
(...skipping 17 matching lines...) Expand all
28 } 28 }
29 29
30 30
31 /** 31 /**
32 * This could be an abstract class but we use it as a stub for the dart_backend. 32 * This could be an abstract class but we use it as a stub for the dart_backend.
33 */ 33 */
34 class NativeEnqueuer { 34 class NativeEnqueuer {
35 /// Initial entry point to native enqueuer. 35 /// Initial entry point to native enqueuer.
36 void processNativeClasses(Collection<LibraryElement> libraries) {} 36 void processNativeClasses(Collection<LibraryElement> libraries) {}
37 37
38 /// Notification of a main Enqueuer worklist element. For methods, adds
39 /// information from metadata attributes, and computes types instantiated due
40 /// to calling the method.
41 void registerElement(Element element) {} 38 void registerElement(Element element) {}
42 39
43 /// Notification of native field. Adds information from metadata attributes. 40 /// Method is a member of a native class.
44 void registerField(Element field) {} 41 void registerMethod(Element method) {}
45 42
46 /// Computes types instantiated due to getting a native field. 43 /// Compute types instantiated due to getting a native field.
47 void registerFieldLoad(Element field) {} 44 void registerFieldLoad(Element field) {}
48 45
49 /// Computes types instantiated due to setting a native field. 46 /// Compute types instantiated due to setting a native field.
50 void registerFieldStore(Element field) {} 47 void registerFieldStore(Element field) {}
51 48
52 /** 49 /**
53 * Handles JS-calls, which can be an instantiation point for types. 50 * Handles JS-calls, which can be an instantiation point for types.
54 * 51 *
55 * For example, the following code instantiates and returns native classes 52 * For example, the following code instantiates and returns native classes
56 * that are `_DOMWindowImpl` or a subtype. 53 * that are `_DOMWindowImpl` or a subtype.
57 * 54 *
58 * JS('_DOMWindowImpl', 'window') 55 * JS('_DOMWindowImpl', 'window')
59 * 56 *
(...skipping 29 matching lines...) Expand all
89 final queue = new Queue(); 86 final queue = new Queue();
90 bool flushing = false; 87 bool flushing = false;
91 88
92 89
93 final Enqueuer world; 90 final Enqueuer world;
94 final Compiler compiler; 91 final Compiler compiler;
95 final bool enableLiveTypeAnalysis; 92 final bool enableLiveTypeAnalysis;
96 93
97 ClassElement _annotationCreatesClass; 94 ClassElement _annotationCreatesClass;
98 ClassElement _annotationReturnsClass; 95 ClassElement _annotationReturnsClass;
99 ClassElement _annotationJsNameClass;
100 96
101 /// Subclasses of [NativeEnqueuerBase] are constructed by the backend. 97 /// Subclasses of [NativeEnqueuerBase] are constructed by the backend.
102 NativeEnqueuerBase(this.world, this.compiler, this.enableLiveTypeAnalysis); 98 NativeEnqueuerBase(this.world, this.compiler, this.enableLiveTypeAnalysis);
103 99
104 void processNativeClasses(Collection<LibraryElement> libraries) { 100 void processNativeClasses(Collection<LibraryElement> libraries) {
105 libraries.forEach(processNativeClassesInLibrary); 101 libraries.forEach(processNativeClassesInLibrary);
106 if (!enableLiveTypeAnalysis) { 102 if (!enableLiveTypeAnalysis) {
107 nativeClasses.forEach((c) => enqueueClass(c, 'forced')); 103 nativeClasses.forEach((c) => enqueueClass(c, 'forced'));
108 flushQueue(); 104 flushQueue();
109 } 105 }
110 } 106 }
111 107
112 void processNativeClassesInLibrary(LibraryElement library) { 108 void processNativeClassesInLibrary(LibraryElement library) {
113 // Use implementation to ensure the inclusion of injected members. 109 // Use implementation to ensure the inclusion of injected members.
114 library.implementation.forEachLocalMember((Element element) { 110 library.implementation.forEachLocalMember((Element element) {
115 if (element.kind == ElementKind.CLASS) { 111 if (element.kind == ElementKind.CLASS) {
116 ClassElement classElement = element; 112 ClassElement classElement = element;
117 if (classElement.isNative()) { 113 if (classElement.isNative()) {
118 nativeClasses.add(classElement); 114 nativeClasses.add(classElement);
119 unusedClasses.add(classElement); 115 unusedClasses.add(classElement);
120 116
121 // Resolve class to ensure the class has valid inheritance info. 117 // Resolve class to ensure the class has valid inheritance info.
122 classElement.ensureResolved(compiler); 118 classElement.ensureResolved(compiler);
123 } 119 }
124 } 120 }
125 }); 121 });
126 } 122 }
127 123
128 ClassElement get annotationCreatesClass { 124 ClassElement get annotationCreatesClass {
129 findAnnotationClasses(); 125 if (_annotationCreatesClass == null) findAnnotationClasses();
130 return _annotationCreatesClass; 126 return _annotationCreatesClass;
131 } 127 }
132 128
133 ClassElement get annotationReturnsClass { 129 ClassElement get annotationReturnsClass {
134 findAnnotationClasses(); 130 if (_annotationReturnsClass == null) findAnnotationClasses();
135 return _annotationReturnsClass; 131 return _annotationReturnsClass;
136 } 132 }
137 133
138 ClassElement get annotationJsNameClass {
139 findAnnotationClasses();
140 return _annotationJsNameClass;
141 }
142
143 void findAnnotationClasses() { 134 void findAnnotationClasses() {
144 if (_annotationCreatesClass != null) return;
145 ClassElement find(name) { 135 ClassElement find(name) {
146 Element e = compiler.findHelper(name); 136 Element e = compiler.findHelper(name);
147 if (e == null || e is! ClassElement) { 137 if (e == null || e is! ClassElement) {
148 compiler.cancel("Could not find implementation class '${name}'"); 138 compiler.cancel("Could not find implementation class '${name}'");
149 } 139 }
150 return e; 140 return e;
151 } 141 }
152 _annotationCreatesClass = find(const SourceString('Creates')); 142 _annotationCreatesClass = find(const SourceString('Creates'));
153 _annotationReturnsClass = find(const SourceString('Returns')); 143 _annotationReturnsClass = find(const SourceString('Returns'));
154 _annotationJsNameClass = find(const SourceString('JSName'));
155 } 144 }
156 145
157 /// Returns the JSName annotation string or `null` if no JSName annotation is
158 /// present.
159 String findJsNameFromAnnotation(Element element) {
160 String name = null;
161 ClassElement annotationClass = annotationJsNameClass;
162 for (Link<MetadataAnnotation> link = element.metadata;
163 !link.isEmpty;
164 link = link.tail) {
165 MetadataAnnotation annotation = link.head.ensureResolved(compiler);
166 var value = annotation.value;
167 if (value is! ConstructedConstant) continue;
168 if (value.type is! InterfaceType) continue;
169 if (!identical(value.type.element, annotationClass)) continue;
170
171 var fields = value.fields;
172 // TODO(sra): Better validation of the constant.
173 if (fields.length != 1 || fields[0] is! StringConstant) {
174 PartialMetadataAnnotation partial = annotation;
175 compiler.cancel(
176 'Annotations needs one string: ${partial.parseNode(compiler)}');
177 }
178 String specString = fields[0].toDartString().slowToString();
179 if (name == null) {
180 name = specString;
181 } else {
182 PartialMetadataAnnotation partial = annotation;
183 compiler.cancel(
184 'Too many JSName annotations: ${partial.parseNode(compiler)}');
185 }
186 }
187 return name;
188 }
189 146
190 enqueueClass(ClassElement classElement, cause) { 147 enqueueClass(ClassElement classElement, cause) {
191 assert(unusedClasses.contains(classElement)); 148 assert(unusedClasses.contains(classElement));
192 unusedClasses.remove(classElement); 149 unusedClasses.remove(classElement);
193 pendingClasses.add(classElement); 150 pendingClasses.add(classElement);
194 queue.add(() { processClass(classElement, cause); }); 151 queue.add(() { processClass(classElement, cause); });
195 } 152 }
196 153
197 void flushQueue() { 154 void flushQueue() {
198 if (flushing) return; 155 if (flushing) return;
(...skipping 19 matching lines...) Expand all
218 175
219 if (firstTime) { 176 if (firstTime) {
220 queue.add(onFirstNativeClass); 177 queue.add(onFirstNativeClass);
221 } 178 }
222 } 179 }
223 180
224 registerElement(Element element) { 181 registerElement(Element element) {
225 if (element.isFunction()) return registerMethod(element); 182 if (element.isFunction()) return registerMethod(element);
226 } 183 }
227 184
228 registerField(Element element) {
229 if (element.enclosingElement.isNative()) {
230 setNativeName(element);
231 }
232 }
233
234 registerMethod(Element method) { 185 registerMethod(Element method) {
235 if (isNativeMethod(method)) { 186 if (isNativeMethod(method)) {
236 setNativeName(method);
237 processNativeBehavior( 187 processNativeBehavior(
238 NativeBehavior.ofMethod(method, compiler), 188 NativeBehavior.ofMethod(method, compiler),
239 method); 189 method);
240 flushQueue(); 190 flushQueue();
241 } 191 }
242 } 192 }
243 193
244 /// Sets the native name of [element], either from an annotation, or
245 /// defaulting to the Dart name.
246 void setNativeName(Element element) {
247 String name = findJsNameFromAnnotation(element);
248 if (name == null) name = element.name.slowToString();
249 element.setNative(name);
250 }
251
252 bool isNativeMethod(Element element) { 194 bool isNativeMethod(Element element) {
253 if (!element.getLibrary().canUseNative) return false; 195 if (!element.getLibrary().canUseNative) return false;
254 // Native method? 196 // Native method?
255 return compiler.withCurrentElement(element, () { 197 return compiler.withCurrentElement(element, () {
256 Node node = element.parseNode(compiler); 198 Node node = element.parseNode(compiler);
257 if (node is! FunctionExpression) return false; 199 if (node is! FunctionExpression) return false;
258 node = node.body; 200 node = node.body;
259 Token token = node.getBeginToken(); 201 Token token = node.getBeginToken();
260 if (identical(token.stringValue, 'native')) return true; 202 if (identical(token.stringValue, 'native')) return true;
261 return false; 203 return false;
(...skipping 455 matching lines...) Expand 10 before | Expand all | Expand 10 after
717 listener.endLiteralString(0); 659 listener.endLiteralString(0);
718 token = token.next; 660 token = token.next;
719 } 661 }
720 listener.endReturnStatement(hasExpression, begin, token); 662 listener.endReturnStatement(hasExpression, begin, token);
721 // TODO(ngeoffray): expect a ';'. 663 // TODO(ngeoffray): expect a ';'.
722 // Currently there are method with both native marker and Dart body. 664 // Currently there are method with both native marker and Dart body.
723 return token.next; 665 return token.next;
724 } 666 }
725 667
726 SourceString checkForNativeClass(ElementListener listener) { 668 SourceString checkForNativeClass(ElementListener listener) {
727 SourceString nativeTagInfo; 669 SourceString nativeName;
728 Node node = listener.nodes.head; 670 Node node = listener.nodes.head;
729 if (node != null 671 if (node != null
730 && node.asIdentifier() != null 672 && node.asIdentifier() != null
731 && node.asIdentifier().source.stringValue == 'native') { 673 && node.asIdentifier().source.stringValue == 'native') {
732 nativeTagInfo = node.asIdentifier().token.next.value; 674 nativeName = node.asIdentifier().token.next.value;
733 listener.popNode(); 675 listener.popNode();
734 } 676 }
735 return nativeTagInfo; 677 return nativeName;
736 } 678 }
737 679
738 bool isOverriddenMethod(FunctionElement element, 680 bool isOverriddenMethod(FunctionElement element,
739 ClassElement cls, 681 ClassElement cls,
740 NativeEmitter nativeEmitter) { 682 NativeEmitter nativeEmitter) {
741 List<ClassElement> subtypes = nativeEmitter.subtypes[cls]; 683 List<ClassElement> subtypes = nativeEmitter.subtypes[cls];
742 if (subtypes == null) return false; 684 if (subtypes == null) return false;
743 for (ClassElement subtype in subtypes) { 685 for (ClassElement subtype in subtypes) {
744 if (subtype.lookupLocalMember(element.name) != null) return true; 686 if (subtype.lookupLocalMember(element.name) != null) return true;
745 } 687 }
746 return false; 688 return false;
747 } 689 }
748 690
749 final RegExp nativeRedirectionRegExp = new RegExp(r'^[a-zA-Z][a-zA-Z_$0-9]*$'); 691 final RegExp nativeRedirectionRegExp = new RegExp(r'^[a-zA-Z][a-zA-Z_$0-9]*$');
750 692
751 void handleSsaNative(SsaBuilder builder, Expression nativeBody) { 693 void handleSsaNative(SsaBuilder builder, Expression nativeBody) {
752 Compiler compiler = builder.compiler; 694 Compiler compiler = builder.compiler;
753 FunctionElement element = builder.work.element; 695 FunctionElement element = builder.work.element;
696 element.setNative();
754 NativeEmitter nativeEmitter = builder.emitter.nativeEmitter; 697 NativeEmitter nativeEmitter = builder.emitter.nativeEmitter;
755 // If what we're compiling is a getter named 'typeName' and the native 698 // If what we're compiling is a getter named 'typeName' and the native
756 // class is named 'DOMType', we generate a call to the typeNameOf 699 // class is named 'DOMType', we generate a call to the typeNameOf
757 // function attached on the isolate. 700 // function attached on the isolate.
758 // The DOM classes assume that their 'typeName' property, which is 701 // The DOM classes assume that their 'typeName' property, which is
759 // not a JS property on the DOM types, returns the type name. 702 // not a JS property on the DOM types, returns the type name.
760 if (element.name == const SourceString('typeName') 703 if (element.name == const SourceString('typeName')
761 && element.isGetter() 704 && element.isGetter()
762 && nativeEmitter.toNativeName(element.getEnclosingClass()) == 'DOMType') { 705 && nativeEmitter.toNativeName(element.getEnclosingClass()) == 'DOMType') {
763 Element helper = 706 Element helper =
764 compiler.findHelper(const SourceString('getTypeNameOf')); 707 compiler.findHelper(const SourceString('getTypeNameOf'));
765 builder.pushInvokeHelper1(helper, builder.localsHandler.readThis()); 708 builder.pushInvokeHelper1(helper, builder.localsHandler.readThis());
766 builder.close(new HReturn(builder.pop())).addSuccessor(builder.graph.exit); 709 builder.close(new HReturn(builder.pop())).addSuccessor(builder.graph.exit);
767 } 710 }
768 711
769 HInstruction convertDartClosure(Element parameter, FunctionType type) { 712 HInstruction convertDartClosure(Element parameter, FunctionType type) {
770 HInstruction local = builder.localsHandler.readLocal(parameter); 713 HInstruction local = builder.localsHandler.readLocal(parameter);
771 Constant arityConstant = 714 Constant arityConstant =
772 builder.constantSystem.createInt(type.computeArity()); 715 builder.constantSystem.createInt(type.computeArity());
773 HInstruction arity = builder.graph.addConstant(arityConstant); 716 HInstruction arity = builder.graph.addConstant(arityConstant);
774 // TODO(ngeoffray): For static methods, we could pass a method with a 717 // TODO(ngeoffray): For static methods, we could pass a method with a
775 // defined arity. 718 // defined arity.
776 Element helper = builder.interceptors.getClosureConverter(); 719 Element helper = builder.interceptors.getClosureConverter();
777 builder.pushInvokeHelper2(helper, local, arity); 720 builder.pushInvokeHelper2(helper, local, arity);
778 HInstruction closure = builder.pop(); 721 HInstruction closure = builder.pop();
779 return closure; 722 return closure;
780 } 723 }
781 724
782 // Check which pattern this native method follows: 725 // Check which pattern this native method follows:
783 // 1) foo() native; 726 // 1) foo() native; hasBody = false, isRedirecting = false
784 // hasBody = false, isRedirecting = false 727 // 2) foo() native "bar"; hasBody = false, isRedirecting = true
785 // 2) foo() native "bar"; 728 // 3) foo() native "return 42"; hasBody = true, isRedirecting = false
786 // hasBody = false, isRedirecting = true, no longer supported.
787 // 3) foo() native "return 42";
788 // hasBody = true, isRedirecting = false
789 bool hasBody = false; 729 bool hasBody = false;
790 String nativeMethodName = element.nativeName(); 730 bool isRedirecting = false;
731 String nativeMethodName = element.name.slowToString();
791 if (nativeBody != null) { 732 if (nativeBody != null) {
792 LiteralString jsCode = nativeBody.asLiteralString(); 733 LiteralString jsCode = nativeBody.asLiteralString();
793 String str = jsCode.dartString.slowToString(); 734 String str = jsCode.dartString.slowToString();
794 if (nativeRedirectionRegExp.hasMatch(str)) { 735 if (nativeRedirectionRegExp.hasMatch(str)) {
795 compiler.cancel("Deprecated syntax, use @JSName('name') instead.", 736 nativeMethodName = str;
796 node: nativeBody); 737 isRedirecting = true;
738 nativeEmitter.addRedirectingMethod(element, nativeMethodName);
739 } else {
740 hasBody = true;
797 } 741 }
798 hasBody = true;
799 } 742 }
800 743
801 if (!hasBody) { 744 if (!hasBody) {
802 nativeEmitter.nativeMethods.add(element); 745 nativeEmitter.nativeMethods.add(element);
803 } 746 }
804 747
805 FunctionSignature parameters = element.computeSignature(builder.compiler); 748 FunctionSignature parameters = element.computeSignature(builder.compiler);
806 if (!hasBody) { 749 if (!hasBody) {
807 List<String> arguments = <String>[]; 750 List<String> arguments = <String>[];
808 List<HInstruction> inputs = <HInstruction>[]; 751 List<HInstruction> inputs = <HInstruction>[];
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
902 String parameters) { 845 String parameters) {
903 buffer.add(" if (Object.getPrototypeOf(this).hasOwnProperty"); 846 buffer.add(" if (Object.getPrototypeOf(this).hasOwnProperty");
904 buffer.add("('$methodName')) {\n"); 847 buffer.add("('$methodName')) {\n");
905 buffer.add(" $code"); 848 buffer.add(" $code");
906 buffer.add(" } else {\n"); 849 buffer.add(" } else {\n");
907 buffer.add(" return Object.prototype.$methodName.call(this"); 850 buffer.add(" return Object.prototype.$methodName.call(this");
908 buffer.add(parameters == '' ? '' : ', $parameters'); 851 buffer.add(parameters == '' ? '' : ', $parameters');
909 buffer.add(");\n"); 852 buffer.add(");\n");
910 buffer.add(" }\n"); 853 buffer.add(" }\n");
911 } 854 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698