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 |