Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 part of dart2js.js_emitter.startup_emitter.model_emitter; | 5 part of dart2js.js_emitter.startup_emitter.model_emitter; |
| 6 | 6 |
| 7 /// The name of the property that stores the tear-off getter on a static | 7 /// The name of the property that stores the tear-off getter on a static |
| 8 /// function. | 8 /// function. |
| 9 /// | 9 /// |
| 10 /// This property is only used when isolates are used. | 10 /// This property is only used when isolates are used. |
| (...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 290 // Every deferred hunk (i.e. fragment) is a function that we can invoke to | 290 // Every deferred hunk (i.e. fragment) is a function that we can invoke to |
| 291 // initialize it. At this moment it contributes its data to the main hunk. | 291 // initialize it. At this moment it contributes its data to the main hunk. |
| 292 function initializeDeferredHunk(hunk) { | 292 function initializeDeferredHunk(hunk) { |
| 293 // Update the typesOffset for the next deferred library. | 293 // Update the typesOffset for the next deferred library. |
| 294 typesOffset = #embeddedTypes.length; | 294 typesOffset = #embeddedTypes.length; |
| 295 | 295 |
| 296 // TODO(floitsch): extend natives. | 296 // TODO(floitsch): extend natives. |
| 297 hunk(inherit, mixin, lazy, makeConstList, convertToFastObject, installTearOff, | 297 hunk(inherit, mixin, lazy, makeConstList, convertToFastObject, installTearOff, |
| 298 setFunctionNamesIfNecessary, updateHolder, updateTypes, | 298 setFunctionNamesIfNecessary, updateHolder, updateTypes, |
| 299 setOrUpdateInterceptorsByTag, setOrUpdateLeafTags, | 299 setOrUpdateInterceptorsByTag, setOrUpdateLeafTags, |
| 300 #embeddedGlobalsObject, #holdersList, #staticState); | 300 #embeddedGlobalsObject, holders, #staticState); |
| 301 } | 301 } |
| 302 | 302 |
| 303 // Returns the global with the given [name]. | 303 // Returns the global with the given [name]. |
| 304 function getGlobalFromName(name) { | 304 function getGlobalFromName(name) { |
| 305 // TODO(floitsch): we are running through all holders. Since negative | 305 // TODO(floitsch): we are running through all holders. Since negative |
| 306 // lookups are expensive we might need to improve this. | 306 // lookups are expensive we might need to improve this. |
| 307 // Relies on the fact that all names are unique across all holders. | 307 // Relies on the fact that all names are unique across all holders. |
| 308 for (var i = 0; i < holders.length; i++) { | 308 for (var i = 0; i < holders.length; i++) { |
| 309 // The constant holder reuses the same names. Therefore we must skip it. | 309 // The constant holder reuses the same names. Therefore we must skip it. |
| 310 if (holders[i] == #constantHolderReference) continue; | 310 if (holders[i] == #constantHolderReference) continue; |
| 311 // Relies on the fact that all variables are unique. | 311 // Relies on the fact that all variables are unique. |
| 312 if (holders[i][name]) return holders[i][name]; | 312 if (holders[i][name]) return holders[i][name]; |
| 313 } | 313 } |
| 314 } | 314 } |
| 315 | 315 |
| 316 if (#hasSoftDeferredClasses) { | |
| 317 // Loads the soft-deferred classes and initializes them. | |
| 318 // Updates the prototype of the given object. | |
| 319 function softDef(o) { | |
| 320 softDef = function(o) {}; // Replace ourselves. | |
| 321 #deferredGlobal[#softId]( | |
| 322 holders, #embeddedGlobalsObject, #staticState, inherit, mixin, | |
| 323 installTearOff); | |
| 324 o.__proto__ = o.constructor.prototype; | |
|
sra1
2017/05/02 20:40:13
This will make Firefox angry.
floitsch
2017/05/06 19:25:43
Yes. I added a comment.
| |
| 325 } | |
| 326 } | |
| 327 | |
| 328 if (#isTrackingAllocations) { | |
| 329 var allocations = #deferredGlobal['allocations'] = {}; | |
| 330 } | |
| 331 | |
| 316 // Creates the holders. | 332 // Creates the holders. |
| 317 #holders; | 333 #holders; |
| 318 | 334 |
| 319 // If the name is not set on the functions, do it now. | 335 // If the name is not set on the functions, do it now. |
| 320 setFunctionNamesIfNecessary(#holdersList); | 336 setFunctionNamesIfNecessary(holders); |
| 321 | 337 |
| 322 // TODO(floitsch): we should build this object as a literal. | 338 // TODO(floitsch): we should build this object as a literal. |
| 323 var #staticStateDeclaration = {}; | 339 var #staticStateDeclaration = {}; |
| 324 | 340 |
| 325 // Sets the prototypes of classes. | 341 // Sets the prototypes of classes. |
| 326 #prototypes; | 342 #prototypes; |
| 327 // Sets aliases of methods (on the prototypes of classes). | 343 // Sets aliases of methods (on the prototypes of classes). |
| 328 #aliases; | 344 #aliases; |
| 329 // Installs the tear-offs of functions. | 345 // Installs the tear-offs of functions. |
| 330 #tearOffs; | 346 #tearOffs; |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 422 #staticNonFinalFields; | 438 #staticNonFinalFields; |
| 423 // Creates lazy getters for statics that must run initializers on first access. | 439 // Creates lazy getters for statics that must run initializers on first access. |
| 424 #lazyStatics; | 440 #lazyStatics; |
| 425 | 441 |
| 426 updateTypes(#types); | 442 updateTypes(#types); |
| 427 | 443 |
| 428 // Native-support uses setOrUpdateInterceptorsByTag and setOrUpdateLeafTags. | 444 // Native-support uses setOrUpdateInterceptorsByTag and setOrUpdateLeafTags. |
| 429 #nativeSupport; | 445 #nativeSupport; |
| 430 }'''; | 446 }'''; |
| 431 | 447 |
| 448 /// Soft-deferred fragments are built similarly to the main fragment. | |
| 449 /// | |
| 450 /// However, they don't contribute anything to global namespace, but just | |
| 451 /// initialize existing classes. For example, they update the inheritance | |
| 452 /// hierarchy, and add methods the prototypes. | |
| 453 const String softDeferredBoilerplate = ''' | |
| 454 #deferredGlobal[#softId] = | |
| 455 function(holdersList, #embeddedGlobalsObject, #staticState, inherit, mixin, | |
| 456 installTearOff) { | |
| 457 | |
| 458 // Installs the holders as local variables. | |
| 459 #installHoldersAsLocals; | |
| 460 // Sets the prototypes of the new classes. | |
| 461 #prototypes; | |
| 462 // Sets aliases of methods (on the prototypes of classes). | |
| 463 #aliases; | |
| 464 // Installs the tear-offs of functions. | |
| 465 #tearOffs; | |
| 466 // Builds the inheritance structure. | |
| 467 #inheritance; | |
| 468 }'''; | |
| 469 | |
| 432 /** | 470 /** |
| 433 * This class builds a JavaScript tree for a given fragment. | 471 * This class builds a JavaScript tree for a given fragment. |
| 434 * | 472 * |
| 435 * A fragment is generally written into a separate file so that it can be | 473 * A fragment is generally written into a separate file so that it can be |
| 436 * loaded dynamically when a deferred library is loaded. | 474 * loaded dynamically when a deferred library is loaded. |
| 437 * | 475 * |
| 438 * This class is stateless and can be reused for different fragments. | 476 * This class is stateless and can be reused for different fragments. |
| 439 */ | 477 */ |
| 440 class FragmentEmitter { | 478 class FragmentEmitter { |
| 441 final Compiler compiler; | 479 final Compiler compiler; |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 457 return js.js('#.#', [cls.holder.name, cls.name]); | 495 return js.js('#.#', [cls.holder.name, cls.name]); |
| 458 } | 496 } |
| 459 | 497 |
| 460 js.Statement emitMainFragment(Program program, | 498 js.Statement emitMainFragment(Program program, |
| 461 Map<DeferredFragment, _DeferredFragmentHash> deferredLoadHashes) { | 499 Map<DeferredFragment, _DeferredFragmentHash> deferredLoadHashes) { |
| 462 MainFragment fragment = program.fragments.first; | 500 MainFragment fragment = program.fragments.first; |
| 463 | 501 |
| 464 Iterable<Holder> nonStaticStateHolders = | 502 Iterable<Holder> nonStaticStateHolders = |
| 465 program.holders.where((Holder holder) => !holder.isStaticStateHolder); | 503 program.holders.where((Holder holder) => !holder.isStaticStateHolder); |
| 466 | 504 |
| 467 return js.js.statement(mainBoilerplate, { | 505 String softDeferredId = "softDeferred${new Random().nextInt(0x7FFFFFFF)}"; |
| 468 'directAccessTestExpression': js.js(directAccessTestExpression), | 506 |
| 469 'typeNameProperty': js.string(ModelEmitter.typeNameProperty), | 507 return new js.Block([ |
| 470 'cyclicThrow': backend.emitter | 508 program.hasSoftDeferredClasses |
| 471 .staticFunctionAccess(compiler.commonElements.cyclicThrowHelper), | 509 ? js.js.statement(softDeferredBoilerplate, { |
| 472 'operatorIsPrefix': js.string(namer.operatorIsPrefix), | 510 'deferredGlobal': ModelEmitter.deferredInitializersGlobal, |
| 473 'tearOffCode': new js.Block(buildTearOffCode(compiler.options, | 511 'softId': js.string(softDeferredId), |
| 474 backend.emitter.emitter, backend.namer, compiler.commonElements)), | 512 // TODO(floitsch): don't just reference 'init'. |
| 475 'embeddedTypes': generateEmbeddedGlobalAccess(TYPES), | 513 'embeddedGlobalsObject': new js.Parameter('init'), |
| 476 'embeddedInterceptorTags': | 514 'staticState': new js.Parameter(namer.staticStateHolder), |
| 477 generateEmbeddedGlobalAccess(INTERCEPTORS_BY_TAG), | 515 'installHoldersAsLocals': |
| 478 'embeddedLeafTags': generateEmbeddedGlobalAccess(LEAF_TAGS), | 516 emitInstallHoldersAsLocals(nonStaticStateHolders), |
| 479 'embeddedGlobalsObject': js.js("init"), | 517 'prototypes': emitPrototypes(fragment, softDeferred: true), |
| 480 'holdersList': new js.ArrayInitializer(nonStaticStateHolders | 518 'aliases': |
| 481 .map((holder) => js.js("#", holder.name)) | 519 emitInstanceMethodAliases(fragment, softDeferred: true), |
| 482 .toList(growable: false)), | 520 'tearOffs': emitInstallTearOffs(fragment, softDeferred: true), |
| 483 'staticStateDeclaration': new js.VariableDeclaration( | 521 'inheritance': emitInheritance(fragment, softDeferred: true), |
| 484 namer.staticStateHolder, | 522 }) |
| 485 allowRename: false), | |
| 486 'staticState': js.js('#', namer.staticStateHolder), | |
| 487 'constantHolderReference': buildConstantHolderReference(program), | |
| 488 'holders': emitHolders(program.holders, fragment), | |
| 489 'callName': js.string(namer.callNameField), | |
| 490 'stubName': js.string(namer.stubNameField), | |
| 491 'argumentCount': js.string(namer.requiredParameterField), | |
| 492 'defaultArgumentValues': js.string(namer.defaultValuesField), | |
| 493 'prototypes': emitPrototypes(fragment), | |
| 494 'inheritance': emitInheritance(fragment), | |
| 495 'aliases': emitInstanceMethodAliases(fragment), | |
| 496 'tearOffs': emitInstallTearOffs(fragment), | |
| 497 'constants': emitConstants(fragment), | |
| 498 'staticNonFinalFields': emitStaticNonFinalFields(fragment), | |
| 499 'lazyStatics': emitLazilyInitializedStatics(fragment), | |
| 500 'embeddedGlobals': emitEmbeddedGlobals(program, deferredLoadHashes), | |
| 501 'nativeSupport': program.needsNativeSupport | |
| 502 ? emitNativeSupport(fragment) | |
| 503 : new js.EmptyStatement(), | 523 : new js.EmptyStatement(), |
| 504 'jsInteropSupport': backend.jsInteropAnalysis.enabledJsInterop | 524 js.js.statement(mainBoilerplate, { |
| 505 ? backend.jsInteropAnalysis.buildJsInteropBootstrap() | 525 'directAccessTestExpression': js.js(directAccessTestExpression), |
| 506 : new js.EmptyStatement(), | 526 'typeNameProperty': js.string(ModelEmitter.typeNameProperty), |
| 507 'invokeMain': fragment.invokeMain, | 527 'cyclicThrow': backend.emitter |
| 508 }); | 528 .staticFunctionAccess(compiler.commonElements.cyclicThrowHelper), |
| 529 'operatorIsPrefix': js.string(namer.operatorIsPrefix), | |
| 530 'tearOffCode': new js.Block(buildTearOffCode(compiler.options, | |
| 531 backend.emitter.emitter, backend.namer, compiler.commonElements)), | |
| 532 'embeddedTypes': generateEmbeddedGlobalAccess(TYPES), | |
| 533 'embeddedInterceptorTags': | |
| 534 generateEmbeddedGlobalAccess(INTERCEPTORS_BY_TAG), | |
| 535 'embeddedLeafTags': generateEmbeddedGlobalAccess(LEAF_TAGS), | |
| 536 'embeddedGlobalsObject': js.js("init"), | |
| 537 'staticStateDeclaration': new js.VariableDeclaration( | |
| 538 namer.staticStateHolder, | |
| 539 allowRename: false), | |
| 540 'staticState': js.js('#', namer.staticStateHolder), | |
| 541 'constantHolderReference': buildConstantHolderReference(program), | |
| 542 'holders': emitHolders(program.holders, fragment), | |
| 543 'callName': js.string(namer.callNameField), | |
| 544 'stubName': js.string(namer.stubNameField), | |
| 545 'argumentCount': js.string(namer.requiredParameterField), | |
| 546 'defaultArgumentValues': js.string(namer.defaultValuesField), | |
| 547 'deferredGlobal': ModelEmitter.deferredInitializersGlobal, | |
| 548 'hasSoftDeferredClasses': program.hasSoftDeferredClasses, | |
| 549 'softId': js.string(softDeferredId), | |
| 550 'isTrackingAllocations': compiler.options.trackAllocations, | |
| 551 'prototypes': emitPrototypes(fragment), | |
| 552 'inheritance': emitInheritance(fragment), | |
| 553 'aliases': emitInstanceMethodAliases(fragment), | |
| 554 'tearOffs': emitInstallTearOffs(fragment), | |
| 555 'constants': emitConstants(fragment), | |
| 556 'staticNonFinalFields': emitStaticNonFinalFields(fragment), | |
| 557 'lazyStatics': emitLazilyInitializedStatics(fragment), | |
| 558 'embeddedGlobals': emitEmbeddedGlobals(program, deferredLoadHashes), | |
| 559 'nativeSupport': program.needsNativeSupport | |
| 560 ? emitNativeSupport(fragment) | |
| 561 : new js.EmptyStatement(), | |
| 562 'jsInteropSupport': backend.jsInteropAnalysis.enabledJsInterop | |
| 563 ? backend.jsInteropAnalysis.buildJsInteropBootstrap() | |
| 564 : new js.EmptyStatement(), | |
| 565 'invokeMain': fragment.invokeMain, | |
| 566 }), | |
| 567 ]); | |
| 568 } | |
| 569 | |
| 570 js.Statement emitInstallHoldersAsLocals(Iterable<Holder> holders) { | |
| 571 List<js.Statement> holderInits = <js.Statement>[]; | |
| 572 int counter = 0; | |
| 573 for (Holder holder in holders) { | |
| 574 holderInits.add(new js.ExpressionStatement(new js.VariableInitialization( | |
| 575 new js.VariableDeclaration(holder.name, allowRename: false), | |
| 576 js.js("holdersList[#]", js.number(counter++))))); | |
| 577 } | |
| 578 return new js.Block(holderInits); | |
| 509 } | 579 } |
| 510 | 580 |
| 511 js.Expression emitDeferredFragment(DeferredFragment fragment, | 581 js.Expression emitDeferredFragment(DeferredFragment fragment, |
| 512 js.Expression deferredTypes, List<Holder> holders) { | 582 js.Expression deferredTypes, List<Holder> holders) { |
| 513 List<Holder> nonStaticStateHolders = holders | 583 List<Holder> nonStaticStateHolders = holders |
| 514 .where((Holder holder) => !holder.isStaticStateHolder) | 584 .where((Holder holder) => !holder.isStaticStateHolder) |
| 515 .toList(growable: false); | 585 .toList(growable: false); |
| 516 | 586 |
| 517 List<js.Statement> updateHolderAssignments = <js.Statement>[]; | 587 List<js.Statement> updateHolderAssignments = <js.Statement>[]; |
| 518 for (int i = 0; i < nonStaticStateHolders.length; i++) { | 588 for (int i = 0; i < nonStaticStateHolders.length; i++) { |
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 650 // If the class is not directly instantiated we only need it for inheritance | 720 // If the class is not directly instantiated we only need it for inheritance |
| 651 // or RTI. In either case we don't need its fields. | 721 // or RTI. In either case we don't need its fields. |
| 652 if (cls.isNative || !cls.isDirectlyInstantiated) { | 722 if (cls.isNative || !cls.isDirectlyInstantiated) { |
| 653 return js.js('function #() { }', name); | 723 return js.js('function #() { }', name); |
| 654 } | 724 } |
| 655 | 725 |
| 656 var statements = <js.Statement>[]; | 726 var statements = <js.Statement>[]; |
| 657 var parameters = <js.Name>[]; | 727 var parameters = <js.Name>[]; |
| 658 var thisRef; | 728 var thisRef; |
| 659 | 729 |
| 730 if (cls.isSoftDeferred) { | |
| 731 statements.add(js.js.statement('softDef(this)')); | |
| 732 } else if (compiler.options.trackAllocations) { | |
| 733 String qualifiedName = | |
| 734 "${cls.element.library.canonicalUri}:${cls.element.name}"; | |
| 735 statements.add(js.js.statement('allocations["$qualifiedName"] = true')); | |
| 736 } | |
| 737 | |
| 660 // If there are many references to `this`, cache it in a local. | 738 // If there are many references to `this`, cache it in a local. |
| 661 if (cls.fields.length + (cls.hasRtiField ? 1 : 0) >= 4) { | 739 if (cls.fields.length + (cls.hasRtiField ? 1 : 0) >= 4) { |
| 662 // TODO(29455): Fix js_ast printer and minifier to avoid conflicts between | 740 // TODO(29455): Fix js_ast printer and minifier to avoid conflicts between |
| 663 // js.Name and string-named variables, then use '_' in the js template | 741 // js.Name and string-named variables, then use '_' in the js template |
| 664 // text. | 742 // text. |
| 665 | 743 |
| 666 // We pick '_' in minified mode because no field minifies to '_'. This | 744 // We pick '_' in minified mode because no field minifies to '_'. This |
| 667 // avoids a conflict with one of the parameters which are named the same | 745 // avoids a conflict with one of the parameters which are named the same |
| 668 // as the fields. Unminified, a field might have the name '_', so we pick | 746 // as the fields. Unminified, a field might have the name '_', so we pick |
| 669 // '$_', which is an impossible member name since we escape '$'s in names. | 747 // '$_', which is an impossible member name since we escape '$'s in names. |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 690 .statement('#.# = #', [thisRef, namer.rtiFieldJsName, paramName])); | 768 .statement('#.# = #', [thisRef, namer.rtiFieldJsName, paramName])); |
| 691 } | 769 } |
| 692 | 770 |
| 693 return js.js('function #(#) { # }', [name, parameters, statements]); | 771 return js.js('function #(#) { # }', [name, parameters, statements]); |
| 694 } | 772 } |
| 695 | 773 |
| 696 /// Emits the prototype-section of the fragment. | 774 /// Emits the prototype-section of the fragment. |
| 697 /// | 775 /// |
| 698 /// This section updates the prototype-property of all constructors in the | 776 /// This section updates the prototype-property of all constructors in the |
| 699 /// global holders. | 777 /// global holders. |
| 700 js.Statement emitPrototypes(Fragment fragment) { | 778 js.Statement emitPrototypes(Fragment fragment, {softDeferred = false}) { |
| 701 List<js.Statement> assignments = fragment.libraries | 779 List<js.Statement> assignments = fragment.libraries |
| 702 .expand((Library library) => library.classes) | 780 .expand((Library library) => library.classes) |
| 781 .where((Class cls) => cls.isSoftDeferred == softDeferred) | |
| 703 .map((Class cls) { | 782 .map((Class cls) { |
| 704 var proto = js.js.statement( | 783 var proto = js.js.statement( |
| 705 '#.prototype = #;', [classReference(cls), emitPrototype(cls)]); | 784 '#.prototype = #;', [classReference(cls), emitPrototype(cls)]); |
| 706 ClassElement element = cls.element; | 785 ClassElement element = cls.element; |
| 707 compiler.dumpInfoTask.registerElementAst(element, proto); | 786 compiler.dumpInfoTask.registerElementAst(element, proto); |
| 708 compiler.dumpInfoTask.registerElementAst(element.library, proto); | 787 compiler.dumpInfoTask.registerElementAst(element.library, proto); |
| 709 return proto; | 788 return proto; |
| 710 }).toList(growable: false); | 789 }).toList(growable: false); |
| 711 | 790 |
| 712 return new js.Block(assignments); | 791 return new js.Block(assignments); |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 857 } | 936 } |
| 858 } | 937 } |
| 859 | 938 |
| 860 return properties; | 939 return properties; |
| 861 } | 940 } |
| 862 | 941 |
| 863 /// Emits the inheritance block of the fragment. | 942 /// Emits the inheritance block of the fragment. |
| 864 /// | 943 /// |
| 865 /// In this section prototype chains are updated and mixin functions are | 944 /// In this section prototype chains are updated and mixin functions are |
| 866 /// copied. | 945 /// copied. |
| 867 js.Statement emitInheritance(Fragment fragment) { | 946 js.Statement emitInheritance(Fragment fragment, {bool softDeferred = false}) { |
| 868 List<js.Statement> inheritCalls = <js.Statement>[]; | 947 List<js.Statement> inheritCalls = <js.Statement>[]; |
| 869 List<js.Statement> mixinCalls = <js.Statement>[]; | 948 List<js.Statement> mixinCalls = <js.Statement>[]; |
| 870 | 949 |
| 871 Set<Class> classesInFragment = new Set<Class>(); | 950 Set<Class> classesInFragment = new Set<Class>(); |
| 872 for (Library library in fragment.libraries) { | 951 for (Library library in fragment.libraries) { |
| 873 classesInFragment.addAll(library.classes); | 952 classesInFragment.addAll(library.classes |
| 953 .where(((Class cls) => cls.isSoftDeferred == softDeferred))); | |
| 874 } | 954 } |
| 875 | 955 |
| 876 Map<Class, List<Class>> subclasses = <Class, List<Class>>{}; | 956 Map<Class, List<Class>> subclasses = <Class, List<Class>>{}; |
| 877 Set<Class> seen = new Set<Class>(); | 957 Set<Class> seen = new Set<Class>(); |
| 878 | 958 |
| 879 void collect(cls) { | 959 void collect(cls) { |
| 880 if (cls == null || seen.contains(cls)) return; | 960 if (cls == null || seen.contains(cls)) return; |
| 881 | 961 |
| 882 Class superclass = cls.superclass; | 962 Class superclass = cls.superclass; |
| 883 if (classesInFragment.contains(superclass)) { | 963 if (classesInFragment.contains(superclass)) { |
| 884 collect(superclass); | 964 collect(superclass); |
| 885 } | 965 } |
| 886 | 966 |
| 887 subclasses.putIfAbsent(superclass, () => <Class>[]).add(cls); | 967 subclasses.putIfAbsent(superclass, () => <Class>[]).add(cls); |
| 888 | 968 |
| 889 seen.add(cls); | 969 seen.add(cls); |
| 890 } | 970 } |
| 891 | 971 |
| 892 for (Library library in fragment.libraries) { | 972 for (Library library in fragment.libraries) { |
| 893 for (Class cls in library.classes) { | 973 for (Class cls in library.classes) { |
| 974 if (cls.isSoftDeferred != softDeferred) continue; | |
| 894 collect(cls); | 975 collect(cls); |
| 895 | 976 |
| 896 if (cls.isMixinApplication) { | 977 if (cls.isMixinApplication) { |
| 897 MixinApplication mixin = cls; | 978 MixinApplication mixin = cls; |
| 898 mixinCalls.add(js.js.statement('mixin(#, #)', | 979 mixinCalls.add(js.js.statement('mixin(#, #)', |
| 899 [classReference(cls), classReference(mixin.mixinClass)])); | 980 [classReference(cls), classReference(mixin.mixinClass)])); |
| 900 } | 981 } |
| 901 } | 982 } |
| 902 } | 983 } |
| 903 | 984 |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 930 } | 1011 } |
| 931 | 1012 |
| 932 return wrapPhase( | 1013 return wrapPhase( |
| 933 'inheritance', js.js.statement('{#; #;}', [inheritCalls, mixinCalls])); | 1014 'inheritance', js.js.statement('{#; #;}', [inheritCalls, mixinCalls])); |
| 934 } | 1015 } |
| 935 | 1016 |
| 936 /// Emits the setup of method aliases. | 1017 /// Emits the setup of method aliases. |
| 937 /// | 1018 /// |
| 938 /// This step consists of simply copying JavaScript functions to their | 1019 /// This step consists of simply copying JavaScript functions to their |
| 939 /// aliased names so they point to the same function. | 1020 /// aliased names so they point to the same function. |
| 940 js.Statement emitInstanceMethodAliases(Fragment fragment) { | 1021 js.Statement emitInstanceMethodAliases(Fragment fragment, |
| 1022 {bool softDeferred = false}) { | |
| 941 List<js.Statement> assignments = <js.Statement>[]; | 1023 List<js.Statement> assignments = <js.Statement>[]; |
| 942 | 1024 |
| 943 for (Library library in fragment.libraries) { | 1025 for (Library library in fragment.libraries) { |
| 944 for (Class cls in library.classes) { | 1026 for (Class cls in library.classes) { |
| 1027 if (cls.isSoftDeferred != softDeferred) continue; | |
| 945 for (InstanceMethod method in cls.methods) { | 1028 for (InstanceMethod method in cls.methods) { |
| 946 if (method.aliasName != null) { | 1029 if (method.aliasName != null) { |
| 947 assignments.add(js.js.statement('#.prototype.# = #.prototype.#', [ | 1030 assignments.add(js.js.statement('#.prototype.# = #.prototype.#', [ |
| 948 classReference(cls), | 1031 classReference(cls), |
| 949 js.quoteName(method.aliasName), | 1032 js.quoteName(method.aliasName), |
| 950 classReference(cls), | 1033 classReference(cls), |
| 951 js.quoteName(method.name) | 1034 js.quoteName(method.name) |
| 952 ])); | 1035 ])); |
| 953 } | 1036 } |
| 954 } | 1037 } |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1059 } | 1142 } |
| 1060 | 1143 |
| 1061 /// Wraps the statement in a named function to that it shows up as a unit in | 1144 /// Wraps the statement in a named function to that it shows up as a unit in |
| 1062 /// profiles. | 1145 /// profiles. |
| 1063 // TODO(sra): Should this be conditional? | 1146 // TODO(sra): Should this be conditional? |
| 1064 js.Statement wrapPhase(String name, js.Statement statement) { | 1147 js.Statement wrapPhase(String name, js.Statement statement) { |
| 1065 return js.js.statement('(function #(){#})();', [name, statement]); | 1148 return js.js.statement('(function #(){#})();', [name, statement]); |
| 1066 } | 1149 } |
| 1067 | 1150 |
| 1068 /// Emits the section that installs tear-off getters. | 1151 /// Emits the section that installs tear-off getters. |
| 1069 js.Statement emitInstallTearOffs(Fragment fragment) { | 1152 js.Statement emitInstallTearOffs(Fragment fragment, |
| 1153 {bool softDeferred = false}) { | |
| 1070 List<js.Statement> inits = <js.Statement>[]; | 1154 List<js.Statement> inits = <js.Statement>[]; |
| 1071 js.Expression temp; | 1155 js.Expression temp; |
| 1072 | 1156 |
| 1073 for (Library library in fragment.libraries) { | 1157 for (Library library in fragment.libraries) { |
| 1074 for (StaticMethod method in library.statics) { | 1158 for (StaticMethod method in library.statics) { |
| 1075 // TODO(floitsch): can there be anything else than a StaticDartMethod? | 1159 // TODO(floitsch): can there be anything else than a StaticDartMethod? |
| 1076 if (method is StaticDartMethod) { | 1160 if (method is StaticDartMethod) { |
| 1077 if (method.needsTearOff) { | 1161 if (method.needsTearOff) { |
| 1078 Holder holder = method.holder; | 1162 Holder holder = method.holder; |
| 1079 inits.add( | 1163 inits.add( |
| 1080 emitInstallTearOff(new js.VariableUse(holder.name), method)); | 1164 emitInstallTearOff(new js.VariableUse(holder.name), method)); |
| 1081 } | 1165 } |
| 1082 } | 1166 } |
| 1083 } | 1167 } |
| 1084 for (Class cls in library.classes) { | 1168 for (Class cls in library.classes) { |
| 1169 if (cls.isSoftDeferred != softDeferred) continue; | |
| 1085 var methods = cls.methods.where((m) => m.needsTearOff).toList(); | 1170 var methods = cls.methods.where((m) => m.needsTearOff).toList(); |
| 1086 js.Expression container = js.js("#.prototype", classReference(cls)); | 1171 js.Expression container = js.js("#.prototype", classReference(cls)); |
| 1087 js.Expression reference = container; | 1172 js.Expression reference = container; |
| 1088 if (methods.length > 1) { | 1173 if (methods.length > 1) { |
| 1089 if (temp == null) { | 1174 if (temp == null) { |
| 1090 inits.add(js.js.statement('var _;')); | 1175 inits.add(js.js.statement('var _;')); |
| 1091 temp = js.js('_'); | 1176 temp = js.js('_'); |
| 1092 } | 1177 } |
| 1093 // First call uses assignment to temp to cache the container. | 1178 // First call uses assignment to temp to cache the container. |
| 1094 reference = js.js('# = #', [temp, container]); | 1179 reference = js.js('# = #', [temp, container]); |
| (...skipping 371 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1466 } | 1551 } |
| 1467 statements.add(js.js.statement("setOrUpdateInterceptorsByTag(#);", | 1552 statements.add(js.js.statement("setOrUpdateInterceptorsByTag(#);", |
| 1468 js.objectLiteral(interceptorsByTag))); | 1553 js.objectLiteral(interceptorsByTag))); |
| 1469 statements.add( | 1554 statements.add( |
| 1470 js.js.statement("setOrUpdateLeafTags(#);", js.objectLiteral(leafTags))); | 1555 js.js.statement("setOrUpdateLeafTags(#);", js.objectLiteral(leafTags))); |
| 1471 statements.addAll(subclassAssignments); | 1556 statements.addAll(subclassAssignments); |
| 1472 | 1557 |
| 1473 return wrapPhase('nativeSupport', new js.Block(statements)); | 1558 return wrapPhase('nativeSupport', new js.Block(statements)); |
| 1474 } | 1559 } |
| 1475 } | 1560 } |
| OLD | NEW |