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 if (o != null) { |
| 325 // TODO(29574): should we do something different for Firefox? |
| 326 // If we recommend that the program triggers the load by itself before |
| 327 // classes are needed, then this line should rarely be hit. |
| 328 // Also, it is only hit at most once (per soft-deferred chunk). |
| 329 o.__proto__ = o.constructor.prototype; |
| 330 } |
| 331 } |
| 332 } |
| 333 |
| 334 if (#isTrackingAllocations) { |
| 335 var allocations = #deferredGlobal['allocations'] = {}; |
| 336 } |
| 337 |
316 // Creates the holders. | 338 // Creates the holders. |
317 #holders; | 339 #holders; |
318 | 340 |
319 // If the name is not set on the functions, do it now. | 341 // If the name is not set on the functions, do it now. |
320 setFunctionNamesIfNecessary(#holdersList); | 342 setFunctionNamesIfNecessary(holders); |
321 | 343 |
322 // TODO(floitsch): we should build this object as a literal. | 344 // TODO(floitsch): we should build this object as a literal. |
323 var #staticStateDeclaration = {}; | 345 var #staticStateDeclaration = {}; |
324 | 346 |
325 // Sets the prototypes of classes. | 347 // Sets the prototypes of classes. |
326 #prototypes; | 348 #prototypes; |
327 // Sets aliases of methods (on the prototypes of classes). | 349 // Sets aliases of methods (on the prototypes of classes). |
328 #aliases; | 350 #aliases; |
329 // Installs the tear-offs of functions. | 351 // Installs the tear-offs of functions. |
330 #tearOffs; | 352 #tearOffs; |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
422 #staticNonFinalFields; | 444 #staticNonFinalFields; |
423 // Creates lazy getters for statics that must run initializers on first access. | 445 // Creates lazy getters for statics that must run initializers on first access. |
424 #lazyStatics; | 446 #lazyStatics; |
425 | 447 |
426 updateTypes(#types); | 448 updateTypes(#types); |
427 | 449 |
428 // Native-support uses setOrUpdateInterceptorsByTag and setOrUpdateLeafTags. | 450 // Native-support uses setOrUpdateInterceptorsByTag and setOrUpdateLeafTags. |
429 #nativeSupport; | 451 #nativeSupport; |
430 }'''; | 452 }'''; |
431 | 453 |
| 454 /// Soft-deferred fragments are built similarly to the main fragment. |
| 455 /// |
| 456 /// However, they don't contribute anything to global namespace, but just |
| 457 /// initialize existing classes. For example, they update the inheritance |
| 458 /// hierarchy, and add methods the prototypes. |
| 459 const String softDeferredBoilerplate = ''' |
| 460 #deferredGlobal[#softId] = |
| 461 function(holdersList, #embeddedGlobalsObject, #staticState, inherit, mixin, |
| 462 installTearOff) { |
| 463 |
| 464 // Installs the holders as local variables. |
| 465 #installHoldersAsLocals; |
| 466 // Sets the prototypes of the new classes. |
| 467 #prototypes; |
| 468 // Sets aliases of methods (on the prototypes of classes). |
| 469 #aliases; |
| 470 // Installs the tear-offs of functions. |
| 471 #tearOffs; |
| 472 // Builds the inheritance structure. |
| 473 #inheritance; |
| 474 }'''; |
| 475 |
432 /** | 476 /** |
433 * This class builds a JavaScript tree for a given fragment. | 477 * This class builds a JavaScript tree for a given fragment. |
434 * | 478 * |
435 * A fragment is generally written into a separate file so that it can be | 479 * A fragment is generally written into a separate file so that it can be |
436 * loaded dynamically when a deferred library is loaded. | 480 * loaded dynamically when a deferred library is loaded. |
437 * | 481 * |
438 * This class is stateless and can be reused for different fragments. | 482 * This class is stateless and can be reused for different fragments. |
439 */ | 483 */ |
440 class FragmentEmitter { | 484 class FragmentEmitter { |
441 final Compiler compiler; | 485 final Compiler compiler; |
(...skipping 15 matching lines...) Expand all Loading... |
457 return js.js('#.#', [cls.holder.name, cls.name]); | 501 return js.js('#.#', [cls.holder.name, cls.name]); |
458 } | 502 } |
459 | 503 |
460 js.Statement emitMainFragment(Program program, | 504 js.Statement emitMainFragment(Program program, |
461 Map<DeferredFragment, _DeferredFragmentHash> deferredLoadHashes) { | 505 Map<DeferredFragment, _DeferredFragmentHash> deferredLoadHashes) { |
462 MainFragment fragment = program.fragments.first; | 506 MainFragment fragment = program.fragments.first; |
463 | 507 |
464 Iterable<Holder> nonStaticStateHolders = | 508 Iterable<Holder> nonStaticStateHolders = |
465 program.holders.where((Holder holder) => !holder.isStaticStateHolder); | 509 program.holders.where((Holder holder) => !holder.isStaticStateHolder); |
466 | 510 |
467 return js.js.statement(mainBoilerplate, { | 511 String softDeferredId = "softDeferred${new Random().nextInt(0x7FFFFFFF)}"; |
| 512 |
| 513 js.Statement mainCode = js.js.statement(mainBoilerplate, { |
468 'directAccessTestExpression': js.js(directAccessTestExpression), | 514 'directAccessTestExpression': js.js(directAccessTestExpression), |
469 'typeNameProperty': js.string(ModelEmitter.typeNameProperty), | 515 'typeNameProperty': js.string(ModelEmitter.typeNameProperty), |
470 'cyclicThrow': backend.emitter | 516 'cyclicThrow': backend.emitter |
471 .staticFunctionAccess(compiler.commonElements.cyclicThrowHelper), | 517 .staticFunctionAccess(compiler.commonElements.cyclicThrowHelper), |
472 'operatorIsPrefix': js.string(namer.operatorIsPrefix), | 518 'operatorIsPrefix': js.string(namer.operatorIsPrefix), |
473 'tearOffCode': new js.Block(buildTearOffCode(compiler.options, | 519 'tearOffCode': new js.Block(buildTearOffCode(compiler.options, |
474 backend.emitter.emitter, backend.namer, compiler.commonElements)), | 520 backend.emitter.emitter, backend.namer, compiler.commonElements)), |
475 'embeddedTypes': generateEmbeddedGlobalAccess(TYPES), | 521 'embeddedTypes': generateEmbeddedGlobalAccess(TYPES), |
476 'embeddedInterceptorTags': | 522 'embeddedInterceptorTags': |
477 generateEmbeddedGlobalAccess(INTERCEPTORS_BY_TAG), | 523 generateEmbeddedGlobalAccess(INTERCEPTORS_BY_TAG), |
478 'embeddedLeafTags': generateEmbeddedGlobalAccess(LEAF_TAGS), | 524 'embeddedLeafTags': generateEmbeddedGlobalAccess(LEAF_TAGS), |
479 'embeddedGlobalsObject': js.js("init"), | 525 'embeddedGlobalsObject': js.js("init"), |
480 'holdersList': new js.ArrayInitializer(nonStaticStateHolders | |
481 .map((holder) => js.js("#", holder.name)) | |
482 .toList(growable: false)), | |
483 'staticStateDeclaration': new js.VariableDeclaration( | 526 'staticStateDeclaration': new js.VariableDeclaration( |
484 namer.staticStateHolder, | 527 namer.staticStateHolder, |
485 allowRename: false), | 528 allowRename: false), |
486 'staticState': js.js('#', namer.staticStateHolder), | 529 'staticState': js.js('#', namer.staticStateHolder), |
487 'constantHolderReference': buildConstantHolderReference(program), | 530 'constantHolderReference': buildConstantHolderReference(program), |
488 'holders': emitHolders(program.holders, fragment), | 531 'holders': emitHolders(program.holders, fragment), |
489 'callName': js.string(namer.callNameField), | 532 'callName': js.string(namer.callNameField), |
490 'stubName': js.string(namer.stubNameField), | 533 'stubName': js.string(namer.stubNameField), |
491 'argumentCount': js.string(namer.requiredParameterField), | 534 'argumentCount': js.string(namer.requiredParameterField), |
492 'defaultArgumentValues': js.string(namer.defaultValuesField), | 535 'defaultArgumentValues': js.string(namer.defaultValuesField), |
| 536 'deferredGlobal': ModelEmitter.deferredInitializersGlobal, |
| 537 'hasSoftDeferredClasses': program.hasSoftDeferredClasses, |
| 538 'softId': js.string(softDeferredId), |
| 539 'isTrackingAllocations': compiler.options.experimentalTrackAllocations, |
493 'prototypes': emitPrototypes(fragment), | 540 'prototypes': emitPrototypes(fragment), |
494 'inheritance': emitInheritance(fragment), | 541 'inheritance': emitInheritance(fragment), |
495 'aliases': emitInstanceMethodAliases(fragment), | 542 'aliases': emitInstanceMethodAliases(fragment), |
496 'tearOffs': emitInstallTearOffs(fragment), | 543 'tearOffs': emitInstallTearOffs(fragment), |
497 'constants': emitConstants(fragment), | 544 'constants': emitConstants(fragment), |
498 'staticNonFinalFields': emitStaticNonFinalFields(fragment), | 545 'staticNonFinalFields': emitStaticNonFinalFields(fragment), |
499 'lazyStatics': emitLazilyInitializedStatics(fragment), | 546 'lazyStatics': emitLazilyInitializedStatics(fragment), |
500 'embeddedGlobals': emitEmbeddedGlobals(program, deferredLoadHashes), | 547 'embeddedGlobals': emitEmbeddedGlobals(program, deferredLoadHashes), |
501 'nativeSupport': program.needsNativeSupport | 548 'nativeSupport': program.needsNativeSupport |
502 ? emitNativeSupport(fragment) | 549 ? emitNativeSupport(fragment) |
503 : new js.EmptyStatement(), | 550 : new js.EmptyStatement(), |
504 'jsInteropSupport': backend.nativeBasicData.isJsInteropUsed | 551 'jsInteropSupport': backend.nativeBasicData.isJsInteropUsed |
505 ? backend.jsInteropAnalysis.buildJsInteropBootstrap() | 552 ? backend.jsInteropAnalysis.buildJsInteropBootstrap() |
506 : new js.EmptyStatement(), | 553 : new js.EmptyStatement(), |
507 'invokeMain': fragment.invokeMain, | 554 'invokeMain': fragment.invokeMain, |
508 }); | 555 }); |
| 556 if (program.hasSoftDeferredClasses) { |
| 557 return new js.Block([ |
| 558 js.js.statement(softDeferredBoilerplate, { |
| 559 'deferredGlobal': ModelEmitter.deferredInitializersGlobal, |
| 560 'softId': js.string(softDeferredId), |
| 561 // TODO(floitsch): don't just reference 'init'. |
| 562 'embeddedGlobalsObject': new js.Parameter('init'), |
| 563 'staticState': new js.Parameter(namer.staticStateHolder), |
| 564 'installHoldersAsLocals': |
| 565 emitInstallHoldersAsLocals(nonStaticStateHolders), |
| 566 'prototypes': emitPrototypes(fragment, softDeferred: true), |
| 567 'aliases': emitInstanceMethodAliases(fragment, softDeferred: true), |
| 568 'tearOffs': emitInstallTearOffs(fragment, softDeferred: true), |
| 569 'inheritance': emitInheritance(fragment, softDeferred: true), |
| 570 }), |
| 571 mainCode |
| 572 ]); |
| 573 } |
| 574 return mainCode; |
| 575 } |
| 576 |
| 577 js.Statement emitInstallHoldersAsLocals(Iterable<Holder> holders) { |
| 578 List<js.Statement> holderInits = <js.Statement>[]; |
| 579 int counter = 0; |
| 580 for (Holder holder in holders) { |
| 581 holderInits.add(new js.ExpressionStatement(new js.VariableInitialization( |
| 582 new js.VariableDeclaration(holder.name, allowRename: false), |
| 583 js.js("holdersList[#]", js.number(counter++))))); |
| 584 } |
| 585 return new js.Block(holderInits); |
509 } | 586 } |
510 | 587 |
511 js.Expression emitDeferredFragment(DeferredFragment fragment, | 588 js.Expression emitDeferredFragment(DeferredFragment fragment, |
512 js.Expression deferredTypes, List<Holder> holders) { | 589 js.Expression deferredTypes, List<Holder> holders) { |
513 List<Holder> nonStaticStateHolders = holders | 590 List<Holder> nonStaticStateHolders = holders |
514 .where((Holder holder) => !holder.isStaticStateHolder) | 591 .where((Holder holder) => !holder.isStaticStateHolder) |
515 .toList(growable: false); | 592 .toList(growable: false); |
516 | 593 |
517 List<js.Statement> updateHolderAssignments = <js.Statement>[]; | 594 List<js.Statement> updateHolderAssignments = <js.Statement>[]; |
518 for (int i = 0; i < nonStaticStateHolders.length; i++) { | 595 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 | 727 // 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. | 728 // or RTI. In either case we don't need its fields. |
652 if (cls.isNative || !cls.isDirectlyInstantiated) { | 729 if (cls.isNative || !cls.isDirectlyInstantiated) { |
653 return js.js('function #() { }', name); | 730 return js.js('function #() { }', name); |
654 } | 731 } |
655 | 732 |
656 var statements = <js.Statement>[]; | 733 var statements = <js.Statement>[]; |
657 var parameters = <js.Name>[]; | 734 var parameters = <js.Name>[]; |
658 var thisRef; | 735 var thisRef; |
659 | 736 |
| 737 if (cls.isSoftDeferred) { |
| 738 statements.add(js.js.statement('softDef(this)')); |
| 739 } else if (compiler.options.experimentalTrackAllocations) { |
| 740 String qualifiedName = |
| 741 "${cls.element.library.canonicalUri}:${cls.element.name}"; |
| 742 statements.add(js.js.statement('allocations["$qualifiedName"] = true')); |
| 743 } |
| 744 |
660 // If there are many references to `this`, cache it in a local. | 745 // If there are many references to `this`, cache it in a local. |
661 if (cls.fields.length + (cls.hasRtiField ? 1 : 0) >= 4) { | 746 if (cls.fields.length + (cls.hasRtiField ? 1 : 0) >= 4) { |
662 // TODO(29455): Fix js_ast printer and minifier to avoid conflicts between | 747 // 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 | 748 // js.Name and string-named variables, then use '_' in the js template |
664 // text. | 749 // text. |
665 | 750 |
666 // We pick '_' in minified mode because no field minifies to '_'. This | 751 // 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 | 752 // 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 | 753 // 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. | 754 // '$_', 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])); | 775 .statement('#.# = #', [thisRef, namer.rtiFieldJsName, paramName])); |
691 } | 776 } |
692 | 777 |
693 return js.js('function #(#) { # }', [name, parameters, statements]); | 778 return js.js('function #(#) { # }', [name, parameters, statements]); |
694 } | 779 } |
695 | 780 |
696 /// Emits the prototype-section of the fragment. | 781 /// Emits the prototype-section of the fragment. |
697 /// | 782 /// |
698 /// This section updates the prototype-property of all constructors in the | 783 /// This section updates the prototype-property of all constructors in the |
699 /// global holders. | 784 /// global holders. |
700 js.Statement emitPrototypes(Fragment fragment) { | 785 js.Statement emitPrototypes(Fragment fragment, {softDeferred = false}) { |
701 List<js.Statement> assignments = fragment.libraries | 786 List<js.Statement> assignments = fragment.libraries |
702 .expand((Library library) => library.classes) | 787 .expand((Library library) => library.classes) |
| 788 .where((Class cls) => cls.isSoftDeferred == softDeferred) |
703 .map((Class cls) { | 789 .map((Class cls) { |
704 var proto = js.js.statement( | 790 var proto = js.js.statement( |
705 '#.prototype = #;', [classReference(cls), emitPrototype(cls)]); | 791 '#.prototype = #;', [classReference(cls), emitPrototype(cls)]); |
706 ClassElement element = cls.element; | 792 ClassElement element = cls.element; |
707 compiler.dumpInfoTask.registerElementAst(element, proto); | 793 compiler.dumpInfoTask.registerElementAst(element, proto); |
708 compiler.dumpInfoTask.registerElementAst(element.library, proto); | 794 compiler.dumpInfoTask.registerElementAst(element.library, proto); |
709 return proto; | 795 return proto; |
710 }).toList(growable: false); | 796 }).toList(growable: false); |
711 | 797 |
712 return new js.Block(assignments); | 798 return new js.Block(assignments); |
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
857 } | 943 } |
858 } | 944 } |
859 | 945 |
860 return properties; | 946 return properties; |
861 } | 947 } |
862 | 948 |
863 /// Emits the inheritance block of the fragment. | 949 /// Emits the inheritance block of the fragment. |
864 /// | 950 /// |
865 /// In this section prototype chains are updated and mixin functions are | 951 /// In this section prototype chains are updated and mixin functions are |
866 /// copied. | 952 /// copied. |
867 js.Statement emitInheritance(Fragment fragment) { | 953 js.Statement emitInheritance(Fragment fragment, {bool softDeferred = false}) { |
868 List<js.Statement> inheritCalls = <js.Statement>[]; | 954 List<js.Statement> inheritCalls = <js.Statement>[]; |
869 List<js.Statement> mixinCalls = <js.Statement>[]; | 955 List<js.Statement> mixinCalls = <js.Statement>[]; |
870 | 956 |
871 Set<Class> classesInFragment = new Set<Class>(); | 957 Set<Class> classesInFragment = new Set<Class>(); |
872 for (Library library in fragment.libraries) { | 958 for (Library library in fragment.libraries) { |
873 classesInFragment.addAll(library.classes); | 959 classesInFragment.addAll(library.classes |
| 960 .where(((Class cls) => cls.isSoftDeferred == softDeferred))); |
874 } | 961 } |
875 | 962 |
876 Map<Class, List<Class>> subclasses = <Class, List<Class>>{}; | 963 Map<Class, List<Class>> subclasses = <Class, List<Class>>{}; |
877 Set<Class> seen = new Set<Class>(); | 964 Set<Class> seen = new Set<Class>(); |
878 | 965 |
879 void collect(cls) { | 966 void collect(cls) { |
880 if (cls == null || seen.contains(cls)) return; | 967 if (cls == null || seen.contains(cls)) return; |
881 | 968 |
882 Class superclass = cls.superclass; | 969 Class superclass = cls.superclass; |
883 if (classesInFragment.contains(superclass)) { | 970 if (classesInFragment.contains(superclass)) { |
884 collect(superclass); | 971 collect(superclass); |
885 } | 972 } |
886 | 973 |
887 subclasses.putIfAbsent(superclass, () => <Class>[]).add(cls); | 974 subclasses.putIfAbsent(superclass, () => <Class>[]).add(cls); |
888 | 975 |
889 seen.add(cls); | 976 seen.add(cls); |
890 } | 977 } |
891 | 978 |
892 for (Library library in fragment.libraries) { | 979 for (Library library in fragment.libraries) { |
893 for (Class cls in library.classes) { | 980 for (Class cls in library.classes) { |
| 981 if (cls.isSoftDeferred != softDeferred) continue; |
894 collect(cls); | 982 collect(cls); |
895 | 983 |
896 if (cls.isMixinApplication) { | 984 if (cls.isMixinApplication) { |
897 MixinApplication mixin = cls; | 985 MixinApplication mixin = cls; |
898 mixinCalls.add(js.js.statement('mixin(#, #)', | 986 mixinCalls.add(js.js.statement('mixin(#, #)', |
899 [classReference(cls), classReference(mixin.mixinClass)])); | 987 [classReference(cls), classReference(mixin.mixinClass)])); |
900 } | 988 } |
901 } | 989 } |
902 } | 990 } |
903 | 991 |
(...skipping 26 matching lines...) Expand all Loading... |
930 } | 1018 } |
931 | 1019 |
932 return wrapPhase( | 1020 return wrapPhase( |
933 'inheritance', js.js.statement('{#; #;}', [inheritCalls, mixinCalls])); | 1021 'inheritance', js.js.statement('{#; #;}', [inheritCalls, mixinCalls])); |
934 } | 1022 } |
935 | 1023 |
936 /// Emits the setup of method aliases. | 1024 /// Emits the setup of method aliases. |
937 /// | 1025 /// |
938 /// This step consists of simply copying JavaScript functions to their | 1026 /// This step consists of simply copying JavaScript functions to their |
939 /// aliased names so they point to the same function. | 1027 /// aliased names so they point to the same function. |
940 js.Statement emitInstanceMethodAliases(Fragment fragment) { | 1028 js.Statement emitInstanceMethodAliases(Fragment fragment, |
| 1029 {bool softDeferred = false}) { |
941 List<js.Statement> assignments = <js.Statement>[]; | 1030 List<js.Statement> assignments = <js.Statement>[]; |
942 | 1031 |
943 for (Library library in fragment.libraries) { | 1032 for (Library library in fragment.libraries) { |
944 for (Class cls in library.classes) { | 1033 for (Class cls in library.classes) { |
| 1034 if (cls.isSoftDeferred != softDeferred) continue; |
945 for (InstanceMethod method in cls.methods) { | 1035 for (InstanceMethod method in cls.methods) { |
946 if (method.aliasName != null) { | 1036 if (method.aliasName != null) { |
947 assignments.add(js.js.statement('#.prototype.# = #.prototype.#', [ | 1037 assignments.add(js.js.statement('#.prototype.# = #.prototype.#', [ |
948 classReference(cls), | 1038 classReference(cls), |
949 js.quoteName(method.aliasName), | 1039 js.quoteName(method.aliasName), |
950 classReference(cls), | 1040 classReference(cls), |
951 js.quoteName(method.name) | 1041 js.quoteName(method.name) |
952 ])); | 1042 ])); |
953 } | 1043 } |
954 } | 1044 } |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1059 } | 1149 } |
1060 | 1150 |
1061 /// Wraps the statement in a named function to that it shows up as a unit in | 1151 /// Wraps the statement in a named function to that it shows up as a unit in |
1062 /// profiles. | 1152 /// profiles. |
1063 // TODO(sra): Should this be conditional? | 1153 // TODO(sra): Should this be conditional? |
1064 js.Statement wrapPhase(String name, js.Statement statement) { | 1154 js.Statement wrapPhase(String name, js.Statement statement) { |
1065 return js.js.statement('(function #(){#})();', [name, statement]); | 1155 return js.js.statement('(function #(){#})();', [name, statement]); |
1066 } | 1156 } |
1067 | 1157 |
1068 /// Emits the section that installs tear-off getters. | 1158 /// Emits the section that installs tear-off getters. |
1069 js.Statement emitInstallTearOffs(Fragment fragment) { | 1159 js.Statement emitInstallTearOffs(Fragment fragment, |
| 1160 {bool softDeferred = false}) { |
1070 List<js.Statement> inits = <js.Statement>[]; | 1161 List<js.Statement> inits = <js.Statement>[]; |
1071 js.Expression temp; | 1162 js.Expression temp; |
1072 | 1163 |
1073 for (Library library in fragment.libraries) { | 1164 for (Library library in fragment.libraries) { |
1074 for (StaticMethod method in library.statics) { | 1165 for (StaticMethod method in library.statics) { |
1075 // TODO(floitsch): can there be anything else than a StaticDartMethod? | 1166 // TODO(floitsch): can there be anything else than a StaticDartMethod? |
1076 if (method is StaticDartMethod) { | 1167 if (method is StaticDartMethod) { |
1077 if (method.needsTearOff) { | 1168 if (method.needsTearOff) { |
1078 Holder holder = method.holder; | 1169 Holder holder = method.holder; |
1079 inits.add( | 1170 inits.add( |
1080 emitInstallTearOff(new js.VariableUse(holder.name), method)); | 1171 emitInstallTearOff(new js.VariableUse(holder.name), method)); |
1081 } | 1172 } |
1082 } | 1173 } |
1083 } | 1174 } |
1084 for (Class cls in library.classes) { | 1175 for (Class cls in library.classes) { |
| 1176 if (cls.isSoftDeferred != softDeferred) continue; |
1085 var methods = cls.methods.where((m) => m.needsTearOff).toList(); | 1177 var methods = cls.methods.where((m) => m.needsTearOff).toList(); |
1086 js.Expression container = js.js("#.prototype", classReference(cls)); | 1178 js.Expression container = js.js("#.prototype", classReference(cls)); |
1087 js.Expression reference = container; | 1179 js.Expression reference = container; |
1088 if (methods.length > 1) { | 1180 if (methods.length > 1) { |
1089 if (temp == null) { | 1181 if (temp == null) { |
1090 inits.add(js.js.statement('var _;')); | 1182 inits.add(js.js.statement('var _;')); |
1091 temp = js.js('_'); | 1183 temp = js.js('_'); |
1092 } | 1184 } |
1093 // First call uses assignment to temp to cache the container. | 1185 // First call uses assignment to temp to cache the container. |
1094 reference = js.js('# = #', [temp, container]); | 1186 reference = js.js('# = #', [temp, container]); |
(...skipping 371 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1466 } | 1558 } |
1467 statements.add(js.js.statement("setOrUpdateInterceptorsByTag(#);", | 1559 statements.add(js.js.statement("setOrUpdateInterceptorsByTag(#);", |
1468 js.objectLiteral(interceptorsByTag))); | 1560 js.objectLiteral(interceptorsByTag))); |
1469 statements.add( | 1561 statements.add( |
1470 js.js.statement("setOrUpdateLeafTags(#);", js.objectLiteral(leafTags))); | 1562 js.js.statement("setOrUpdateLeafTags(#);", js.objectLiteral(leafTags))); |
1471 statements.addAll(subclassAssignments); | 1563 statements.addAll(subclassAssignments); |
1472 | 1564 |
1473 return wrapPhase('nativeSupport', new js.Block(statements)); | 1565 return wrapPhase('nativeSupport', new js.Block(statements)); |
1474 } | 1566 } |
1475 } | 1567 } |
OLD | NEW |