| 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 'dart:collection' show Queue; | 5 import 'dart:collection' show Queue; |
| 6 | 6 |
| 7 import '../common.dart'; | 7 import '../common.dart'; |
| 8 import '../common/backend_api.dart' show | 8 import '../common/backend_api.dart' show ForeignResolver; |
| 9 ForeignResolver; | 9 import '../common/registry.dart' show Registry; |
| 10 import '../common/registry.dart' show | 10 import '../common/resolution.dart' show Parsing, Resolution; |
| 11 Registry; | 11 import '../compiler.dart' show Compiler; |
| 12 import '../common/resolution.dart' show | |
| 13 Parsing, | |
| 14 Resolution; | |
| 15 import '../compiler.dart' show | |
| 16 Compiler; | |
| 17 import '../constants/values.dart'; | 12 import '../constants/values.dart'; |
| 18 import '../core_types.dart' show | 13 import '../core_types.dart' show CoreTypes; |
| 19 CoreTypes; | |
| 20 import '../dart_types.dart'; | 14 import '../dart_types.dart'; |
| 21 import '../enqueue.dart' show | 15 import '../enqueue.dart' show Enqueuer, ResolutionEnqueuer; |
| 22 Enqueuer, | |
| 23 ResolutionEnqueuer; | |
| 24 import '../elements/elements.dart'; | 16 import '../elements/elements.dart'; |
| 25 import '../elements/modelx.dart' show | 17 import '../elements/modelx.dart' |
| 26 BaseClassElementX, | 18 show BaseClassElementX, ElementX, FunctionElementX, LibraryElementX; |
| 27 ElementX, | 19 import '../js_backend/backend_helpers.dart' show BackendHelpers; |
| 28 FunctionElementX, | |
| 29 LibraryElementX; | |
| 30 import '../js_backend/backend_helpers.dart' show | |
| 31 BackendHelpers; | |
| 32 import '../js_backend/js_backend.dart'; | 20 import '../js_backend/js_backend.dart'; |
| 33 import '../js_emitter/js_emitter.dart' show | 21 import '../js_emitter/js_emitter.dart' show CodeEmitterTask, NativeEmitter; |
| 34 CodeEmitterTask, | 22 import '../tokens/token.dart' show BeginGroupToken, Token; |
| 35 NativeEmitter; | 23 import '../tokens/token_constants.dart' as Tokens show EOF_TOKEN, STRING_TOKEN; |
| 36 import '../tokens/token.dart' show | |
| 37 BeginGroupToken, | |
| 38 Token; | |
| 39 import '../tokens/token_constants.dart' as Tokens show | |
| 40 EOF_TOKEN, | |
| 41 STRING_TOKEN; | |
| 42 import '../tree/tree.dart'; | 24 import '../tree/tree.dart'; |
| 43 | 25 |
| 44 import 'behavior.dart'; | 26 import 'behavior.dart'; |
| 45 | 27 |
| 46 /** | 28 /** |
| 47 * This could be an abstract class but we use it as a stub for the dart_backend. | 29 * This could be an abstract class but we use it as a stub for the dart_backend. |
| 48 */ | 30 */ |
| 49 class NativeEnqueuer { | 31 class NativeEnqueuer { |
| 50 /// Initial entry point to native enqueuer. | 32 /// Initial entry point to native enqueuer. |
| 51 void processNativeClasses(Iterable<LibraryElement> libraries) {} | 33 void processNativeClasses(Iterable<LibraryElement> libraries) {} |
| (...skipping 23 matching lines...) Expand all Loading... |
| 75 | 57 |
| 76 /// Emits a summary information using the [log] function. | 58 /// Emits a summary information using the [log] function. |
| 77 void logSummary(log(message)) {} | 59 void logSummary(log(message)) {} |
| 78 | 60 |
| 79 // Do not use annotations in dart2dart. | 61 // Do not use annotations in dart2dart. |
| 80 ClassElement get annotationCreatesClass => null; | 62 ClassElement get annotationCreatesClass => null; |
| 81 ClassElement get annotationReturnsClass => null; | 63 ClassElement get annotationReturnsClass => null; |
| 82 ClassElement get annotationJsNameClass => null; | 64 ClassElement get annotationJsNameClass => null; |
| 83 } | 65 } |
| 84 | 66 |
| 85 | |
| 86 abstract class NativeEnqueuerBase implements NativeEnqueuer { | 67 abstract class NativeEnqueuerBase implements NativeEnqueuer { |
| 87 static final RegExp _identifier = new RegExp(r'^[a-zA-Z_$][a-zA-Z0-9_$]*$'); | 68 static final RegExp _identifier = new RegExp(r'^[a-zA-Z_$][a-zA-Z0-9_$]*$'); |
| 88 | 69 |
| 89 /** | 70 /** |
| 90 * The set of all native classes. Each native class is in [nativeClasses] and | 71 * The set of all native classes. Each native class is in [nativeClasses] and |
| 91 * exactly one of [unusedClasses], [pendingClasses] and [registeredClasses]. | 72 * exactly one of [unusedClasses], [pendingClasses] and [registeredClasses]. |
| 92 */ | 73 */ |
| 93 final Set<ClassElement> nativeClasses = new Set<ClassElement>(); | 74 final Set<ClassElement> nativeClasses = new Set<ClassElement>(); |
| 94 | 75 |
| 95 final Set<ClassElement> registeredClasses = new Set<ClassElement>(); | 76 final Set<ClassElement> registeredClasses = new Set<ClassElement>(); |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 181 // | 162 // |
| 182 // String "A" has a potential subclass B. | 163 // String "A" has a potential subclass B. |
| 183 | 164 |
| 184 var potentialExtends = new Map<String, Set<ClassElement>>(); | 165 var potentialExtends = new Map<String, Set<ClassElement>>(); |
| 185 | 166 |
| 186 libraries.forEach((library) { | 167 libraries.forEach((library) { |
| 187 library.implementation.forEachLocalMember((element) { | 168 library.implementation.forEachLocalMember((element) { |
| 188 if (element.isClass) { | 169 if (element.isClass) { |
| 189 String extendsName = findExtendsNameOfClass(element); | 170 String extendsName = findExtendsNameOfClass(element); |
| 190 if (extendsName != null) { | 171 if (extendsName != null) { |
| 191 Set<ClassElement> potentialSubclasses = | 172 Set<ClassElement> potentialSubclasses = potentialExtends |
| 192 potentialExtends.putIfAbsent( | 173 .putIfAbsent(extendsName, () => new Set<ClassElement>()); |
| 193 extendsName, | |
| 194 () => new Set<ClassElement>()); | |
| 195 potentialSubclasses.add(element); | 174 potentialSubclasses.add(element); |
| 196 } | 175 } |
| 197 } | 176 } |
| 198 }); | 177 }); |
| 199 }); | 178 }); |
| 200 | 179 |
| 201 // Resolve all the native classes and any classes that might extend them in | 180 // Resolve all the native classes and any classes that might extend them in |
| 202 // [potentialExtends], and then check that the properly resolved class is in | 181 // [potentialExtends], and then check that the properly resolved class is in |
| 203 // fact a subclass of a native class. | 182 // fact a subclass of a native class. |
| 204 | 183 |
| 205 ClassElement nativeSuperclassOf(ClassElement classElement) { | 184 ClassElement nativeSuperclassOf(ClassElement classElement) { |
| 206 if (backend.isNative(classElement)) return classElement; | 185 if (backend.isNative(classElement)) return classElement; |
| 207 if (classElement.superclass == null) return null; | 186 if (classElement.superclass == null) return null; |
| 208 return nativeSuperclassOf(classElement.superclass); | 187 return nativeSuperclassOf(classElement.superclass); |
| 209 } | 188 } |
| 210 | 189 |
| 211 void walkPotentialSubclasses(ClassElement element) { | 190 void walkPotentialSubclasses(ClassElement element) { |
| 212 if (nativeClassesAndSubclasses.contains(element)) return; | 191 if (nativeClassesAndSubclasses.contains(element)) return; |
| 213 element.ensureResolved(resolution); | 192 element.ensureResolved(resolution); |
| 214 ClassElement nativeSuperclass = nativeSuperclassOf(element); | 193 ClassElement nativeSuperclass = nativeSuperclassOf(element); |
| 215 if (nativeSuperclass != null) { | 194 if (nativeSuperclass != null) { |
| 216 nativeClassesAndSubclasses.add(element); | 195 nativeClassesAndSubclasses.add(element); |
| 217 if (!backend.isNative(element)) { | 196 if (!backend.isNative(element)) { |
| 218 nonNativeSubclasses.putIfAbsent(nativeSuperclass, | 197 nonNativeSubclasses |
| 219 () => new Set<ClassElement>()) | 198 .putIfAbsent(nativeSuperclass, () => new Set<ClassElement>()) |
| 220 .add(element); | 199 .add(element); |
| 221 } | 200 } |
| 222 Set<ClassElement> potentialSubclasses = potentialExtends[element.name]; | 201 Set<ClassElement> potentialSubclasses = potentialExtends[element.name]; |
| 223 if (potentialSubclasses != null) { | 202 if (potentialSubclasses != null) { |
| 224 potentialSubclasses.forEach(walkPotentialSubclasses); | 203 potentialSubclasses.forEach(walkPotentialSubclasses); |
| 225 } | 204 } |
| 226 } | 205 } |
| 227 } | 206 } |
| 228 | 207 |
| 229 nativeClasses.forEach(walkPotentialSubclasses); | 208 nativeClasses.forEach(walkPotentialSubclasses); |
| 230 | 209 |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 341 annotation.ensureResolved(resolution); | 320 annotation.ensureResolved(resolution); |
| 342 ConstantValue value = | 321 ConstantValue value = |
| 343 compiler.constants.getConstantValue(annotation.constant); | 322 compiler.constants.getConstantValue(annotation.constant); |
| 344 if (!value.isConstructedObject) continue; | 323 if (!value.isConstructedObject) continue; |
| 345 ConstructedConstantValue constructedObject = value; | 324 ConstructedConstantValue constructedObject = value; |
| 346 if (constructedObject.type.element != annotationClass) continue; | 325 if (constructedObject.type.element != annotationClass) continue; |
| 347 | 326 |
| 348 Iterable<ConstantValue> fields = constructedObject.fields.values; | 327 Iterable<ConstantValue> fields = constructedObject.fields.values; |
| 349 // TODO(sra): Better validation of the constant. | 328 // TODO(sra): Better validation of the constant. |
| 350 if (fields.length != 1 || fields.single is! StringConstantValue) { | 329 if (fields.length != 1 || fields.single is! StringConstantValue) { |
| 351 reporter.internalError(annotation, | 330 reporter.internalError( |
| 352 'Annotations needs one string: ${annotation.node}'); | 331 annotation, 'Annotations needs one string: ${annotation.node}'); |
| 353 } | 332 } |
| 354 StringConstantValue specStringConstant = fields.single; | 333 StringConstantValue specStringConstant = fields.single; |
| 355 String specString = specStringConstant.toDartString().slowToString(); | 334 String specString = specStringConstant.toDartString().slowToString(); |
| 356 if (name == null) { | 335 if (name == null) { |
| 357 name = specString; | 336 name = specString; |
| 358 } else { | 337 } else { |
| 359 reporter.internalError(annotation, | 338 reporter.internalError( |
| 360 'Too many JSName annotations: ${annotation.node}'); | 339 annotation, 'Too many JSName annotations: ${annotation.node}'); |
| 361 } | 340 } |
| 362 } | 341 } |
| 363 return name; | 342 return name; |
| 364 } | 343 } |
| 365 | 344 |
| 366 enqueueClass(ClassElement classElement, cause) { | 345 enqueueClass(ClassElement classElement, cause) { |
| 367 assert(unusedClasses.contains(classElement)); | 346 assert(unusedClasses.contains(classElement)); |
| 368 unusedClasses.remove(classElement); | 347 unusedClasses.remove(classElement); |
| 369 pendingClasses.add(classElement); | 348 pendingClasses.add(classElement); |
| 370 queue.add(() { processClass(classElement, cause); }); | 349 queue.add(() { |
| 350 processClass(classElement, cause); |
| 351 }); |
| 371 } | 352 } |
| 372 | 353 |
| 373 void flushQueue() { | 354 void flushQueue() { |
| 374 if (flushing) return; | 355 if (flushing) return; |
| 375 flushing = true; | 356 flushing = true; |
| 376 while (!queue.isEmpty) { | 357 while (!queue.isEmpty) { |
| 377 (queue.removeFirst())(); | 358 (queue.removeFirst())(); |
| 378 } | 359 } |
| 379 flushing = false; | 360 flushing = false; |
| 380 } | 361 } |
| 381 | 362 |
| 382 processClass(ClassElement classElement, cause) { | 363 processClass(ClassElement classElement, cause) { |
| 383 // TODO(ahe): Fix this assertion to work in incremental compilation. | 364 // TODO(ahe): Fix this assertion to work in incremental compilation. |
| 384 assert(compiler.options.hasIncrementalSupport || | 365 assert(compiler.options.hasIncrementalSupport || |
| 385 !registeredClasses.contains(classElement)); | 366 !registeredClasses.contains(classElement)); |
| 386 | 367 |
| 387 bool firstTime = registeredClasses.isEmpty; | 368 bool firstTime = registeredClasses.isEmpty; |
| 388 pendingClasses.remove(classElement); | 369 pendingClasses.remove(classElement); |
| 389 registeredClasses.add(classElement); | 370 registeredClasses.add(classElement); |
| 390 | 371 |
| 391 // TODO(ahe): Is this really a global dependency? | 372 // TODO(ahe): Is this really a global dependency? |
| 392 classElement.ensureResolved(resolution); | 373 classElement.ensureResolved(resolution); |
| 393 compiler.backend.registerInstantiatedType( | 374 compiler.backend.registerInstantiatedType( |
| 394 classElement.rawType, world, compiler.globalDependencies); | 375 classElement.rawType, world, compiler.globalDependencies); |
| 395 | 376 |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 462 /// use the declared @JSName as the expression | 443 /// use the declared @JSName as the expression |
| 463 /// 3. If [element] does not have a @JSName annotation, qualify the name of | 444 /// 3. If [element] does not have a @JSName annotation, qualify the name of |
| 464 /// the method with the @Native name of the enclosing class. | 445 /// the method with the @Native name of the enclosing class. |
| 465 void _setNativeNameForStaticMethod(MethodElement element) { | 446 void _setNativeNameForStaticMethod(MethodElement element) { |
| 466 String name = findJsNameFromAnnotation(element); | 447 String name = findJsNameFromAnnotation(element); |
| 467 if (name == null) name = element.name; | 448 if (name == null) name = element.name; |
| 468 if (isIdentifier(name)) { | 449 if (isIdentifier(name)) { |
| 469 List<String> nativeNames = | 450 List<String> nativeNames = |
| 470 backend.nativeData.getNativeTagsOfClassRaw(element.enclosingClass); | 451 backend.nativeData.getNativeTagsOfClassRaw(element.enclosingClass); |
| 471 if (nativeNames.length != 1) { | 452 if (nativeNames.length != 1) { |
| 472 reporter.internalError(element, | 453 reporter.internalError( |
| 454 element, |
| 473 'Unable to determine a native name for the enclosing class, ' | 455 'Unable to determine a native name for the enclosing class, ' |
| 474 'options: $nativeNames'); | 456 'options: $nativeNames'); |
| 475 } | 457 } |
| 476 backend.nativeData.setNativeMemberName( | 458 backend.nativeData |
| 477 element, '${nativeNames[0]}.$name'); | 459 .setNativeMemberName(element, '${nativeNames[0]}.$name'); |
| 478 } else { | 460 } else { |
| 479 backend.nativeData.setNativeMemberName(element, name); | 461 backend.nativeData.setNativeMemberName(element, name); |
| 480 } | 462 } |
| 481 } | 463 } |
| 482 | 464 |
| 483 bool isIdentifier(String s) => _identifier.hasMatch(s); | 465 bool isIdentifier(String s) => _identifier.hasMatch(s); |
| 484 | 466 |
| 485 bool isNativeMethod(FunctionElementX element) { | 467 bool isNativeMethod(FunctionElementX element) { |
| 486 if (!backend.canLibraryUseNative(element.library)) return false; | 468 if (!backend.canLibraryUseNative(element.library)) return false; |
| 487 // Native method? | 469 // Native method? |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 530 continue; | 512 continue; |
| 531 } | 513 } |
| 532 if (type is InterfaceType) { | 514 if (type is InterfaceType) { |
| 533 if (type == coreTypes.intType) { | 515 if (type == coreTypes.intType) { |
| 534 backend.registerInstantiatedType(type, world, registry); | 516 backend.registerInstantiatedType(type, world, registry); |
| 535 } else if (type == coreTypes.doubleType) { | 517 } else if (type == coreTypes.doubleType) { |
| 536 backend.registerInstantiatedType(type, world, registry); | 518 backend.registerInstantiatedType(type, world, registry); |
| 537 } else if (type == coreTypes.numType) { | 519 } else if (type == coreTypes.numType) { |
| 538 backend.registerInstantiatedType( | 520 backend.registerInstantiatedType( |
| 539 coreTypes.doubleType, world, registry); | 521 coreTypes.doubleType, world, registry); |
| 540 backend.registerInstantiatedType( | 522 backend.registerInstantiatedType(coreTypes.intType, world, registry); |
| 541 coreTypes.intType, world, registry); | |
| 542 } else if (type == coreTypes.stringType) { | 523 } else if (type == coreTypes.stringType) { |
| 543 backend.registerInstantiatedType(type, world, registry); | 524 backend.registerInstantiatedType(type, world, registry); |
| 544 } else if (type == coreTypes.nullType) { | 525 } else if (type == coreTypes.nullType) { |
| 545 backend.registerInstantiatedType(type, world, registry); | 526 backend.registerInstantiatedType(type, world, registry); |
| 546 } else if (type == coreTypes.boolType) { | 527 } else if (type == coreTypes.boolType) { |
| 547 backend.registerInstantiatedType(type, world, registry); | 528 backend.registerInstantiatedType(type, world, registry); |
| 548 } else if (compiler.types.isSubtype( | 529 } else if (compiler.types |
| 549 type, backend.listImplementation.rawType)) { | 530 .isSubtype(type, backend.listImplementation.rawType)) { |
| 550 backend.registerInstantiatedType(type, world, registry); | 531 backend.registerInstantiatedType(type, world, registry); |
| 551 } | 532 } |
| 552 } | 533 } |
| 553 assert(type is DartType); | 534 assert(type is DartType); |
| 554 enqueueUnusedClassesMatching( | 535 enqueueUnusedClassesMatching( |
| 555 (nativeClass) => compiler.types.isSubtype(nativeClass.thisType, type), | 536 (nativeClass) => compiler.types.isSubtype(nativeClass.thisType, type), |
| 556 cause, | 537 cause, |
| 557 'subtypeof($type)'); | 538 'subtypeof($type)'); |
| 558 } | 539 } |
| 559 | 540 |
| 560 // Give an info so that library developers can compile with -v to find why | 541 // Give an info so that library developers can compile with -v to find why |
| 561 // all the native classes are included. | 542 // all the native classes are included. |
| 562 if (unusedClasses.isEmpty && !allUsedBefore) { | 543 if (unusedClasses.isEmpty && !allUsedBefore) { |
| 563 reporter.log('All native types marked as used due to $cause.'); | 544 reporter.log('All native types marked as used due to $cause.'); |
| 564 } | 545 } |
| 565 } | 546 } |
| 566 | 547 |
| 567 enqueueUnusedClassesMatching(bool predicate(classElement), | 548 enqueueUnusedClassesMatching(bool predicate(classElement), cause, |
| 568 cause, | 549 [String reason]) { |
| 569 [String reason]) { | |
| 570 Iterable matches = unusedClasses.where(predicate); | 550 Iterable matches = unusedClasses.where(predicate); |
| 571 matches.toList().forEach((c) => enqueueClass(c, cause)); | 551 matches.toList().forEach((c) => enqueueClass(c, cause)); |
| 572 } | 552 } |
| 573 | 553 |
| 574 onFirstNativeClass() { | 554 onFirstNativeClass() { |
| 575 staticUse(name) { | 555 staticUse(name) { |
| 576 backend.enqueue( | 556 backend.enqueue( |
| 577 world, helpers.findHelper(name), compiler.globalDependencies); | 557 world, helpers.findHelper(name), compiler.globalDependencies); |
| 578 } | 558 } |
| 579 | 559 |
| 580 staticUse('defineProperty'); | 560 staticUse('defineProperty'); |
| 581 staticUse('toStringForNativeObject'); | 561 staticUse('toStringForNativeObject'); |
| 582 staticUse('hashCodeForNativeObject'); | 562 staticUse('hashCodeForNativeObject'); |
| 583 staticUse('convertDartClosureToJS'); | 563 staticUse('convertDartClosureToJS'); |
| 584 addNativeExceptions(); | 564 addNativeExceptions(); |
| 585 } | 565 } |
| 586 | 566 |
| 587 addNativeExceptions() { | 567 addNativeExceptions() { |
| 588 enqueueUnusedClassesMatching((classElement) { | 568 enqueueUnusedClassesMatching((classElement) { |
| 589 // TODO(sra): Annotate exception classes in dart:html. | 569 // TODO(sra): Annotate exception classes in dart:html. |
| 590 String name = classElement.name; | 570 String name = classElement.name; |
| 591 if (name.contains('Exception')) return true; | 571 if (name.contains('Exception')) return true; |
| 592 if (name.contains('Error')) return true; | 572 if (name.contains('Error')) return true; |
| 593 return false; | 573 return false; |
| 594 }, | 574 }, 'native exception'); |
| 595 'native exception'); | |
| 596 } | 575 } |
| 597 } | 576 } |
| 598 | 577 |
| 599 | |
| 600 class NativeResolutionEnqueuer extends NativeEnqueuerBase { | 578 class NativeResolutionEnqueuer extends NativeEnqueuerBase { |
| 601 | |
| 602 Map<String, ClassElement> tagOwner = new Map<String, ClassElement>(); | 579 Map<String, ClassElement> tagOwner = new Map<String, ClassElement>(); |
| 603 | 580 |
| 604 NativeResolutionEnqueuer(Enqueuer world, Compiler compiler) | 581 NativeResolutionEnqueuer(Enqueuer world, Compiler compiler) |
| 605 : super(world, compiler, compiler.options.enableNativeLiveTypeAnalysis); | 582 : super(world, compiler, compiler.options.enableNativeLiveTypeAnalysis); |
| 606 | 583 |
| 607 void processNativeClass(ClassElement classElement) { | 584 void processNativeClass(ClassElement classElement) { |
| 608 super.processNativeClass(classElement); | 585 super.processNativeClass(classElement); |
| 609 | 586 |
| 610 // Js Interop interfaces do not have tags. | 587 // Js Interop interfaces do not have tags. |
| 611 if (backend.isJsInterop(classElement)) return; | 588 if (backend.isJsInterop(classElement)) return; |
| 612 // Since we map from dispatch tags to classes, a dispatch tag must be used | 589 // Since we map from dispatch tags to classes, a dispatch tag must be used |
| 613 // on only one native class. | 590 // on only one native class. |
| 614 for (String tag in backend.nativeData.getNativeTagsOfClass(classElement)) { | 591 for (String tag in backend.nativeData.getNativeTagsOfClass(classElement)) { |
| 615 ClassElement owner = tagOwner[tag]; | 592 ClassElement owner = tagOwner[tag]; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 638 * JS('_DOMWindowImpl', 'window') | 615 * JS('_DOMWindowImpl', 'window') |
| 639 * | 616 * |
| 640 */ | 617 */ |
| 641 void registerJsCall(Send node, ForeignResolver resolver) { | 618 void registerJsCall(Send node, ForeignResolver resolver) { |
| 642 NativeBehavior behavior = NativeBehavior.ofJsCall( | 619 NativeBehavior behavior = NativeBehavior.ofJsCall( |
| 643 node, reporter, compiler.parsing, compiler.coreTypes, resolver); | 620 node, reporter, compiler.parsing, compiler.coreTypes, resolver); |
| 644 registerNativeBehavior(behavior, node); | 621 registerNativeBehavior(behavior, node); |
| 645 nativeBehaviors[node] = behavior; | 622 nativeBehaviors[node] = behavior; |
| 646 } | 623 } |
| 647 | 624 |
| 648 | |
| 649 /** | 625 /** |
| 650 * Handles JS-embedded global calls, which can be an instantiation point for | 626 * Handles JS-embedded global calls, which can be an instantiation point for |
| 651 * types. | 627 * types. |
| 652 * | 628 * |
| 653 * For example, the following code instantiates and returns a String class | 629 * For example, the following code instantiates and returns a String class |
| 654 * | 630 * |
| 655 * JS_EMBEDDED_GLOBAL('String', 'foo') | 631 * JS_EMBEDDED_GLOBAL('String', 'foo') |
| 656 * | 632 * |
| 657 */ | 633 */ |
| 658 void registerJsEmbeddedGlobalCall(Send node, ForeignResolver resolver) { | 634 void registerJsEmbeddedGlobalCall(Send node, ForeignResolver resolver) { |
| 659 NativeBehavior behavior = NativeBehavior.ofJsEmbeddedGlobalCall( | 635 NativeBehavior behavior = NativeBehavior.ofJsEmbeddedGlobalCall( |
| 660 node, reporter, compiler.parsing, compiler.coreTypes, resolver); | 636 node, reporter, compiler.parsing, compiler.coreTypes, resolver); |
| 661 registerNativeBehavior(behavior, node); | 637 registerNativeBehavior(behavior, node); |
| 662 nativeBehaviors[node] = behavior; | 638 nativeBehaviors[node] = behavior; |
| 663 } | 639 } |
| 664 | 640 |
| 665 | |
| 666 /** | 641 /** |
| 667 * Handles JS-compiler builtin calls, which can be an instantiation point for | 642 * Handles JS-compiler builtin calls, which can be an instantiation point for |
| 668 * types. | 643 * types. |
| 669 * | 644 * |
| 670 * For example, the following code instantiates and returns a String class | 645 * For example, the following code instantiates and returns a String class |
| 671 * | 646 * |
| 672 * JS_BUILTIN('String', 'int2string', 0) | 647 * JS_BUILTIN('String', 'int2string', 0) |
| 673 * | 648 * |
| 674 */ | 649 */ |
| 675 void registerJsBuiltinCall(Send node, ForeignResolver resolver) { | 650 void registerJsBuiltinCall(Send node, ForeignResolver resolver) { |
| 676 NativeBehavior behavior = NativeBehavior.ofJsBuiltinCall( | 651 NativeBehavior behavior = NativeBehavior.ofJsBuiltinCall( |
| 677 node, reporter, compiler.parsing, compiler.coreTypes, resolver); | 652 node, reporter, compiler.parsing, compiler.coreTypes, resolver); |
| 678 registerNativeBehavior(behavior, node); | 653 registerNativeBehavior(behavior, node); |
| 679 nativeBehaviors[node] = behavior; | 654 nativeBehaviors[node] = behavior; |
| 680 } | 655 } |
| 681 } | 656 } |
| 682 | 657 |
| 683 | |
| 684 class NativeCodegenEnqueuer extends NativeEnqueuerBase { | 658 class NativeCodegenEnqueuer extends NativeEnqueuerBase { |
| 685 | |
| 686 final CodeEmitterTask emitter; | 659 final CodeEmitterTask emitter; |
| 687 | 660 |
| 688 final Set<ClassElement> doneAddSubtypes = new Set<ClassElement>(); | 661 final Set<ClassElement> doneAddSubtypes = new Set<ClassElement>(); |
| 689 | 662 |
| 690 NativeCodegenEnqueuer(Enqueuer world, Compiler compiler, this.emitter) | 663 NativeCodegenEnqueuer(Enqueuer world, Compiler compiler, this.emitter) |
| 691 : super(world, compiler, compiler.options.enableNativeLiveTypeAnalysis); | 664 : super(world, compiler, compiler.options.enableNativeLiveTypeAnalysis); |
| 692 | 665 |
| 693 void processNativeClasses(Iterable<LibraryElement> libraries) { | 666 void processNativeClasses(Iterable<LibraryElement> libraries) { |
| 694 super.processNativeClasses(libraries); | 667 super.processNativeClasses(libraries); |
| 695 | 668 |
| 696 // HACK HACK - add all the resolved classes. | 669 // HACK HACK - add all the resolved classes. |
| 697 NativeEnqueuerBase enqueuer = compiler.enqueuer.resolution.nativeEnqueuer; | 670 NativeEnqueuerBase enqueuer = compiler.enqueuer.resolution.nativeEnqueuer; |
| 698 for (final classElement in enqueuer.registeredClasses) { | 671 for (final classElement in enqueuer.registeredClasses) { |
| 699 if (unusedClasses.contains(classElement)) { | 672 if (unusedClasses.contains(classElement)) { |
| 700 enqueueClass(classElement, 'was resolved'); | 673 enqueueClass(classElement, 'was resolved'); |
| 701 } | 674 } |
| (...skipping 11 matching lines...) Expand all Loading... |
| 713 void addSubtypes(ClassElement cls, NativeEmitter emitter) { | 686 void addSubtypes(ClassElement cls, NativeEmitter emitter) { |
| 714 if (!backend.isNative(cls)) return; | 687 if (!backend.isNative(cls)) return; |
| 715 if (doneAddSubtypes.contains(cls)) return; | 688 if (doneAddSubtypes.contains(cls)) return; |
| 716 doneAddSubtypes.add(cls); | 689 doneAddSubtypes.add(cls); |
| 717 | 690 |
| 718 // Walk the superclass chain since classes on the superclass chain might not | 691 // Walk the superclass chain since classes on the superclass chain might not |
| 719 // be instantiated (abstract or simply unused). | 692 // be instantiated (abstract or simply unused). |
| 720 addSubtypes(cls.superclass, emitter); | 693 addSubtypes(cls.superclass, emitter); |
| 721 | 694 |
| 722 for (DartType type in cls.allSupertypes) { | 695 for (DartType type in cls.allSupertypes) { |
| 723 List<Element> subtypes = emitter.subtypes.putIfAbsent( | 696 List<Element> subtypes = |
| 724 type.element, | 697 emitter.subtypes.putIfAbsent(type.element, () => <ClassElement>[]); |
| 725 () => <ClassElement>[]); | |
| 726 subtypes.add(cls); | 698 subtypes.add(cls); |
| 727 } | 699 } |
| 728 | 700 |
| 729 // Skip through all the mixin applications in the super class | 701 // Skip through all the mixin applications in the super class |
| 730 // chain. That way, the direct subtypes set only contain the | 702 // chain. That way, the direct subtypes set only contain the |
| 731 // natives classes. | 703 // natives classes. |
| 732 ClassElement superclass = cls.superclass; | 704 ClassElement superclass = cls.superclass; |
| 733 while (superclass != null && superclass.isMixinApplication) { | 705 while (superclass != null && superclass.isMixinApplication) { |
| 734 assert(!backend.isNative(superclass)); | 706 assert(!backend.isNative(superclass)); |
| 735 superclass = superclass.superclass; | 707 superclass = superclass.superclass; |
| 736 } | 708 } |
| 737 | 709 |
| 738 List<Element> directSubtypes = emitter.directSubtypes.putIfAbsent( | 710 List<Element> directSubtypes = |
| 739 superclass, | 711 emitter.directSubtypes.putIfAbsent(superclass, () => <ClassElement>[]); |
| 740 () => <ClassElement>[]); | |
| 741 directSubtypes.add(cls); | 712 directSubtypes.add(cls); |
| 742 } | 713 } |
| 743 | 714 |
| 744 void logSummary(log(message)) { | 715 void logSummary(log(message)) { |
| 745 log('Compiled ${registeredClasses.length} native classes, ' | 716 log('Compiled ${registeredClasses.length} native classes, ' |
| 746 '${unusedClasses.length} native classes omitted.'); | 717 '${unusedClasses.length} native classes omitted.'); |
| 747 } | 718 } |
| 748 } | 719 } |
| OLD | NEW |