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

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

Issue 2732793002: Add NativeDataResolver (Closed)
Patch Set: Fix. 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) 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 '../common.dart'; 5 import '../common.dart';
6 import '../common/backend_api.dart' show ForeignResolver; 6 import '../common/backend_api.dart' show ForeignResolver;
7 import '../common/resolution.dart' show Resolution; 7 import '../common/resolution.dart' show Resolution;
8 import '../compiler.dart' show Compiler; 8 import '../compiler.dart' show Compiler;
9 import '../constants/values.dart'; 9 import '../constants/values.dart';
10 import '../common_elements.dart' show CommonElements; 10 import '../common_elements.dart' show CommonElements;
11 import '../elements/elements.dart'; 11 import '../elements/elements.dart';
12 import '../elements/entities.dart'; 12 import '../elements/entities.dart';
13 import '../elements/modelx.dart' show FunctionElementX; 13 import '../elements/modelx.dart' show FunctionElementX;
14 import '../elements/resolution_types.dart'; 14 import '../elements/resolution_types.dart';
15 import '../elements/types.dart'; 15 import '../elements/types.dart';
16 import '../js_backend/backend_helpers.dart' show BackendHelpers; 16 import '../js_backend/backend_helpers.dart' show BackendHelpers;
17 import '../js_backend/backend_usage.dart' show BackendUsageBuilder; 17 import '../js_backend/backend_usage.dart' show BackendUsageBuilder;
18 import '../js_backend/js_backend.dart'; 18 import '../js_backend/js_backend.dart';
19 import '../js_backend/native_data.dart' show NativeClassDataBuilder;
19 import '../js_emitter/js_emitter.dart' show CodeEmitterTask, NativeEmitter; 20 import '../js_emitter/js_emitter.dart' show CodeEmitterTask, NativeEmitter;
20 import 'package:front_end/src/fasta/scanner.dart' show BeginGroupToken, Token; 21 import 'package:front_end/src/fasta/scanner.dart' show BeginGroupToken, Token;
21 import 'package:front_end/src/fasta/scanner.dart' as Tokens show EOF_TOKEN; 22 import 'package:front_end/src/fasta/scanner.dart' as Tokens show EOF_TOKEN;
22 import '../tree/tree.dart'; 23 import '../tree/tree.dart';
23 import '../universe/use.dart' show StaticUse, TypeUse; 24 import '../universe/use.dart' show StaticUse, TypeUse;
24 import '../universe/world_impact.dart' 25 import '../universe/world_impact.dart'
25 show WorldImpact, WorldImpactBuilder, WorldImpactBuilderImpl; 26 show WorldImpact, WorldImpactBuilder, WorldImpactBuilderImpl;
26 import 'behavior.dart'; 27 import 'behavior.dart';
27 28
28 /** 29 /**
29 * This could be an abstract class but we use it as a stub for the dart_backend. 30 * This could be an abstract class but we use it as a stub for the dart_backend.
30 */ 31 */
31 class NativeEnqueuer { 32 class NativeEnqueuer {
32 /// Called when a [type] has been instantiated natively. 33 /// Called when a [type] has been instantiated natively.
33 void onInstantiatedType(InterfaceType type) {} 34 void onInstantiatedType(InterfaceType type) {}
34 35
35 /// Initial entry point to native enqueuer. 36 /// Initial entry point to native enqueuer.
36 WorldImpact processNativeClasses(Iterable<LibraryElement> libraries) => 37 WorldImpact processNativeClasses(Iterable<LibraryElement> libraries) =>
37 const WorldImpact(); 38 const WorldImpact();
38 39
39 /// Registers the [nativeBehavior]. Adds the liveness of its instantiated 40 /// Registers the [nativeBehavior]. Adds the liveness of its instantiated
40 /// types to the world. 41 /// types to the world.
41 void registerNativeBehavior( 42 void registerNativeBehavior(
42 WorldImpactBuilder impactBuilder, NativeBehavior nativeBehavior, cause) {} 43 WorldImpactBuilder impactBuilder, NativeBehavior nativeBehavior, cause) {}
43 44
44 // TODO(johnniwinther): Move [handleFieldAnnotations] and
45 // [handleMethodAnnotations] to [JavaScriptBackend] or [NativeData].
46 // TODO(johnniwinther): Change the return type to 'bool' and rename them to
47 // something like `computeNativeField`.
48 /// Process the potentially native [field]. Adds information from metadata
49 /// attributes.
50 void handleFieldAnnotations(Element field) {}
51
52 /// Process the potentially native [method]. Adds information from metadata
53 /// attributes.
54 void handleMethodAnnotations(Element method) {}
55
56 /// Returns whether native classes are being used. 45 /// Returns whether native classes are being used.
57 bool get hasInstantiatedNativeClasses => false; 46 bool get hasInstantiatedNativeClasses => false;
58 47
59 /// Emits a summary information using the [log] function. 48 /// Emits a summary information using the [log] function.
60 void logSummary(log(message)) {} 49 void logSummary(log(message)) {}
61 } 50 }
62 51
63 abstract class NativeEnqueuerBase implements NativeEnqueuer { 52 abstract class NativeEnqueuerBase implements NativeEnqueuer {
64 static final RegExp _identifier = new RegExp(r'^[a-zA-Z_$][a-zA-Z0-9_$]*$');
65
66 /// The set of all native classes. Each native class is in [nativeClasses] 53 /// The set of all native classes. Each native class is in [nativeClasses]
67 /// and exactly one of [unusedClasses] and [registeredClasses]. 54 /// and exactly one of [unusedClasses] and [registeredClasses].
68 final Set<ClassElement> _nativeClasses = new Set<ClassElement>(); 55 final Set<ClassElement> _nativeClasses = new Set<ClassElement>();
69 56
70 final Set<ClassElement> _registeredClasses = new Set<ClassElement>(); 57 final Set<ClassElement> _registeredClasses = new Set<ClassElement>();
71 final Set<ClassElement> _unusedClasses = new Set<ClassElement>(); 58 final Set<ClassElement> _unusedClasses = new Set<ClassElement>();
72 59
73 bool get hasInstantiatedNativeClasses => !_registeredClasses.isEmpty; 60 bool get hasInstantiatedNativeClasses => !_registeredClasses.isEmpty;
74 61
75 final Set<ClassElement> nativeClassesAndSubclasses = new Set<ClassElement>(); 62 final Set<ClassElement> nativeClassesAndSubclasses = new Set<ClassElement>();
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after
246 } 233 }
247 // Should be at '{', 'with', 'implements', '<' or 'native'. 234 // Should be at '{', 'with', 'implements', '<' or 'native'.
248 return id.value; 235 return id.value;
249 } 236 }
250 237
251 return reporter.withCurrentElement(classElement, () { 238 return reporter.withCurrentElement(classElement, () {
252 return scanForExtendsName(classElement.position); 239 return scanForExtendsName(classElement.position);
253 }); 240 });
254 } 241 }
255 242
256 /// Returns the JSName annotation string or `null` if no JSName annotation is
257 /// present.
258 String findJsNameFromAnnotation(Element element) {
259 String name = null;
260 ClassElement annotationClass = backend.helpers.annotationJSNameClass;
261 for (MetadataAnnotation annotation in element.implementation.metadata) {
262 annotation.ensureResolved(resolution);
263 ConstantValue value =
264 compiler.constants.getConstantValue(annotation.constant);
265 if (!value.isConstructedObject) continue;
266 ConstructedConstantValue constructedObject = value;
267 if (constructedObject.type.element != annotationClass) continue;
268
269 Iterable<ConstantValue> fields = constructedObject.fields.values;
270 // TODO(sra): Better validation of the constant.
271 if (fields.length != 1 || fields.single is! StringConstantValue) {
272 reporter.internalError(
273 annotation, 'Annotations needs one string: ${annotation}');
274 }
275 StringConstantValue specStringConstant = fields.single;
276 String specString = specStringConstant.toDartString().slowToString();
277 if (name == null) {
278 name = specString;
279 } else {
280 reporter.internalError(
281 annotation, 'Too many JSName annotations: ${annotation}');
282 }
283 }
284 return name;
285 }
286
287 /// Register [classes] as natively instantiated in [impactBuilder]. 243 /// Register [classes] as natively instantiated in [impactBuilder].
288 void _registerTypeUses( 244 void _registerTypeUses(
289 WorldImpactBuilder impactBuilder, Set<ClassElement> classes, cause) { 245 WorldImpactBuilder impactBuilder, Set<ClassElement> classes, cause) {
290 for (ClassElement cls in classes) { 246 for (ClassElement cls in classes) {
291 if (!_unusedClasses.contains(cls)) { 247 if (!_unusedClasses.contains(cls)) {
292 // No need to add [classElement] to [impactBuilder]: it has already been 248 // No need to add [classElement] to [impactBuilder]: it has already been
293 // instantiated and we don't track origins of native instantiations 249 // instantiated and we don't track origins of native instantiations
294 // precisely. 250 // precisely.
295 continue; 251 continue;
296 } 252 }
297 cls.ensureResolved(resolution); 253 cls.ensureResolved(resolution);
298 impactBuilder 254 impactBuilder
299 .registerTypeUse(new TypeUse.nativeInstantiation(cls.rawType)); 255 .registerTypeUse(new TypeUse.nativeInstantiation(cls.rawType));
300 } 256 }
301 } 257 }
302 258
303 void handleFieldAnnotations(Element element) {
304 if (compiler.serialization.isDeserialized(element)) {
305 return;
306 }
307 if (element.isInstanceMember &&
308 backend.nativeClassData.isNativeClass(element.enclosingClass)) {
309 // Exclude non-instance (static) fields - they are not really native and
310 // are compiled as isolate globals. Access of a property of a constructor
311 // function or a non-method property in the prototype chain, must be coded
312 // using a JS-call.
313 _setNativeName(element);
314 }
315 }
316
317 void handleMethodAnnotations(Element method) {
318 if (compiler.serialization.isDeserialized(method)) {
319 return;
320 }
321 if (isNativeMethod(method)) {
322 if (method.isStatic) {
323 _setNativeNameForStaticMethod(method);
324 } else {
325 _setNativeName(method);
326 }
327 }
328 }
329
330 /// Sets the native name of [element], either from an annotation, or
331 /// defaulting to the Dart name.
332 void _setNativeName(MemberElement element) {
333 String name = findJsNameFromAnnotation(element);
334 if (name == null) name = element.name;
335 backend.nativeClassDataBuilder.setNativeMemberName(element, name);
336 }
337
338 /// Sets the native name of the static native method [element], using the
339 /// following rules:
340 /// 1. If [element] has a @JSName annotation that is an identifier, qualify
341 /// that identifier to the @Native name of the enclosing class
342 /// 2. If [element] has a @JSName annotation that is not an identifier,
343 /// use the declared @JSName as the expression
344 /// 3. If [element] does not have a @JSName annotation, qualify the name of
345 /// the method with the @Native name of the enclosing class.
346 void _setNativeNameForStaticMethod(MethodElement element) {
347 String name = findJsNameFromAnnotation(element);
348 if (name == null) name = element.name;
349 if (isIdentifier(name)) {
350 List<String> nativeNames = backend.nativeClassDataBuilder
351 .getNativeTagsOfClassRaw(element.enclosingClass);
352 if (nativeNames.length != 1) {
353 reporter.internalError(
354 element,
355 'Unable to determine a native name for the enclosing class, '
356 'options: $nativeNames');
357 }
358 backend.nativeClassDataBuilder
359 .setNativeMemberName(element, '${nativeNames[0]}.$name');
360 } else {
361 backend.nativeClassDataBuilder.setNativeMemberName(element, name);
362 }
363 }
364
365 bool isIdentifier(String s) => _identifier.hasMatch(s);
366
367 bool isNativeMethod(FunctionElementX element) {
368 if (!backend.canLibraryUseNative(element.library)) return false;
369 // Native method?
370 return reporter.withCurrentElement(element, () {
371 Node node = element.parseNode(resolution.parsingContext);
372 if (node is! FunctionExpression) return false;
373 FunctionExpression functionExpression = node;
374 node = functionExpression.body;
375 Token token = node.getBeginToken();
376 if (identical(token.stringValue, 'native')) return true;
377 return false;
378 });
379 }
380
381 void registerNativeBehavior( 259 void registerNativeBehavior(
382 WorldImpactBuilder impactBuilder, NativeBehavior nativeBehavior, cause) { 260 WorldImpactBuilder impactBuilder, NativeBehavior nativeBehavior, cause) {
383 _processNativeBehavior(impactBuilder, nativeBehavior, cause); 261 _processNativeBehavior(impactBuilder, nativeBehavior, cause);
384 } 262 }
385 263
386 void _processNativeBehavior( 264 void _processNativeBehavior(
387 WorldImpactBuilder impactBuilder, NativeBehavior behavior, cause) { 265 WorldImpactBuilder impactBuilder, NativeBehavior behavior, cause) {
388 void registerInstantiation(ResolutionInterfaceType type) { 266 void registerInstantiation(ResolutionInterfaceType type) {
389 impactBuilder.registerTypeUse(new TypeUse.nativeInstantiation(type)); 267 impactBuilder.registerTypeUse(new TypeUse.nativeInstantiation(type));
390 } 268 }
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
482 360
483 void registerBackendUse(MethodElement element) { 361 void registerBackendUse(MethodElement element) {
484 _backendUsageBuilder.registerBackendFunctionUse(element); 362 _backendUsageBuilder.registerBackendFunctionUse(element);
485 _backendUsageBuilder.registerGlobalFunctionDependency(element); 363 _backendUsageBuilder.registerGlobalFunctionDependency(element);
486 } 364 }
487 365
488 void processNativeClass(ClassElement classElement) { 366 void processNativeClass(ClassElement classElement) {
489 super.processNativeClass(classElement); 367 super.processNativeClass(classElement);
490 368
491 // Js Interop interfaces do not have tags. 369 // Js Interop interfaces do not have tags.
492 if (backend.nativeData.isJsInterop(classElement)) return; 370 if (backend.nativeData.isJsInteropClass(classElement)) return;
493 // Since we map from dispatch tags to classes, a dispatch tag must be used 371 // Since we map from dispatch tags to classes, a dispatch tag must be used
494 // on only one native class. 372 // on only one native class.
495 for (String tag in backend.nativeData.getNativeTagsOfClass(classElement)) { 373 for (String tag in backend.nativeData.getNativeTagsOfClass(classElement)) {
496 ClassElement owner = tagOwner[tag]; 374 ClassElement owner = tagOwner[tag];
497 if (owner != null) { 375 if (owner != null) {
498 if (owner != classElement) { 376 if (owner != classElement) {
499 reporter.internalError( 377 reporter.internalError(
500 classElement, "Tag '$tag' already in use by '${owner.name}'"); 378 classElement, "Tag '$tag' already in use by '${owner.name}'");
501 } 379 }
502 } else { 380 } else {
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
620 List<ClassEntity> directSubtypes = 498 List<ClassEntity> directSubtypes =
621 emitter.directSubtypes.putIfAbsent(superclass, () => <ClassEntity>[]); 499 emitter.directSubtypes.putIfAbsent(superclass, () => <ClassEntity>[]);
622 directSubtypes.add(cls); 500 directSubtypes.add(cls);
623 } 501 }
624 502
625 void logSummary(log(message)) { 503 void logSummary(log(message)) {
626 log('Compiled ${_registeredClasses.length} native classes, ' 504 log('Compiled ${_registeredClasses.length} native classes, '
627 '${_unusedClasses.length} native classes omitted.'); 505 '${_unusedClasses.length} native classes omitted.');
628 } 506 }
629 } 507 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698