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

Side by Side Diff: pkg/compiler/lib/src/native/resolver.dart

Issue 2873113004: Add equivalence check of NativeData and InterceptorData (Closed)
Patch Set: Created 3 years, 7 months 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
OLDNEW
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' 5 import 'package:front_end/src/fasta/scanner.dart'
6 show BeginGroupToken, StringToken, Token; 6 show BeginGroupToken, StringToken, Token;
7 import 'package:front_end/src/fasta/scanner.dart' as Tokens show EOF_TOKEN; 7 import 'package:front_end/src/fasta/scanner.dart' as Tokens show EOF_TOKEN;
8 8
9 import '../common.dart'; 9 import '../common.dart';
10 import '../common_elements.dart' show CommonElements, ElementEnvironment; 10 import '../common_elements.dart' show CommonElements, ElementEnvironment;
(...skipping 11 matching lines...) Expand all
22 MethodElement; 22 MethodElement;
23 import '../elements/entities.dart'; 23 import '../elements/entities.dart';
24 import '../elements/modelx.dart' show FunctionElementX, MetadataAnnotationX; 24 import '../elements/modelx.dart' show FunctionElementX, MetadataAnnotationX;
25 import '../elements/resolution_types.dart' show ResolutionDartType; 25 import '../elements/resolution_types.dart' show ResolutionDartType;
26 import '../js_backend/js_backend.dart'; 26 import '../js_backend/js_backend.dart';
27 import '../js_backend/native_data.dart'; 27 import '../js_backend/native_data.dart';
28 import '../patch_parser.dart'; 28 import '../patch_parser.dart';
29 import '../tree/tree.dart'; 29 import '../tree/tree.dart';
30 import 'behavior.dart'; 30 import 'behavior.dart';
31 31
32 /// Interface for computing native members.
33 abstract class NativeMemberResolver {
34 /// Computes whether [element] is native or JsInterop and, if so, registers
35 /// its [NativeBehavior]s to [registry].
36 void resolveNativeMember(MemberEntity element, [NativeRegistry registry]);
37 }
38
32 /// Interface for computing native members and [NativeBehavior]s in member code 39 /// Interface for computing native members and [NativeBehavior]s in member code
33 /// based on the AST. 40 /// based on the AST.
34 abstract class NativeDataResolver { 41 abstract class NativeDataResolver implements NativeMemberResolver {
35 /// Returns `true` if [element] is a JsInterop member. 42 /// Returns `true` if [element] is a JsInterop member.
36 bool isJsInteropMember(MemberElement element); 43 bool isJsInteropMember(MemberElement element);
37 44
38 /// Computes whether [element] is native or JsInterop and, if so, registers
39 /// its [NativeBehavior]s to [registry].
40 void resolveNativeMember(MemberElement element, NativeRegistry registry);
41
42 /// Computes the [NativeBehavior] for a `JS` call, which can be an 45 /// Computes the [NativeBehavior] for a `JS` call, which can be an
43 /// instantiation point for types. 46 /// instantiation point for types.
44 /// 47 ///
45 /// For example, the following code instantiates and returns native classes 48 /// For example, the following code instantiates and returns native classes
46 /// that are `_DOMWindowImpl` or a subtype. 49 /// that are `_DOMWindowImpl` or a subtype.
47 /// 50 ///
48 /// JS('_DOMWindowImpl', 'window') 51 /// JS('_DOMWindowImpl', 'window')
49 /// 52 ///
50 NativeBehavior resolveJsCall(Send node, ForeignResolver resolver); 53 NativeBehavior resolveJsCall(Send node, ForeignResolver resolver);
51 54
(...skipping 10 matching lines...) Expand all
62 /// Computes the [NativeBehavior] for a `JS_BUILTIN` call, which can be an 65 /// Computes the [NativeBehavior] for a `JS_BUILTIN` call, which can be an
63 /// instantiation point for types. 66 /// instantiation point for types.
64 /// 67 ///
65 /// For example, the following code instantiates and returns a String class 68 /// For example, the following code instantiates and returns a String class
66 /// 69 ///
67 /// JS_BUILTIN('String', 'int2string', 0) 70 /// JS_BUILTIN('String', 'int2string', 0)
68 /// 71 ///
69 NativeBehavior resolveJsBuiltinCall(Send node, ForeignResolver resolver); 72 NativeBehavior resolveJsBuiltinCall(Send node, ForeignResolver resolver);
70 } 73 }
71 74
72 class NativeDataResolverImpl implements NativeDataResolver { 75 abstract class NativeMemberResolverBase implements NativeMemberResolver {
73 static final RegExp _identifier = new RegExp(r'^[a-zA-Z_$][a-zA-Z0-9_$]*$'); 76 static final RegExp _identifier = new RegExp(r'^[a-zA-Z_$][a-zA-Z0-9_$]*$');
74 77
75 final Compiler _compiler; 78 ElementEnvironment get elementEnvironment;
79 CommonElements get commonElements;
80 NativeBasicData get nativeBasicData;
81 NativeDataBuilder get nativeDataBuilder;
76 82
77 NativeDataResolverImpl(this._compiler); 83 bool isJsInteropMember(MemberEntity element);
84 bool isNativeMethod(FunctionEntity element);
78 85
79 JavaScriptBackend get _backend => _compiler.backend; 86 NativeBehavior computeNativeMethodBehavior(FunctionEntity function,
80 DiagnosticReporter get _reporter => _compiler.reporter; 87 {bool isJsInterop});
81 NativeBasicData get _nativeBasicData => _backend.nativeBasicData; 88 NativeBehavior computeNativeFieldLoadBehavior(FieldEntity field,
82 NativeDataBuilder get _nativeDataBuilder => _backend.nativeDataBuilder; 89 {bool isJsInterop});
90 NativeBehavior computeNativeFieldStoreBehavior(FieldEntity field);
83 91
84 @override 92 @override
85 bool isJsInteropMember(MemberElement element) { 93 void resolveNativeMember(MemberEntity element, [NativeRegistry registry]) {
86 // TODO(johnniwinther): Avoid computing this twice for external function;
87 // once from JavaScriptBackendTarget.resolveExternalFunction and once
88 // through JavaScriptBackendTarget.resolveNativeMember.
89 bool isJsInterop =
90 checkJsInteropMemberAnnotations(_compiler, element, _nativeDataBuilder);
91 // TODO(johnniwinther): Avoid this duplication of logic from
92 // NativeData.isJsInterop.
93 if (!isJsInterop && element is MethodElement && element.isExternal) {
94 if (element.enclosingClass != null) {
95 isJsInterop = _nativeBasicData.isJsInteropClass(element.enclosingClass);
96 } else {
97 isJsInterop = _nativeBasicData.isJsInteropLibrary(element.library);
98 }
99 }
100 return isJsInterop;
101 }
102
103 void resolveNativeMember(MemberElement element, NativeRegistry registry) {
104 bool isJsInterop = isJsInteropMember(element); 94 bool isJsInterop = isJsInteropMember(element);
105 if (element.isFunction || 95 if (element.isFunction ||
106 element.isConstructor || 96 element.isConstructor ||
107 element.isGetter || 97 element.isGetter ||
108 element.isSetter) { 98 element.isSetter) {
109 MethodElement method = element; 99 FunctionEntity method = element;
110 bool isNative = _processMethodAnnotations(method); 100 bool isNative = _processMethodAnnotations(method);
111 if (isNative || isJsInterop) { 101 if (isNative || isJsInterop) {
112 NativeBehavior behavior = NativeBehavior 102 NativeBehavior behavior =
113 .ofMethodElement(method, _compiler, isJsInterop: isJsInterop); 103 computeNativeMethodBehavior(method, isJsInterop: isJsInterop);
114 _nativeDataBuilder.setNativeMethodBehavior(method, behavior); 104 nativeDataBuilder.setNativeMethodBehavior(method, behavior);
115 registry.registerNativeData(behavior); 105 registry?.registerNativeData(behavior);
116 } 106 }
117 } else if (element.isField) { 107 } else if (element.isField) {
118 FieldElement field = element; 108 FieldEntity field = element;
119 bool isNative = _processFieldAnnotations(field); 109 bool isNative = _processFieldAnnotations(field);
120 if (isNative || isJsInterop) { 110 if (isNative || isJsInterop) {
121 NativeBehavior fieldLoadBehavior = NativeBehavior 111 NativeBehavior fieldLoadBehavior =
122 .ofFieldElementLoad(field, _compiler, isJsInterop: isJsInterop); 112 computeNativeFieldLoadBehavior(field, isJsInterop: isJsInterop);
123 NativeBehavior fieldStoreBehavior = 113 NativeBehavior fieldStoreBehavior =
124 NativeBehavior.ofFieldElementStore(field, _compiler); 114 computeNativeFieldStoreBehavior(field);
125 _nativeDataBuilder.setNativeFieldLoadBehavior(field, fieldLoadBehavior); 115 nativeDataBuilder.setNativeFieldLoadBehavior(field, fieldLoadBehavior);
126 _nativeDataBuilder.setNativeFieldStoreBehavior( 116 nativeDataBuilder.setNativeFieldStoreBehavior(
127 field, fieldStoreBehavior); 117 field, fieldStoreBehavior);
128 118
129 // TODO(sra): Process fields for storing separately. 119 // TODO(sra): Process fields for storing separately.
130 // We have to handle both loading and storing to the field because we 120 // We have to handle both loading and storing to the field because we
131 // only get one look at each member and there might be a load or store 121 // only get one look at each member and there might be a load or store
132 // we have not seen yet. 122 // we have not seen yet.
133 registry.registerNativeData(fieldLoadBehavior); 123 registry?.registerNativeData(fieldLoadBehavior);
134 registry.registerNativeData(fieldStoreBehavior); 124 registry?.registerNativeData(fieldStoreBehavior);
135 } 125 }
136 } 126 }
137 } 127 }
138 128
139 /// Process the potentially native [field]. Adds information from metadata 129 /// Process the potentially native [field]. Adds information from metadata
140 /// attributes. Returns `true` of [method] is native. 130 /// attributes. Returns `true` of [method] is native.
141 bool _processFieldAnnotations(Element element) { 131 bool _processFieldAnnotations(FieldEntity element) {
142 if (_compiler.serialization.isDeserialized(element)) {
143 return false;
144 }
145 if (element.isInstanceMember && 132 if (element.isInstanceMember &&
146 _backend.nativeBasicData.isNativeClass(element.enclosingClass)) { 133 nativeBasicData.isNativeClass(element.enclosingClass)) {
147 // Exclude non-instance (static) fields - they are not really native and 134 // Exclude non-instance (static) fields - they are not really native and
148 // are compiled as isolate globals. Access of a property of a constructor 135 // are compiled as isolate globals. Access of a property of a constructor
149 // function or a non-method property in the prototype chain, must be coded 136 // function or a non-method property in the prototype chain, must be coded
150 // using a JS-call. 137 // using a JS-call.
151 _setNativeName(element); 138 _setNativeName(element);
152 return true; 139 return true;
153 } 140 }
154 return false; 141 return false;
155 } 142 }
156 143
157 /// Process the potentially native [method]. Adds information from metadata 144 /// Process the potentially native [method]. Adds information from metadata
158 /// attributes. Returns `true` of [method] is native. 145 /// attributes. Returns `true` of [method] is native.
159 bool _processMethodAnnotations(Element method) { 146 bool _processMethodAnnotations(FunctionEntity method) {
160 if (_compiler.serialization.isDeserialized(method)) { 147 if (isNativeMethod(method)) {
161 return false;
162 }
163 if (_isNativeMethod(method)) {
164 if (method.isStatic) { 148 if (method.isStatic) {
165 _setNativeNameForStaticMethod(method); 149 _setNativeNameForStaticMethod(method);
166 } else { 150 } else {
167 _setNativeName(method); 151 _setNativeName(method);
168 } 152 }
169 return true; 153 return true;
170 } 154 }
171 return false; 155 return false;
172 } 156 }
173 157
174 /// Sets the native name of [element], either from an annotation, or 158 /// Sets the native name of [element], either from an annotation, or
175 /// defaulting to the Dart name. 159 /// defaulting to the Dart name.
176 void _setNativeName(MemberElement element) { 160 void _setNativeName(MemberEntity element) {
177 String name = _findJsNameFromAnnotation(element); 161 String name = _findJsNameFromAnnotation(element);
178 if (name == null) name = element.name; 162 if (name == null) name = element.name;
179 _nativeDataBuilder.setNativeMemberName(element, name); 163 nativeDataBuilder.setNativeMemberName(element, name);
180 } 164 }
181 165
182 /// Sets the native name of the static native method [element], using the 166 /// Sets the native name of the static native method [element], using the
183 /// following rules: 167 /// following rules:
184 /// 1. If [element] has a @JSName annotation that is an identifier, qualify 168 /// 1. If [element] has a @JSName annotation that is an identifier, qualify
185 /// that identifier to the @Native name of the enclosing class 169 /// that identifier to the @Native name of the enclosing class
186 /// 2. If [element] has a @JSName annotation that is not an identifier, 170 /// 2. If [element] has a @JSName annotation that is not an identifier,
187 /// use the declared @JSName as the expression 171 /// use the declared @JSName as the expression
188 /// 3. If [element] does not have a @JSName annotation, qualify the name of 172 /// 3. If [element] does not have a @JSName annotation, qualify the name of
189 /// the method with the @Native name of the enclosing class. 173 /// the method with the @Native name of the enclosing class.
190 void _setNativeNameForStaticMethod(MethodElement element) { 174 void _setNativeNameForStaticMethod(FunctionEntity element) {
191 String name = _findJsNameFromAnnotation(element); 175 String name = _findJsNameFromAnnotation(element);
192 if (name == null) name = element.name; 176 if (name == null) name = element.name;
193 if (_isIdentifier(name)) { 177 if (_isIdentifier(name)) {
194 List<String> nativeNames = 178 List<String> nativeNames =
195 _nativeBasicData.getNativeTagsOfClass(element.enclosingClass); 179 nativeBasicData.getNativeTagsOfClass(element.enclosingClass);
196 if (nativeNames.length != 1) { 180 if (nativeNames.length != 1) {
197 _reporter.internalError( 181 throw new SpannableAssertionFailure(
198 element, 182 element,
199 'Unable to determine a native name for the enclosing class, ' 183 'Unable to determine a native name for the enclosing class, '
200 'options: $nativeNames'); 184 'options: $nativeNames');
201 } 185 }
202 _nativeDataBuilder.setNativeMemberName( 186 nativeDataBuilder.setNativeMemberName(element, '${nativeNames[0]}.$name');
203 element, '${nativeNames[0]}.$name');
204 } else { 187 } else {
205 _nativeDataBuilder.setNativeMemberName(element, name); 188 nativeDataBuilder.setNativeMemberName(element, name);
206 } 189 }
207 } 190 }
208 191
209 bool _isIdentifier(String s) => _identifier.hasMatch(s); 192 bool _isIdentifier(String s) => _identifier.hasMatch(s);
210 193
211 bool _isNativeMethod(FunctionElementX element) { 194 /// Returns the JSName annotation string or `null` if no JSName annotation is
195 /// present.
196 String _findJsNameFromAnnotation(MemberEntity element) {
197 String jsName = null;
198 for (ConstantValue value in elementEnvironment.getMemberMetadata(element)) {
199 String name = readAnnotationName(
200 element, value, commonElements.annotationJSNameClass);
201 if (jsName == null) {
202 jsName = name;
203 } else if (name != null) {
204 throw new SpannableAssertionFailure(
205 element, 'Too many JSName annotations: ${value.toDartText()}');
206 }
207 }
208 return jsName;
209 }
210 }
211
212 class NativeDataResolverImpl extends NativeMemberResolverBase
213 implements NativeDataResolver {
214 final Compiler _compiler;
215
216 NativeDataResolverImpl(this._compiler);
217
218 JavaScriptBackend get _backend => _compiler.backend;
219 DiagnosticReporter get _reporter => _compiler.reporter;
220 ElementEnvironment get elementEnvironment => _compiler.elementEnvironment;
221 CommonElements get commonElements => _compiler.commonElements;
222 NativeBasicData get nativeBasicData => _backend.nativeBasicData;
223 NativeDataBuilder get nativeDataBuilder => _backend.nativeDataBuilder;
224
225 @override
226 bool isJsInteropMember(MemberElement element) {
227 // TODO(johnniwinther): Avoid computing this twice for external function;
228 // once from JavaScriptBackendTarget.resolveExternalFunction and once
229 // through JavaScriptBackendTarget.resolveNativeMember.
230 bool isJsInterop =
231 checkJsInteropMemberAnnotations(_compiler, element, nativeDataBuilder);
232 // TODO(johnniwinther): Avoid this duplication of logic from
233 // NativeData.isJsInterop.
234 if (!isJsInterop && element is MethodElement && element.isExternal) {
235 if (element.enclosingClass != null) {
236 isJsInterop = nativeBasicData.isJsInteropClass(element.enclosingClass);
237 } else {
238 isJsInterop = nativeBasicData.isJsInteropLibrary(element.library);
239 }
240 }
241 return isJsInterop;
242 }
243
244 @override
245 NativeBehavior computeNativeMethodBehavior(MethodElement function,
246 {bool isJsInterop}) {
247 return NativeBehavior.ofMethodElement(function, _compiler,
248 isJsInterop: isJsInterop);
249 }
250
251 @override
252 NativeBehavior computeNativeFieldLoadBehavior(FieldElement field,
253 {bool isJsInterop}) {
254 return NativeBehavior.ofFieldElementLoad(field, _compiler,
255 isJsInterop: isJsInterop);
256 }
257
258 @override
259 NativeBehavior computeNativeFieldStoreBehavior(FieldElement field) {
260 return NativeBehavior.ofFieldElementStore(field, _compiler);
261 }
262
263 @override
264 bool isNativeMethod(FunctionElementX element) {
212 if (!_backend.canLibraryUseNative(element.library)) return false; 265 if (!_backend.canLibraryUseNative(element.library)) return false;
213 // Native method? 266 // Native method?
214 return _reporter.withCurrentElement(element, () { 267 return _reporter.withCurrentElement(element, () {
215 Node node = element.parseNode(_compiler.resolution.parsingContext); 268 Node node = element.parseNode(_compiler.resolution.parsingContext);
216 if (node is! FunctionExpression) return false; 269 if (node is! FunctionExpression) return false;
217 FunctionExpression functionExpression = node; 270 FunctionExpression functionExpression = node;
218 node = functionExpression.body; 271 node = functionExpression.body;
219 Token token = node.getBeginToken(); 272 Token token = node.getBeginToken();
220 if (identical(token.stringValue, 'native')) return true; 273 if (identical(token.stringValue, 'native')) return true;
221 return false; 274 return false;
222 }); 275 });
223 } 276 }
224 277
225 /// Returns the JSName annotation string or `null` if no JSName annotation is 278 @override
226 /// present. 279 bool _processMethodAnnotations(MethodElement method) {
227 String _findJsNameFromAnnotation(Element element) { 280 if (_compiler.serialization.isDeserialized(method)) {
228 String jsName = null; 281 return false;
229 for (MetadataAnnotation annotation in element.implementation.metadata) {
230 annotation.ensureResolved(_compiler.resolution);
231 ConstantValue value =
232 _compiler.constants.getConstantValue(annotation.constant);
233 String name = readAnnotationName(
234 annotation, value, _compiler.commonElements.annotationJSNameClass);
235 if (jsName == null) {
236 jsName = name;
237 } else if (name != null) {
238 throw new SpannableAssertionFailure(
239 annotation, 'Too many JSName annotations: ${annotation}');
240 }
241 } 282 }
242 return jsName; 283 return super._processMethodAnnotations(method);
243 } 284 }
244 285
245 @override 286 @override
287 bool _processFieldAnnotations(FieldElement element) {
288 if (_compiler.serialization.isDeserialized(element)) {
289 return false;
290 }
291 return super._processFieldAnnotations(element);
292 }
293
294 @override
246 NativeBehavior resolveJsCall(Send node, ForeignResolver resolver) { 295 NativeBehavior resolveJsCall(Send node, ForeignResolver resolver) {
247 return NativeBehavior.ofJsCallSend(node, _reporter, 296 return NativeBehavior.ofJsCallSend(node, _reporter,
248 _compiler.parsingContext, _compiler.commonElements, resolver); 297 _compiler.parsingContext, _compiler.commonElements, resolver);
249 } 298 }
250 299
251 @override 300 @override
252 NativeBehavior resolveJsEmbeddedGlobalCall( 301 NativeBehavior resolveJsEmbeddedGlobalCall(
253 Send node, ForeignResolver resolver) { 302 Send node, ForeignResolver resolver) {
254 return NativeBehavior.ofJsEmbeddedGlobalCallSend( 303 return NativeBehavior.ofJsEmbeddedGlobalCallSend(
255 node, _reporter, _compiler.commonElements, resolver); 304 node, _reporter, _compiler.commonElements, resolver);
(...skipping 310 matching lines...) Expand 10 before | Expand all | Expand 10 after
566 615
567 Iterable<ConstantValue> fields = constructedObject.fields.values; 616 Iterable<ConstantValue> fields = constructedObject.fields.values;
568 // TODO(sra): Better validation of the constant. 617 // TODO(sra): Better validation of the constant.
569 if (fields.length != 1 || fields.single is! StringConstantValue) { 618 if (fields.length != 1 || fields.single is! StringConstantValue) {
570 throw new SpannableAssertionFailure( 619 throw new SpannableAssertionFailure(
571 spannable, 'Annotations needs one string: ${value.toStructuredText()}'); 620 spannable, 'Annotations needs one string: ${value.toStructuredText()}');
572 } 621 }
573 StringConstantValue specStringConstant = fields.single; 622 StringConstantValue specStringConstant = fields.single;
574 return specStringConstant.primitiveValue; 623 return specStringConstant.primitiveValue;
575 } 624 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698