OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 } |
OLD | NEW |