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

Side by Side Diff: pkg/compiler/lib/src/js_backend/native_data.dart

Issue 2731163002: Split js interop registration into library/class/member elements (Closed)
Patch Set: Updated cf. comments Created 3 years, 9 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) 2016, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2016, 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 js_backend.native_data; 5 library js_backend.native_data;
6 6
7 import '../common.dart'; 7 import '../common.dart';
8 import '../elements/elements.dart' 8 import '../elements/elements.dart'
9 show 9 show
10 ClassElement, 10 ClassElement,
11 Element, 11 Element,
12 FieldElement, 12 FieldElement,
13 FunctionElement,
14 LibraryElement, 13 LibraryElement,
15 MemberElement, 14 MemberElement,
16 MethodElement; 15 MethodElement;
17 import '../elements/entities.dart'; 16 import '../elements/entities.dart';
18 import '../native/behavior.dart' show NativeBehavior; 17 import '../native/behavior.dart' show NativeBehavior;
19 18
20 /// Basic information for native classes and methods and js-interop 19 /// Basic information for native classes and methods and js-interop
21 /// classes. 20 /// classes.
22 /// 21 ///
23 /// This information is computed during loading using [NativeClassDataBuilder]. 22 /// This information is computed during loading using [NativeClassDataBuilder].
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
56 NativeBehavior getNativeMethodBehavior(MethodElement method); 55 NativeBehavior getNativeMethodBehavior(MethodElement method);
57 56
58 /// Returns the [NativeBehavior] for reading from the native [field]. 57 /// Returns the [NativeBehavior] for reading from the native [field].
59 NativeBehavior getNativeFieldLoadBehavior(FieldElement field); 58 NativeBehavior getNativeFieldLoadBehavior(FieldElement field);
60 59
61 /// Returns the [NativeBehavior] for writing to the native [field]. 60 /// Returns the [NativeBehavior] for writing to the native [field].
62 NativeBehavior getNativeFieldStoreBehavior(FieldElement field); 61 NativeBehavior getNativeFieldStoreBehavior(FieldElement field);
63 62
64 /// Returns `true` if the name of [element] is fixed for the generated 63 /// Returns `true` if the name of [element] is fixed for the generated
65 /// JavaScript. 64 /// JavaScript.
66 bool hasFixedBackendName(Element element); 65 bool hasFixedBackendName(MemberElement element);
67 66
68 /// Computes the name for [element] to use in the generated JavaScript. This 67 /// Computes the name for [element] to use in the generated JavaScript. This
69 /// is either given through a native annotation or a js interop annotation. 68 /// is either given through a native annotation or a js interop annotation.
70 String getFixedBackendName(Entity entity); 69 String getFixedBackendName(MemberEntity element);
70
71 /// Computes the name prefix for [element] to use in the generated JavaScript.
72 ///
73 /// For static and top-level members and constructors this is based on the
74 /// JavaScript names for the library and/or the enclosing class.
75 String getFixedBackendMethodPath(MethodElement element);
71 76
72 /// Returns the list of non-directive native tag words for [cls]. 77 /// Returns the list of non-directive native tag words for [cls].
73 List<String> getNativeTagsOfClass(ClassElement cls); 78 List<String> getNativeTagsOfClass(ClassElement cls);
74 79
75 /// Returns `true` if [cls] has a `!nonleaf` tag word. 80 /// Returns `true` if [cls] has a `!nonleaf` tag word.
76 bool hasNativeTagsForcedNonLeaf(ClassElement cls); 81 bool hasNativeTagsForcedNonLeaf(ClassElement cls);
77 82
78 /// Returns `true` if [element] is part of JsInterop. 83 /// Returns `true` if [element] is a JsInterop method.
79 /// 84 bool isJsInteropMember(MemberEntity element);
80 /// Deprecated: Use [isJsInteropLibrary], [isJsInteropClass] or
81 /// [isJsInteropMember] instead.
82 @deprecated
83 bool isJsInterop(Element element);
84 85
85 /// Returns `true` if [element] is a JsInterop method. 86 /// Returns the explicit js interop name for library [element].
86 bool isJsInteropMember(MethodElement element); 87 String getJsInteropLibraryName(LibraryElement element);
87 88
88 /// Returns the explicit js interop name for [element]. 89 /// Returns the explicit js interop name for class [element].
89 String getJsInteropName(Element element); 90 String getJsInteropClassName(ClassElement element);
91
92 /// Returns the explicit js interop name for member [element].
93 String getJsInteropMemberName(MemberElement element);
90 94
91 /// Apply JS$ escaping scheme to convert possible escaped Dart names into 95 /// Apply JS$ escaping scheme to convert possible escaped Dart names into
92 /// JS names. 96 /// JS names.
93 String getUnescapedJSInteropName(String name); 97 String computeUnescapedJSInteropName(String name);
94 } 98 }
95 99
96 abstract class NativeClassDataBuilder { 100 abstract class NativeClassDataBuilder {
97 /// Sets the native tag info for [cls]. 101 /// Sets the native tag info for [cls].
98 /// 102 ///
99 /// The tag info string contains comma-separated 'words' which are either 103 /// The tag info string contains comma-separated 'words' which are either
100 /// dispatch tags (having JavaScript identifier syntax) and directives that 104 /// dispatch tags (having JavaScript identifier syntax) and directives that
101 /// begin with `!`. 105 /// begin with `!`.
102 void setNativeClassTagInfo(ClassElement cls, String tagInfo); 106 void setNativeClassTagInfo(ClassElement cls, String tagInfo);
103 107
(...skipping 20 matching lines...) Expand all
124 List<String> getNativeTagsOfClassRaw(ClassElement cls); 128 List<String> getNativeTagsOfClassRaw(ClassElement cls);
125 129
126 /// Returns [element] as an explicit part of JsInterop. The js interop name is 130 /// Returns [element] as an explicit part of JsInterop. The js interop name is
127 /// expected to be computed later. 131 /// expected to be computed later.
128 void markAsJsInteropMember(MemberElement element); 132 void markAsJsInteropMember(MemberElement element);
129 133
130 /// Sets the native [name] for the member [element]. This name is used for 134 /// Sets the native [name] for the member [element]. This name is used for
131 /// [element] in the generated JavaScript. 135 /// [element] in the generated JavaScript.
132 void setNativeMemberName(MemberElement element, String name); 136 void setNativeMemberName(MemberElement element, String name);
133 137
134 /// Sets the explicit js interop [name] for [element]. 138 /// Sets the explicit js interop [name] for the library [element].
135 void setJsInteropName(Element element, String name); 139 void setJsInteropLibraryName(LibraryElement element, String name);
140
141 /// Sets the explicit js interop [name] for the class [element].
142 void setJsInteropClassName(ClassElement element, String name);
143
144 /// Sets the explicit js interop [name] for the member [element].
145 void setJsInteropMemberName(MemberElement element, String name);
136 } 146 }
137 147
138 class NativeDataImpl 148 class NativeDataImpl
139 implements NativeData, NativeDataBuilder, NativeClassDataBuilder { 149 implements NativeData, NativeDataBuilder, NativeClassDataBuilder {
140 /// The JavaScript names for elements implemented via typed JavaScript 150 /// The JavaScript names for elements implemented via typed JavaScript
141 /// interop. 151 /// interop.
142 Map<Element, String> jsInteropNames = <Element, String>{}; 152 Map<LibraryElement, String> jsInteropLibraryNames =
153 <LibraryElement, String>{};
154 Map<ClassElement, String> jsInteropClassNames = <ClassElement, String>{};
155 Map<MemberElement, String> jsInteropMemberNames = <MemberElement, String>{};
143 156
144 /// The JavaScript names for native JavaScript elements implemented. 157 /// The JavaScript names for native JavaScript elements implemented.
145 Map<Element, String> nativeMemberName = <Element, String>{}; 158 Map<Element, String> nativeMemberName = <Element, String>{};
146 159
147 /// Tag info for native JavaScript classes names. See 160 /// Tag info for native JavaScript classes names. See
148 /// [setNativeClassTagInfo]. 161 /// [setNativeClassTagInfo].
149 Map<ClassElement, String> nativeClassTagInfo = <ClassElement, String>{}; 162 Map<ClassElement, String> nativeClassTagInfo = <ClassElement, String>{};
150 163
151 /// Cache for [NativeBehavior]s for calling native methods. 164 /// Cache for [NativeBehavior]s for calling native methods.
152 Map<MethodElement, NativeBehavior> nativeMethodBehavior = 165 Map<MethodElement, NativeBehavior> nativeMethodBehavior =
153 <MethodElement, NativeBehavior>{}; 166 <MethodElement, NativeBehavior>{};
154 167
155 /// Cache for [NativeBehavior]s for reading from native fields. 168 /// Cache for [NativeBehavior]s for reading from native fields.
156 Map<MemberElement, NativeBehavior> nativeFieldLoadBehavior = 169 Map<MemberElement, NativeBehavior> nativeFieldLoadBehavior =
157 <FieldElement, NativeBehavior>{}; 170 <FieldElement, NativeBehavior>{};
158 171
159 /// Cache for [NativeBehavior]s for writing to native fields. 172 /// Cache for [NativeBehavior]s for writing to native fields.
160 Map<MemberElement, NativeBehavior> nativeFieldStoreBehavior = 173 Map<MemberElement, NativeBehavior> nativeFieldStoreBehavior =
161 <FieldElement, NativeBehavior>{}; 174 <FieldElement, NativeBehavior>{};
162 175
163 /// Prefix used to escape JS names that are not valid Dart names 176 /// Prefix used to escape JS names that are not valid Dart names
164 /// when using JSInterop. 177 /// when using JSInterop.
165 static const String _jsInteropEscapePrefix = r'JS$'; 178 static const String _jsInteropEscapePrefix = r'JS$';
166 179
167 /// Returns `true` if [element] is explicitly marked as part of JsInterop. 180 /// Returns `true` if [element] is explicitly marked as part of JsInterop.
168 bool _isJsInterop(Element element) { 181 bool _isJsInteropLibrary(LibraryElement element) {
169 return jsInteropNames.containsKey(element.declaration); 182 return jsInteropLibraryNames.containsKey(element);
170 } 183 }
171 184
172 /// Marks [element] as an explicit part of JsInterop. The js interop name is 185 /// Returns `true` if [element] is explicitly marked as part of JsInterop.
173 /// expected to be computed later. 186 bool _isJsInteropClass(ClassElement element) {
174 void markAsJsInterop(Element element) { 187 return jsInteropClassNames.containsKey(element);
175 jsInteropNames[element.declaration] = null; 188 }
189
190 /// Returns `true` if [element] is explicitly marked as part of JsInterop.
191 bool _isJsInteropMember(MemberElement element) {
192 return jsInteropMemberNames.containsKey(element);
176 } 193 }
177 194
178 @override 195 @override
179 void markAsJsInteropLibrary(LibraryElement element) { 196 void markAsJsInteropLibrary(LibraryElement element) {
180 markAsJsInterop(element); 197 jsInteropLibraryNames[element] = null;
181 } 198 }
182 199
183 @override 200 @override
184 void markAsJsInteropClass(ClassElement element) { 201 void markAsJsInteropClass(ClassElement element) {
185 markAsJsInterop(element); 202 jsInteropClassNames[element] = null;
186 } 203 }
187 204
188 @override 205 @override
189 void markAsJsInteropMember(MemberElement element) { 206 void markAsJsInteropMember(MemberElement element) {
190 markAsJsInterop(element); 207 jsInteropMemberNames[element] = null;
191 } 208 }
192 209
193 /// Sets the explicit js interop [name] for [element]. 210 /// Sets the explicit js interop [name] for the library [element].
194 void setJsInteropName(Element element, String name) { 211 void setJsInteropLibraryName(LibraryElement element, String name) {
195 assert(invariant(element, isJsInterop(element), 212 assert(invariant(element, _isJsInteropLibrary(element),
196 message: 213 message:
197 'Element $element is not js interop but given a js interop name.')); 214 'Library $element is not js interop but given a js interop name.'));
198 jsInteropNames[element.declaration] = name; 215 jsInteropLibraryNames[element] = name;
199 } 216 }
200 217
201 /// Returns the explicit js interop name for [element]. 218 /// Sets the explicit js interop [name] for the class [element].
202 String getJsInteropName(Element element) { 219 void setJsInteropClassName(ClassElement element, String name) {
203 return jsInteropNames[element.declaration]; 220 assert(invariant(element, _isJsInteropClass(element),
221 message:
222 'Class $element is not js interop but given a js interop name.'));
223 jsInteropClassNames[element] = name;
204 } 224 }
205 225
206 /// Returns `true` if [element] is part of JsInterop. 226 /// Sets the explicit js interop [name] for the member [element].
207 bool isJsInterop(Element element) { 227 void setJsInteropMemberName(MemberElement element, String name) {
208 // An function is part of JsInterop in the following cases: 228 assert(invariant(element, _isJsInteropMember(element),
209 // * It has a jsInteropName annotation 229 message:
210 // * It is external member of a class or library tagged as JsInterop. 230 'Member $element is not js interop but given a js interop name.'));
231 jsInteropMemberNames[element] = name;
232 }
233
234 /// Returns the explicit js interop name for library [element].
235 String getJsInteropLibraryName(LibraryElement element) {
236 return jsInteropLibraryNames[element];
237 }
238
239 /// Returns the explicit js interop name for class [element].
240 String getJsInteropClassName(ClassElement element) {
241 return jsInteropClassNames[element];
242 }
243
244 /// Returns the explicit js interop name for member [element].
245 String getJsInteropMemberName(MemberElement element) {
246 return jsInteropMemberNames[element];
247 }
248
249 /// Returns `true` if [element] is a JsInterop library.
250 bool isJsInteropLibrary(LibraryElement element) =>
251 _isJsInteropLibrary(element);
252
253 /// Returns `true` if [element] is a JsInterop class.
254 bool isJsInteropClass(ClassElement element) => _isJsInteropClass(element);
255
256 /// Returns `true` if [element] is a JsInterop method.
257 bool isJsInteropMember(MemberElement element) {
211 if (element.isFunction || element.isConstructor || element.isAccessor) { 258 if (element.isFunction || element.isConstructor || element.isAccessor) {
212 FunctionElement function = element; 259 MethodElement function = element;
213 if (!function.isExternal) return false; 260 if (!function.isExternal) return false;
214 261
215 if (_isJsInterop(function)) return true; 262 if (_isJsInteropMember(function)) return true;
216 if (function.isClassMember) return isJsInterop(function.contextClass); 263 if (function.isClassMember) {
217 if (function.isTopLevel) return isJsInterop(function.library); 264 return _isJsInteropClass(function.enclosingClass);
265 }
266 if (function.isTopLevel) {
267 return _isJsInteropLibrary(function.library);
268 }
218 return false; 269 return false;
219 } else { 270 } else {
220 return _isJsInterop(element); 271 return _isJsInteropMember(element);
221 } 272 }
222 } 273 }
223 274
224 /// Returns `true` if [element] is a JsInterop library.
225 bool isJsInteropLibrary(LibraryElement element) => isJsInterop(element);
226
227 /// Returns `true` if [element] is a JsInterop class.
228 bool isJsInteropClass(ClassElement element) => isJsInterop(element);
229
230 /// Returns `true` if [element] is a JsInterop method.
231 bool isJsInteropMember(MethodElement element) => isJsInterop(element);
232
233 /// Returns `true` if the name of [element] is fixed for the generated 275 /// Returns `true` if the name of [element] is fixed for the generated
234 /// JavaScript. 276 /// JavaScript.
235 bool hasFixedBackendName(Element element) { 277 bool hasFixedBackendName(MemberElement element) {
236 return isJsInterop(element) || 278 return isJsInteropMember(element) ||
237 nativeMemberName.containsKey(element.declaration); 279 nativeMemberName.containsKey(element.declaration);
238 } 280 }
239 281
240 String _jsNameHelper(Element element) {
241 String jsInteropName = jsInteropNames[element.declaration];
242 assert(invariant(element, !(_isJsInterop(element) && jsInteropName == null),
243 message:
244 'Element $element is js interop but js interop name has not yet '
245 'been computed.'));
246 if (jsInteropName != null && jsInteropName.isNotEmpty) {
247 return jsInteropName;
248 }
249 return element.isLibrary ? 'self' : getUnescapedJSInteropName(element.name);
250 }
251
252 /// Computes the name for [element] to use in the generated JavaScript. This 282 /// Computes the name for [element] to use in the generated JavaScript. This
253 /// is either given through a native annotation or a js interop annotation. 283 /// is either given through a native annotation or a js interop annotation.
254 String getFixedBackendName(Entity entity) { 284 String getFixedBackendName(MemberElement element) {
255 // TODO(johnniwinther): Remove this assignment from [Entity] to [Element]
256 // when `.declaration` is no longer needed.
257 Element element = entity;
258 String name = nativeMemberName[element.declaration]; 285 String name = nativeMemberName[element.declaration];
259 if (name == null && isJsInterop(element)) { 286 if (name == null && isJsInteropMember(element)) {
260 // If an element isJsInterop but _isJsInterop is false that means it is 287 // If an element isJsInterop but _isJsInterop is false that means it is
261 // considered interop as the parent class is interop. 288 // considered interop as the parent class is interop.
262 name = _jsNameHelper( 289 name = element.isConstructor
263 element.isConstructor ? element.enclosingClass : element); 290 ? _jsClassNameHelper(element.enclosingClass)
291 : _jsMemberNameHelper(element);
264 nativeMemberName[element.declaration] = name; 292 nativeMemberName[element.declaration] = name;
265 } 293 }
266 return name; 294 return name;
267 } 295 }
268 296
269 /// Whether [element] corresponds to a native JavaScript construct either 297 String _jsLibraryNameHelper(LibraryElement element) {
270 /// through the native mechanism (`@Native(...)` or the `native` pseudo 298 String jsInteropName = getJsInteropLibraryName(element);
271 /// keyword) which is only allowed for internal libraries or via the typed 299 if (jsInteropName != null && jsInteropName.isNotEmpty) return jsInteropName;
272 /// JavaScriptInterop mechanism which is allowed for user libraries. 300 return 'self';
273 bool isNative(Element element) { 301 }
274 if (isJsInterop(element)) return true; 302
275 if (element.isClass) { 303 String _jsClassNameHelper(ClassElement element) {
276 return nativeClassTagInfo.containsKey(element.declaration); 304 String jsInteropName = getJsInteropClassName(element);
277 } else { 305 if (jsInteropName != null && jsInteropName.isNotEmpty) return jsInteropName;
278 return nativeMemberName.containsKey(element.declaration); 306 return computeUnescapedJSInteropName(element.name);
307 }
308
309 String _jsMemberNameHelper(MemberElement element) {
310 String jsInteropName = jsInteropMemberNames[element];
311 assert(invariant(element,
312 !(jsInteropMemberNames.containsKey(element) && jsInteropName == null),
313 message:
314 'Member $element is js interop but js interop name has not yet '
315 'been computed.'));
316 if (jsInteropName != null && jsInteropName.isNotEmpty) {
317 return jsInteropName;
279 } 318 }
319 return computeUnescapedJSInteropName(element.name);
320 }
321
322 /// Returns a JavaScript path specifying the context in which
323 /// [element.fixedBackendName] should be evaluated. Only applicable for
324 /// elements using typed JavaScript interop.
325 /// For example: fixedBackendPath for the static method createMap in the
326 /// Map class of the goog.map JavaScript library would have path
327 /// "goog.maps.Map".
328 String getFixedBackendMethodPath(MethodElement element) {
329 if (!isJsInteropMember(element)) return null;
330 if (element.isInstanceMember) return 'this';
331 if (element.isConstructor) {
332 return _fixedBackendClassPath(element.enclosingClass);
333 }
334 StringBuffer sb = new StringBuffer();
335 sb.write(_jsLibraryNameHelper(element.library));
336 if (element.enclosingClass != null) {
337 sb..write('.')..write(_jsClassNameHelper(element.enclosingClass));
338 }
339 return sb.toString();
340 }
341
342 String _fixedBackendClassPath(ClassElement element) {
343 if (!isJsInteropClass(element)) return null;
344 return _jsLibraryNameHelper(element.library);
280 } 345 }
281 346
282 /// Returns `true` if [cls] is a native class. 347 /// Returns `true` if [cls] is a native class.
283 bool isNativeClass(ClassElement element) => isNative(element); 348 bool isNativeClass(ClassElement element) {
349 if (isJsInteropClass(element)) return true;
350 return nativeClassTagInfo.containsKey(element);
351 }
284 352
285 /// Returns `true` if [element] is a native member of a native class. 353 /// Returns `true` if [element] is a native member of a native class.
286 bool isNativeMember(MemberElement element) => isNative(element); 354 bool isNativeMember(MemberElement element) {
355 if (isJsInteropMember(element)) return true;
356 return nativeMemberName.containsKey(element);
357 }
287 358
288 /// Returns `true` if [element] or any of its superclasses is native. 359 /// Returns `true` if [element] or any of its superclasses is native.
289 bool isNativeOrExtendsNative(ClassElement element) { 360 bool isNativeOrExtendsNative(ClassElement element) {
290 if (element == null) return false; 361 if (element == null) return false;
291 if (isNativeClass(element) || isJsInteropClass(element)) { 362 if (isNativeClass(element) || isJsInteropClass(element)) {
292 return true; 363 return true;
293 } 364 }
294 assert(element.isResolved); 365 assert(element.isResolved);
295 return isNativeOrExtendsNative(element.superclass); 366 return isNativeOrExtendsNative(element.superclass);
296 } 367 }
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
383 } 454 }
384 455
385 /// Registers the [behavior] for writing to the native [field]. 456 /// Registers the [behavior] for writing to the native [field].
386 void setNativeFieldStoreBehavior( 457 void setNativeFieldStoreBehavior(
387 FieldElement field, NativeBehavior behavior) { 458 FieldElement field, NativeBehavior behavior) {
388 nativeFieldStoreBehavior[field] = behavior; 459 nativeFieldStoreBehavior[field] = behavior;
389 } 460 }
390 461
391 /// Apply JS$ escaping scheme to convert possible escaped Dart names into 462 /// Apply JS$ escaping scheme to convert possible escaped Dart names into
392 /// JS names. 463 /// JS names.
393 String getUnescapedJSInteropName(String name) { 464 String computeUnescapedJSInteropName(String name) {
394 return name.startsWith(_jsInteropEscapePrefix) 465 return name.startsWith(_jsInteropEscapePrefix)
395 ? name.substring(_jsInteropEscapePrefix.length) 466 ? name.substring(_jsInteropEscapePrefix.length)
396 : name; 467 : name;
397 } 468 }
398 } 469 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/js_backend/namer.dart ('k') | pkg/compiler/lib/src/js_emitter/native_emitter.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698