| 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 |
| 11 UTF8; | 11 UTF8; |
| 12 | 12 |
| 13 import 'package:compiler/compiler.dart' as api; | 13 import 'package:compiler/compiler.dart' as api; |
| 14 | 14 |
| 15 import 'package:compiler/src/dart2jslib.dart' show | 15 import 'package:compiler/src/dart2jslib.dart' show |
| 16 Compiler, | 16 Compiler, |
| 17 EnqueueTask, |
| 17 Script; | 18 Script; |
| 18 | 19 |
| 19 import 'package:compiler/src/elements/elements.dart' show | 20 import 'package:compiler/src/elements/elements.dart' show |
| 20 ClassElement, | 21 ClassElement, |
| 21 Element, | 22 Element, |
| 22 FunctionElement, | 23 FunctionElement, |
| 23 LibraryElement, | 24 LibraryElement, |
| 24 STATE_NOT_STARTED, | 25 STATE_NOT_STARTED, |
| 25 ScopeContainerElement; | 26 ScopeContainerElement; |
| 26 | 27 |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 65 LinkBuilder; | 66 LinkBuilder; |
| 66 | 67 |
| 67 import 'package:compiler/src/elements/modelx.dart' show | 68 import 'package:compiler/src/elements/modelx.dart' show |
| 68 ClassElementX, | 69 ClassElementX, |
| 69 CompilationUnitElementX, | 70 CompilationUnitElementX, |
| 70 DeclarationSite, | 71 DeclarationSite, |
| 71 ElementX, | 72 ElementX, |
| 72 FieldElementX, | 73 FieldElementX, |
| 73 LibraryElementX; | 74 LibraryElementX; |
| 74 | 75 |
| 76 import 'package:compiler/src/universe/universe.dart' show |
| 77 Selector; |
| 78 |
| 75 import 'diff.dart' show | 79 import 'diff.dart' show |
| 76 Difference, | 80 Difference, |
| 77 computeDifference; | 81 computeDifference; |
| 78 | 82 |
| 79 typedef void Logger(message); | 83 typedef void Logger(message); |
| 80 | 84 |
| 81 typedef bool Reuser( | 85 typedef bool Reuser( |
| 82 Token diffToken, | 86 Token diffToken, |
| 83 PartialElement before, | 87 PartialElement before, |
| 84 PartialElement after); | 88 PartialElement after); |
| (...skipping 455 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 540 } | 544 } |
| 541 | 545 |
| 542 String computeUpdateJs() { | 546 String computeUpdateJs() { |
| 543 List<Update> removals = <Update>[]; | 547 List<Update> removals = <Update>[]; |
| 544 List<Element> updatedElements = applyUpdates(removals); | 548 List<Element> updatedElements = applyUpdates(removals); |
| 545 if (compiler.progress != null) { | 549 if (compiler.progress != null) { |
| 546 compiler.progress.reset(); | 550 compiler.progress.reset(); |
| 547 } | 551 } |
| 548 for (Element element in updatedElements) { | 552 for (Element element in updatedElements) { |
| 549 if (!element.isClass) { | 553 if (!element.isClass) { |
| 550 compiler.enqueuer.resolution.addToWorkList(element); | 554 enqueuer.resolution.addToWorkList(element); |
| 551 } else { | 555 } else { |
| 552 NO_WARN(element).ensureResolved(compiler); | 556 NO_WARN(element).ensureResolved(compiler); |
| 553 } | 557 } |
| 554 } | 558 } |
| 555 compiler.processQueue(compiler.enqueuer.resolution, null); | 559 compiler.processQueue(enqueuer.resolution, null); |
| 556 | 560 |
| 557 compiler.phase = Compiler.PHASE_DONE_RESOLVING; | 561 compiler.phase = Compiler.PHASE_DONE_RESOLVING; |
| 558 | 562 |
| 559 // TODO(ahe): Clean this up. Don't call this method in analyze-only mode. | 563 // TODO(ahe): Clean this up. Don't call this method in analyze-only mode. |
| 560 if (compiler.analyzeOnly) return "/* analyze only */"; | 564 if (compiler.analyzeOnly) return "/* analyze only */"; |
| 561 | 565 |
| 562 Set<ClassElementX> changedClasses = | 566 Set<ClassElementX> changedClasses = |
| 563 new Set<ClassElementX>.from(_classesWithSchemaChanges); | 567 new Set<ClassElementX>.from(_classesWithSchemaChanges); |
| 564 for (Element element in updatedElements) { | 568 for (Element element in updatedElements) { |
| 565 if (!element.isClass) { | 569 if (!element.isClass) { |
| 566 compiler.enqueuer.codegen.addToWorkList(element); | 570 enqueuer.codegen.addToWorkList(element); |
| 567 } else { | 571 } else { |
| 568 changedClasses.add(element); | 572 changedClasses.add(element); |
| 569 } | 573 } |
| 570 } | 574 } |
| 571 compiler.processQueue(compiler.enqueuer.codegen, null); | 575 compiler.processQueue(enqueuer.codegen, null); |
| 576 |
| 577 // Run through all compiled methods and see if they may apply to |
| 578 // newlySeenSelectors. |
| 579 for (Element e in enqueuer.codegen.generatedCode.keys) { |
| 580 if (e.isFunction && !e.isConstructor && |
| 581 e.functionSignature.hasOptionalParameters) { |
| 582 for (Selector selector in enqueuer.codegen.newlySeenSelectors) { |
| 583 // TODO(ahe): Group selectors by name at this point for improved |
| 584 // performance. |
| 585 if (e.isInstanceMember && selector.applies(e, compiler.world)) { |
| 586 // TODO(ahe): Don't use |
| 587 // enqueuer.codegen.newlyEnqueuedElements directly like |
| 588 // this, make a copy. |
| 589 enqueuer.codegen.newlyEnqueuedElements.add(e); |
| 590 } |
| 591 if (selector.name == namer.closureInvocationSelectorName) { |
| 592 selector = new Selector.call( |
| 593 e.name, e.library, |
| 594 selector.argumentCount, selector.namedArguments); |
| 595 if (selector.appliesUnnamed(e, compiler.world)) { |
| 596 // TODO(ahe): Also make a copy here. |
| 597 enqueuer.codegen.newlyEnqueuedElements.add(e); |
| 598 } |
| 599 } |
| 600 } |
| 601 } |
| 602 } |
| 572 | 603 |
| 573 List<jsAst.Statement> updates = <jsAst.Statement>[]; | 604 List<jsAst.Statement> updates = <jsAst.Statement>[]; |
| 574 | 605 |
| 575 Set newClasses = new Set.from( | 606 // TODO(ahe): allInstantiatedClasses seem to include interfaces that aren't |
| 607 // needed. |
| 608 Set<ClassElementX> newClasses = new Set.from( |
| 576 compiler.codegenWorld.allInstantiatedClasses.where( | 609 compiler.codegenWorld.allInstantiatedClasses.where( |
| 577 emitter.computeClassFilter())); | 610 emitter.computeClassFilter())); |
| 578 newClasses.removeAll(_existingClasses); | 611 newClasses.removeAll(_existingClasses); |
| 579 | 612 |
| 613 // TODO(ahe): When more than one updated is computed, we need to make sure |
| 614 // that existing classes aren't overwritten. No test except the one test |
| 615 // that tests more than one update is affected by this problem, and only |
| 616 // because main is closurized because we always enable tear-off. Is that |
| 617 // really necessary? Also, add a test which tests directly that what |
| 618 // happens when tear-off is introduced in second update. |
| 619 emitter.neededClasses.addAll(newClasses); |
| 620 |
| 580 List<jsAst.Statement> inherits = <jsAst.Statement>[]; | 621 List<jsAst.Statement> inherits = <jsAst.Statement>[]; |
| 581 | 622 |
| 582 for (ClassElementX cls in newClasses) { | 623 for (ClassElementX cls in newClasses) { |
| 583 jsAst.Node classAccess = emitter.classAccess(cls); | 624 jsAst.Node classAccess = emitter.classAccess(cls); |
| 584 String name = namer.getNameOfClass(cls); | 625 String name = namer.getNameOfClass(cls); |
| 585 | 626 |
| 586 updates.add( | 627 updates.add( |
| 587 js.statement( | 628 js.statement( |
| 588 r'# = #', [classAccess, invokeDefineClass(cls)])); | 629 r'# = #', [classAccess, invokeDefineClass(cls)])); |
| 589 | 630 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 610 jsAst.Node classAccess = emitter.classAccess(cls); | 651 jsAst.Node classAccess = emitter.classAccess(cls); |
| 611 updates.add( | 652 updates.add( |
| 612 js.statement( | 653 js.statement( |
| 613 r'# = self.$dart_unsafe_eval.schemaChange(#, #, #)', | 654 r'# = self.$dart_unsafe_eval.schemaChange(#, #, #)', |
| 614 [classAccess, invokeDefineClass(cls), classAccess, superAccess])); | 655 [classAccess, invokeDefineClass(cls), classAccess, superAccess])); |
| 615 } | 656 } |
| 616 | 657 |
| 617 for (RemovalUpdate update in removals) { | 658 for (RemovalUpdate update in removals) { |
| 618 update.writeUpdateJsOn(updates); | 659 update.writeUpdateJsOn(updates); |
| 619 } | 660 } |
| 620 for (Element element in compiler.enqueuer.codegen.newlyEnqueuedElements) { | 661 for (Element element in enqueuer.codegen.newlyEnqueuedElements) { |
| 621 if (!element.isField) { | 662 if (!element.isField) { |
| 622 updates.add(computeMemberUpdateJs(element)); | 663 updates.add(computeMemberUpdateJs(element)); |
| 664 } else { |
| 665 if (backend.constants.lazyStatics.contains(element)) { |
| 666 throw new StateError("$element requires lazy initializer."); |
| 667 } |
| 623 } | 668 } |
| 624 } | 669 } |
| 625 | 670 |
| 671 updates.add(js.statement(r''' |
| 672 if (self.$dart_unsafe_eval.pendingStubs) { |
| 673 self.$dart_unsafe_eval.pendingStubs.map(function(e) { return e(); }); |
| 674 self.$dart_unsafe_eval.pendingStubs = void 0; |
| 675 } |
| 676 ''')); |
| 677 |
| 626 if (updates.length == 1) { | 678 if (updates.length == 1) { |
| 627 return prettyPrintJs(updates.single); | 679 return prettyPrintJs(updates.single); |
| 628 } else { | 680 } else { |
| 629 return prettyPrintJs(js.statement('{#}', [updates])); | 681 return prettyPrintJs(js.statement('{#}', [updates])); |
| 630 } | 682 } |
| 631 } | 683 } |
| 632 | 684 |
| 633 jsAst.Expression invokeDefineClass(ClassElementX cls) { | 685 jsAst.Expression invokeDefineClass(ClassElementX cls) { |
| 634 String name = namer.getNameOfClass(cls); | 686 String name = namer.getNameOfClass(cls); |
| 635 var descriptor = js('Object.create(null)'); | 687 var descriptor = js('Object.create(null)'); |
| (...skipping 494 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1130 abstract class JsFeatures { | 1182 abstract class JsFeatures { |
| 1131 Compiler get compiler; | 1183 Compiler get compiler; |
| 1132 | 1184 |
| 1133 JavaScriptBackend get backend => compiler.backend; | 1185 JavaScriptBackend get backend => compiler.backend; |
| 1134 | 1186 |
| 1135 Namer get namer => backend.namer; | 1187 Namer get namer => backend.namer; |
| 1136 | 1188 |
| 1137 CodeEmitterTask get emitter => backend.emitter; | 1189 CodeEmitterTask get emitter => backend.emitter; |
| 1138 | 1190 |
| 1139 ContainerBuilder get containerBuilder => emitter.oldEmitter.containerBuilder; | 1191 ContainerBuilder get containerBuilder => emitter.oldEmitter.containerBuilder; |
| 1192 |
| 1193 EnqueueTask get enqueuer => compiler.enqueuer; |
| 1140 } | 1194 } |
| 1141 | 1195 |
| 1142 class EmitterHelper extends JsFeatures { | 1196 class EmitterHelper extends JsFeatures { |
| 1143 final Compiler compiler; | 1197 final Compiler compiler; |
| 1144 | 1198 |
| 1145 EmitterHelper(this.compiler); | 1199 EmitterHelper(this.compiler); |
| 1146 | 1200 |
| 1147 ClassEmitter get classEmitter => backend.emitter.oldEmitter.classEmitter; | 1201 ClassEmitter get classEmitter => backend.emitter.oldEmitter.classEmitter; |
| 1148 | 1202 |
| 1149 List<String> computeFields(ClassElement cls) { | 1203 List<String> computeFields(ClassElement cls) { |
| 1150 // TODO(ahe): Rewrite for new emitter. | 1204 // TODO(ahe): Rewrite for new emitter. |
| 1151 ClassBuilder builder = new ClassBuilder(cls, namer); | 1205 ClassBuilder builder = new ClassBuilder(cls, namer); |
| 1152 classEmitter.emitFields(cls, builder, ""); | 1206 classEmitter.emitFields(cls, builder, ""); |
| 1153 return builder.fields; | 1207 return builder.fields; |
| 1154 } | 1208 } |
| 1155 } | 1209 } |
| 1156 | 1210 |
| 1157 // TODO(ahe): Remove this method. | 1211 // TODO(ahe): Remove this method. |
| 1158 NO_WARN(x) => x; | 1212 NO_WARN(x) => x; |
| OLD | NEW |