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 library dart2js_incremental.library_updater; | 5 library dart2js_incremental.library_updater; |
6 | 6 |
7 import 'dart:async' show | 7 import 'dart:async' show |
8 Future; | 8 Future; |
9 | 9 |
10 import 'dart:convert' show | 10 import 'dart:convert' show |
(...skipping 600 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
611 | 611 |
612 List<jsAst.Statement> updates = <jsAst.Statement>[]; | 612 List<jsAst.Statement> updates = <jsAst.Statement>[]; |
613 | 613 |
614 Set<ClassElementX> newClasses = new Set.from( | 614 Set<ClassElementX> newClasses = new Set.from( |
615 compiler.codegenWorld.directlyInstantiatedClasses); | 615 compiler.codegenWorld.directlyInstantiatedClasses); |
616 newClasses.removeAll(_directlyInstantiatedClasses); | 616 newClasses.removeAll(_directlyInstantiatedClasses); |
617 | 617 |
618 if (!newClasses.isEmpty) { | 618 if (!newClasses.isEmpty) { |
619 // Ask the emitter to compute "needs" (only) if new classes were | 619 // Ask the emitter to compute "needs" (only) if new classes were |
620 // instantiated. | 620 // instantiated. |
621 _ensureNeedsComputed(); | 621 _ensureAllNeededEntitiesComputed(); |
622 newClasses = new Set.from(emitter.neededClasses); | 622 newClasses = new Set.from(emitter.neededClasses); |
623 newClasses.removeAll(_emittedClasses); | 623 newClasses.removeAll(_emittedClasses); |
624 } else { | 624 } else { |
625 // Make sure that the set of emitted classes is preserved for subsequent | 625 // Make sure that the set of emitted classes is preserved for subsequent |
626 // updates. | 626 // updates. |
627 // TODO(ahe): This is a bit convoluted, find a better approach. | 627 // TODO(ahe): This is a bit convoluted, find a better approach. |
628 emitter.neededClasses | 628 emitter.neededClasses |
629 ..clear() | 629 ..clear() |
630 ..addAll(_emittedClasses); | 630 ..addAll(_emittedClasses); |
631 } | 631 } |
632 | 632 |
633 List<jsAst.Statement> inherits = <jsAst.Statement>[]; | 633 List<jsAst.Statement> inherits = <jsAst.Statement>[]; |
634 | 634 |
635 for (ClassElementX cls in newClasses) { | 635 for (ClassElementX cls in newClasses) { |
636 jsAst.Node classAccess = emitter.classAccess(cls); | 636 jsAst.Node classAccess = emitter.classAccess(cls); |
637 String name = namer.getNameOfClass(cls); | 637 String name = namer.getNameOfClass(cls); |
638 | 638 |
639 updates.add( | 639 updates.add( |
640 js.statement( | 640 js.statement( |
641 r'# = #', [classAccess, invokeDefineClass(cls)])); | 641 r'# = #', [classAccess, invokeDefineClass(cls)])); |
642 | 642 |
643 ClassElement superclass = cls.superclass; | 643 ClassElement superclass = cls.superclass; |
644 if (superclass != null) { | 644 if (superclass != null) { |
645 jsAst.Node superAccess = emitter.classAccess(superclass); | 645 jsAst.Node superAccess = emitter.classAccess(superclass); |
646 inherits.add( | 646 inherits.add( |
647 js.statement( | 647 js.statement( |
648 r'self.$dart_unsafe_eval.inheritFrom(#, #)', | 648 r'#.inheritFrom(#, #)', [helper, classAccess, superAccess])); |
649 [classAccess, superAccess])); | |
650 } | 649 } |
651 } | 650 } |
652 | 651 |
653 // Call inheritFrom after all classes have been created. This way we don't | 652 // Call inheritFrom after all classes have been created. This way we don't |
654 // need to sort the classes by having superclasses defined before their | 653 // need to sort the classes by having superclasses defined before their |
655 // subclasses. | 654 // subclasses. |
656 updates.addAll(inherits); | 655 updates.addAll(inherits); |
657 | 656 |
658 for (ClassElementX cls in changedClasses) { | 657 for (ClassElementX cls in changedClasses) { |
659 ClassElement superclass = cls.superclass; | 658 ClassElement superclass = cls.superclass; |
660 jsAst.Node superAccess = | 659 jsAst.Node superAccess = |
661 superclass == null ? js('null') | 660 superclass == null ? js('null') |
662 : emitter.classAccess(superclass); | 661 : emitter.classAccess(superclass); |
663 jsAst.Node classAccess = emitter.classAccess(cls); | 662 jsAst.Node classAccess = emitter.classAccess(cls); |
664 updates.add( | 663 updates.add( |
665 js.statement( | 664 js.statement( |
666 r'# = self.$dart_unsafe_eval.schemaChange(#, #, #)', | 665 r'# = #.schemaChange(#, #, #)', |
667 [classAccess, invokeDefineClass(cls), classAccess, superAccess])); | 666 [classAccess, helper, |
| 667 invokeDefineClass(cls), classAccess, superAccess])); |
668 } | 668 } |
669 | 669 |
670 for (RemovalUpdate update in removals) { | 670 for (RemovalUpdate update in removals) { |
671 update.writeUpdateJsOn(updates); | 671 update.writeUpdateJsOn(updates); |
672 } | 672 } |
673 for (Element element in enqueuer.codegen.newlyEnqueuedElements) { | 673 for (Element element in enqueuer.codegen.newlyEnqueuedElements) { |
674 if (element.isField) { | 674 if (element.isField) { |
675 updates.addAll(computeFieldUpdateJs(element)); | 675 updates.addAll(computeFieldUpdateJs(element)); |
676 } else { | 676 } else { |
677 updates.add(computeMethodUpdateJs(element)); | 677 updates.add(computeMethodUpdateJs(element)); |
678 } | 678 } |
679 } | 679 } |
680 | 680 |
681 Set<ConstantValue> newConstants = new Set<ConstantValue>.identity()..addAll( | 681 Set<ConstantValue> newConstants = new Set<ConstantValue>.identity()..addAll( |
682 compiler.backend.constants.compiledConstants); | 682 compiler.backend.constants.compiledConstants); |
683 newConstants.removeAll(_compiledConstants); | 683 newConstants.removeAll(_compiledConstants); |
684 | 684 |
685 if (!newConstants.isEmpty) { | 685 if (!newConstants.isEmpty) { |
686 _ensureNeedsComputed(); | 686 _ensureAllNeededEntitiesComputed(); |
687 List<ConstantValue> constants = | 687 List<ConstantValue> constants = |
688 emitter.outputConstantLists[compiler.deferredLoadTask.mainOutputUnit]; | 688 emitter.outputConstantLists[compiler.deferredLoadTask.mainOutputUnit]; |
689 if (constants != null) { | 689 if (constants != null) { |
690 for (ConstantValue constant in constants) { | 690 for (ConstantValue constant in constants) { |
691 if (newConstants.contains(constant)) { | 691 if (newConstants.contains(constant)) { |
692 jsAst.Statement constantInitializer = emitter.oldEmitter | 692 jsAst.Statement constantInitializer = emitter.oldEmitter |
693 .buildConstantInitializer(constant).toStatement(); | 693 .buildConstantInitializer(constant).toStatement(); |
694 updates.add(constantInitializer); | 694 updates.add(constantInitializer); |
695 } | 695 } |
696 } | 696 } |
697 } | 697 } |
698 } | 698 } |
699 | 699 |
700 updates.add(js.statement(r''' | 700 updates.add(js.statement(r''' |
701 if (self.$dart_unsafe_eval.pendingStubs) { | 701 if (#helper.pendingStubs) { |
702 self.$dart_unsafe_eval.pendingStubs.map(function(e) { return e(); }); | 702 #helper.pendingStubs.map(function(e) { return e(); }); |
703 self.$dart_unsafe_eval.pendingStubs = void 0; | 703 #helper.pendingStubs = void 0; |
704 } | 704 } |
705 ''')); | 705 ''', {'helper': helper})); |
706 | 706 |
707 if (updates.length == 1) { | 707 if (updates.length == 1) { |
708 return prettyPrintJs(updates.single); | 708 return prettyPrintJs(updates.single); |
709 } else { | 709 } else { |
710 return prettyPrintJs(js.statement('{#}', [updates])); | 710 return prettyPrintJs(js.statement('{#}', [updates])); |
711 } | 711 } |
712 } | 712 } |
713 | 713 |
714 jsAst.Expression invokeDefineClass(ClassElementX cls) { | 714 jsAst.Expression invokeDefineClass(ClassElementX cls) { |
715 String name = namer.getNameOfClass(cls); | 715 String name = namer.getNameOfClass(cls); |
716 var descriptor = js('Object.create(null)'); | 716 var descriptor = js('Object.create(null)'); |
717 return js( | 717 return js( |
718 r''' | 718 r''' |
719 (new Function( | 719 (new Function( |
720 "$collectedClasses", "$desc", | 720 "$collectedClasses", "$desc", |
721 self.$dart_unsafe_eval.defineClass(#, #) +"\n;return " + #))({#: #})''', | 721 #helper.defineClass(#name, #computeFields) +"\n;return " + #name))( |
722 [js.string(name), js.stringArray(computeFields(cls)), | 722 {#name: #descriptor})''', |
723 js.string(name), | 723 {'helper': helper, |
724 js.string(name), descriptor]); | 724 'name': js.string(name), |
| 725 'computeFields': js.stringArray(computeFields(cls)), |
| 726 'descriptor': descriptor}); |
725 } | 727 } |
726 | 728 |
727 jsAst.Node computeMethodUpdateJs(Element element) { | 729 jsAst.Node computeMethodUpdateJs(Element element) { |
728 MemberInfo info = containerBuilder.analyzeMemberMethod(element); | 730 MemberInfo info = containerBuilder.analyzeMemberMethod(element); |
729 if (info == null) { | 731 if (info == null) { |
730 compiler.internalError(element, '${element.runtimeType}'); | 732 compiler.internalError(element, '${element.runtimeType}'); |
731 } | 733 } |
732 ClassBuilder builder = new ClassBuilder(element, namer); | 734 ClassBuilder builder = new ClassBuilder(element, namer); |
733 containerBuilder.addMemberMethodFromInfo(info, builder); | 735 containerBuilder.addMemberMethodFromInfo(info, builder); |
734 jsAst.Node partialDescriptor = | 736 jsAst.Node partialDescriptor = |
735 builder.toObjectInitializer(omitClassDescriptor: true); | 737 builder.toObjectInitializer(emitClassDescriptor: false); |
736 | 738 |
737 String name = info.name; | 739 String name = info.name; |
738 jsAst.Node function = info.code; | 740 jsAst.Node function = info.code; |
739 bool isStatic = !element.isInstanceMember; | 741 bool isStatic = !element.isInstanceMember; |
740 | 742 |
741 /// Either a global object (non-instance members) or a prototype (instance | 743 /// Either a global object (non-instance members) or a prototype (instance |
742 /// members). | 744 /// members). |
743 jsAst.Node holder; | 745 jsAst.Node holder; |
744 | 746 |
745 if (element.isInstanceMember) { | 747 if (element.isInstanceMember) { |
746 holder = js('#.prototype', emitter.classAccess(element.enclosingClass)); | 748 holder = js('#.prototype', emitter.classAccess(element.enclosingClass)); |
747 } else { | 749 } else { |
748 holder = js('#', namer.globalObjectFor(element)); | 750 holder = js('#', namer.globalObjectFor(element)); |
749 } | 751 } |
750 | 752 |
751 jsAst.Expression globalFunctionsAccess = | 753 jsAst.Expression globalFunctionsAccess = |
752 emitter.generateEmbeddedGlobalAccess(embeddedNames.GLOBAL_FUNCTIONS); | 754 emitter.generateEmbeddedGlobalAccess(embeddedNames.GLOBAL_FUNCTIONS); |
753 | 755 |
754 return js.statement( | 756 return js.statement( |
755 r'self.$dart_unsafe_eval.addMethod(#, #, #, #, #)', | 757 r'#.addMethod(#, #, #, #, #)', |
756 [partialDescriptor, js.string(name), holder, | 758 [helper, partialDescriptor, js.string(name), holder, |
757 new jsAst.LiteralBool(isStatic), globalFunctionsAccess]); | 759 new jsAst.LiteralBool(isStatic), globalFunctionsAccess]); |
758 } | 760 } |
759 | 761 |
760 List<jsAst.Statement> computeFieldUpdateJs(FieldElementX element) { | 762 List<jsAst.Statement> computeFieldUpdateJs(FieldElementX element) { |
761 if (element.isInstanceMember) { | 763 if (element.isInstanceMember) { |
762 // Any initializers are inlined in factory methods, and the field is | 764 // Any initializers are inlined in factory methods, and the field is |
763 // declared by adding its class to [_classesWithSchemaChanges]. | 765 // declared by adding its class to [_classesWithSchemaChanges]. |
764 return const <jsAst.Statement>[]; | 766 return const <jsAst.Statement>[]; |
765 } | 767 } |
766 // A static (or top-level) field. | 768 // A static (or top-level) field. |
(...skipping 27 matching lines...) Expand all Loading... |
794 // TODO(ahe): Call a method in the compiler to obtain this name. | 796 // TODO(ahe): Call a method in the compiler to obtain this name. |
795 String callPrefix = namer.callPrefix; | 797 String callPrefix = namer.callPrefix; |
796 int parameterCount = element.functionSignature.parameterCount; | 798 int parameterCount = element.functionSignature.parameterCount; |
797 return '$callPrefix\$$parameterCount'; | 799 return '$callPrefix\$$parameterCount'; |
798 } | 800 } |
799 | 801 |
800 List<String> computeFields(ClassElement cls) { | 802 List<String> computeFields(ClassElement cls) { |
801 return new EmitterHelper(compiler).computeFields(cls); | 803 return new EmitterHelper(compiler).computeFields(cls); |
802 } | 804 } |
803 | 805 |
804 void _ensureNeedsComputed() { | 806 void _ensureAllNeededEntitiesComputed() { |
805 if (_hasComputedNeeds) return; | 807 if (_hasComputedNeeds) return; |
806 emitter.computeAllNeededEntities(); | 808 emitter.computeAllNeededEntities(); |
807 _hasComputedNeeds = true; | 809 _hasComputedNeeds = true; |
808 } | 810 } |
809 } | 811 } |
810 | 812 |
811 /// Represents an update (aka patch) of [before] to [after]. We use the word | 813 /// Represents an update (aka patch) of [before] to [after]. We use the word |
812 /// "update" to avoid confusion with the compiler feature of "patch" methods. | 814 /// "update" to avoid confusion with the compiler feature of "patch" methods. |
813 abstract class Update { | 815 abstract class Update { |
814 final Compiler compiler; | 816 final Compiler compiler; |
(...skipping 436 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1251 | 1253 |
1252 JavaScriptBackend get backend => compiler.backend; | 1254 JavaScriptBackend get backend => compiler.backend; |
1253 | 1255 |
1254 Namer get namer => backend.namer; | 1256 Namer get namer => backend.namer; |
1255 | 1257 |
1256 CodeEmitterTask get emitter => backend.emitter; | 1258 CodeEmitterTask get emitter => backend.emitter; |
1257 | 1259 |
1258 ContainerBuilder get containerBuilder => emitter.oldEmitter.containerBuilder; | 1260 ContainerBuilder get containerBuilder => emitter.oldEmitter.containerBuilder; |
1259 | 1261 |
1260 EnqueueTask get enqueuer => compiler.enqueuer; | 1262 EnqueueTask get enqueuer => compiler.enqueuer; |
| 1263 |
| 1264 jsAst.Expression get helper => namer.accessIncrementalHelper; |
1261 } | 1265 } |
1262 | 1266 |
1263 class EmitterHelper extends JsFeatures { | 1267 class EmitterHelper extends JsFeatures { |
1264 final Compiler compiler; | 1268 final Compiler compiler; |
1265 | 1269 |
1266 EmitterHelper(this.compiler); | 1270 EmitterHelper(this.compiler); |
1267 | 1271 |
1268 ClassEmitter get classEmitter => backend.emitter.oldEmitter.classEmitter; | 1272 ClassEmitter get classEmitter => backend.emitter.oldEmitter.classEmitter; |
1269 | 1273 |
1270 List<String> computeFields(ClassElement cls) { | 1274 List<String> computeFields(ClassElement cls) { |
1271 // TODO(ahe): Rewrite for new emitter. | 1275 // TODO(ahe): Rewrite for new emitter. |
1272 ClassBuilder builder = new ClassBuilder(cls, namer); | 1276 ClassBuilder builder = new ClassBuilder(cls, namer); |
1273 classEmitter.emitFields(cls, builder); | 1277 classEmitter.emitFields(cls, builder); |
1274 return builder.fields; | 1278 return builder.fields; |
1275 } | 1279 } |
1276 } | 1280 } |
1277 | 1281 |
1278 // TODO(ahe): Remove this method. | 1282 // TODO(ahe): Remove this method. |
1279 NO_WARN(x) => x; | 1283 NO_WARN(x) => x; |
OLD | NEW |