| 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 |