| 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 Script; | 17 Script; |
| 18 | 18 |
| 19 import 'package:compiler/src/elements/elements.dart' show | 19 import 'package:compiler/src/elements/elements.dart' show |
| 20 ClassElement, | 20 ClassElement, |
| 21 Element, | 21 Element, |
| 22 FunctionElement, | 22 FunctionElement, |
| 23 LibraryElement, | 23 LibraryElement, |
| 24 STATE_NOT_STARTED, |
| 24 ScopeContainerElement; | 25 ScopeContainerElement; |
| 25 | 26 |
| 26 import 'package:compiler/src/scanner/scannerlib.dart' show | 27 import 'package:compiler/src/scanner/scannerlib.dart' show |
| 27 EOF_TOKEN, | 28 EOF_TOKEN, |
| 28 PartialClassElement, | 29 PartialClassElement, |
| 29 PartialElement, | 30 PartialElement, |
| 30 PartialFunctionElement, | 31 PartialFunctionElement, |
| 31 Token; | 32 Token; |
| 32 | 33 |
| 33 import 'package:compiler/src/source_file.dart' show | 34 import 'package:compiler/src/source_file.dart' show |
| (...skipping 332 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 366 PartialClassElement after) { | 367 PartialClassElement after) { |
| 367 ClassNode node = after.parseNode(compiler).asClassNode(); | 368 ClassNode node = after.parseNode(compiler).asClassNode(); |
| 368 if (node == null) { | 369 if (node == null) { |
| 369 return cannotReuse(after, "Not a ClassNode: '$node'"); | 370 return cannotReuse(after, "Not a ClassNode: '$node'"); |
| 370 } | 371 } |
| 371 NodeList body = node.body; | 372 NodeList body = node.body; |
| 372 if (body == null) { | 373 if (body == null) { |
| 373 return cannotReuse(after, "Class has no body."); | 374 return cannotReuse(after, "Class has no body."); |
| 374 } | 375 } |
| 375 if (isTokenBetween(diffToken, node.beginToken, body.beginToken)) { | 376 if (isTokenBetween(diffToken, node.beginToken, body.beginToken)) { |
| 376 return cannotReuse(after, "Class header changed."); | 377 logVerbose('Class header modified in ${after}'); |
| 378 updates.add(new ClassUpdate(compiler, before, after)); |
| 379 before.forEachLocalMember((ElementX member) { |
| 380 // TODO(ahe): Quadratic. |
| 381 invalidateScopesAffectedBy(member, before); |
| 382 }); |
| 377 } | 383 } |
| 378 logVerbose('Simple modification of ${after} detected'); | |
| 379 return canReuseScopeContainerElement(before, after); | 384 return canReuseScopeContainerElement(before, after); |
| 380 } | 385 } |
| 381 | 386 |
| 382 bool isTokenBetween(Token token, Token first, Token last) { | 387 bool isTokenBetween(Token token, Token first, Token last) { |
| 383 Token current = first; | 388 Token current = first; |
| 384 while (current != last && current.kind != EOF_TOKEN) { | 389 while (current != last && current.kind != EOF_TOKEN) { |
| 385 if (current == token) { | 390 if (current == token) { |
| 386 return true; | 391 return true; |
| 387 } | 392 } |
| 388 current = current.next; | 393 current = current.next; |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 439 new Set.from(compiler.codegenWorld.directlyInstantiatedClasses); | 444 new Set.from(compiler.codegenWorld.directlyInstantiatedClasses); |
| 440 | 445 |
| 441 List<Update> removals = <Update>[]; | 446 List<Update> removals = <Update>[]; |
| 442 List<Element> updatedElements = applyUpdates(removals); | 447 List<Element> updatedElements = applyUpdates(removals); |
| 443 if (compiler.progress != null) { | 448 if (compiler.progress != null) { |
| 444 compiler.progress.reset(); | 449 compiler.progress.reset(); |
| 445 } | 450 } |
| 446 for (Element element in updatedElements) { | 451 for (Element element in updatedElements) { |
| 447 if (!element.isClass) { | 452 if (!element.isClass) { |
| 448 compiler.enqueuer.resolution.addToWorkList(element); | 453 compiler.enqueuer.resolution.addToWorkList(element); |
| 454 } else { |
| 455 element.ensureResolved(compiler); |
| 449 } | 456 } |
| 450 } | 457 } |
| 451 compiler.processQueue(compiler.enqueuer.resolution, null); | 458 compiler.processQueue(compiler.enqueuer.resolution, null); |
| 452 | 459 |
| 453 compiler.phase = Compiler.PHASE_DONE_RESOLVING; | 460 compiler.phase = Compiler.PHASE_DONE_RESOLVING; |
| 454 | 461 |
| 462 Set<PartialClassElement> changedClasses = new Set<PartialClassElement>(); |
| 455 for (Element element in updatedElements) { | 463 for (Element element in updatedElements) { |
| 456 if (!element.isClass) { | 464 if (!element.isClass) { |
| 457 compiler.enqueuer.codegen.addToWorkList(element); | 465 compiler.enqueuer.codegen.addToWorkList(element); |
| 466 } else { |
| 467 changedClasses.add(element); |
| 458 } | 468 } |
| 459 } | 469 } |
| 460 compiler.processQueue(compiler.enqueuer.codegen, null); | 470 compiler.processQueue(compiler.enqueuer.codegen, null); |
| 461 | 471 |
| 462 List<jsAst.Statement> updates = <jsAst.Statement>[]; | 472 List<jsAst.Statement> updates = <jsAst.Statement>[]; |
| 463 | 473 |
| 464 Set newClasses = | 474 Set newClasses = |
| 465 new Set.from(compiler.codegenWorld.directlyInstantiatedClasses); | 475 new Set.from(compiler.codegenWorld.directlyInstantiatedClasses); |
| 466 newClasses.removeAll(existingClasses); | 476 newClasses.removeAll(existingClasses); |
| 467 | 477 |
| (...skipping 23 matching lines...) Expand all Loading... |
| 491 jsAst.Node superAccess = namer.elementAccess(superclass); | 501 jsAst.Node superAccess = namer.elementAccess(superclass); |
| 492 inherits.add( | 502 inherits.add( |
| 493 js.statement( | 503 js.statement( |
| 494 r'self.$dart_unsafe_eval.inheritFrom(#, #)', | 504 r'self.$dart_unsafe_eval.inheritFrom(#, #)', |
| 495 [classAccess, superAccess])); | 505 [classAccess, superAccess])); |
| 496 } | 506 } |
| 497 } | 507 } |
| 498 | 508 |
| 499 updates.addAll(inherits); | 509 updates.addAll(inherits); |
| 500 | 510 |
| 511 for (ClassElementX cls in changedClasses) { |
| 512 ClassElement superclass = cls.superclass; |
| 513 if (superclass != null) { |
| 514 jsAst.Node classAccess = namer.elementAccess(cls); |
| 515 jsAst.Node superAccess = namer.elementAccess(superclass); |
| 516 updates.add( |
| 517 js.statement( |
| 518 r'#.prototype.__proto__ = #.prototype', |
| 519 [classAccess, superAccess])); |
| 520 updates.add( |
| 521 js.statement( |
| 522 r'#.prototype.constructor = #', |
| 523 [classAccess, classAccess])); |
| 524 } |
| 525 } |
| 526 |
| 501 for (RemovedFunctionUpdate update in removals) { | 527 for (RemovedFunctionUpdate update in removals) { |
| 502 update.writeUpdateJsOn(updates); | 528 update.writeUpdateJsOn(updates); |
| 503 } | 529 } |
| 504 for (Element element in compiler.enqueuer.codegen.newlyEnqueuedElements) { | 530 for (Element element in compiler.enqueuer.codegen.newlyEnqueuedElements) { |
| 505 if (!element.isField) { | 531 if (!element.isField) { |
| 506 updates.add(computeMemberUpdateJs(element)); | 532 updates.add(computeMemberUpdateJs(element)); |
| 507 } | 533 } |
| 508 } | 534 } |
| 509 | 535 |
| 510 if (updates.length == 1) { | 536 if (updates.length == 1) { |
| (...skipping 339 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 850 | 876 |
| 851 PartialFunctionElement apply() { | 877 PartialFunctionElement apply() { |
| 852 // TODO(ahe): Reuse compilation unit of element instead? | 878 // TODO(ahe): Reuse compilation unit of element instead? |
| 853 CompilationUnitElementX compilationUnit = library.compilationUnit; | 879 CompilationUnitElementX compilationUnit = library.compilationUnit; |
| 854 PartialClassElement copy = element.copyWithEnclosing(compilationUnit); | 880 PartialClassElement copy = element.copyWithEnclosing(compilationUnit); |
| 855 compilationUnit.addMember(copy, compiler); | 881 compilationUnit.addMember(copy, compiler); |
| 856 return copy; | 882 return copy; |
| 857 } | 883 } |
| 858 } | 884 } |
| 859 | 885 |
| 886 class ClassUpdate extends Update with JsFeatures { |
| 887 final PartialClassElement before; |
| 888 |
| 889 final PartialClassElement after; |
| 890 |
| 891 ClassUpdate(Compiler compiler, this.before, this.after) |
| 892 : super(compiler); |
| 893 |
| 894 PartialFunctionElement apply() { |
| 895 patchElement(); |
| 896 reuseElement(); |
| 897 return before; |
| 898 } |
| 899 |
| 900 /// Destructively change the tokens in [before] to match those of [after]. |
| 901 void patchElement() { |
| 902 before.cachedNode = after.cachedNode; |
| 903 before.beginToken = after.beginToken; |
| 904 before.endToken = after.endToken; |
| 905 } |
| 906 |
| 907 void reuseElement() { |
| 908 before.supertype = null; |
| 909 before.interfaces = null; |
| 910 before.nativeTagInfo = null; |
| 911 before.supertypeLoadState = STATE_NOT_STARTED; |
| 912 before.resolutionState = STATE_NOT_STARTED; |
| 913 before.isProxy = false; |
| 914 before.hasIncompleteHierarchy = false; |
| 915 before.backendMembers = const Link<Element>(); |
| 916 before.allSupertypesAndSelf = null; |
| 917 } |
| 918 } |
| 919 |
| 860 /// Returns all qualified names in [element] with less than four identifiers. A | 920 /// Returns all qualified names in [element] with less than four identifiers. A |
| 861 /// qualified name is an identifier followed by a sequence of dots and | 921 /// qualified name is an identifier followed by a sequence of dots and |
| 862 /// identifiers, for example, "x", and "x.y.z". But not "x.y.z.w" ("w" is the | 922 /// identifiers, for example, "x", and "x.y.z". But not "x.y.z.w" ("w" is the |
| 863 /// fourth identifier). | 923 /// fourth identifier). |
| 864 /// | 924 /// |
| 865 /// The longest possible name that can be resolved is three identifiers, for | 925 /// The longest possible name that can be resolved is three identifiers, for |
| 866 /// example, "prefix.MyClass.staticMethod". Since four or more identifiers | 926 /// example, "prefix.MyClass.staticMethod". Since four or more identifiers |
| 867 /// cannot resolve to anything statically, they're not included in the returned | 927 /// cannot resolve to anything statically, they're not included in the returned |
| 868 /// value of this method. | 928 /// value of this method. |
| 869 Set<String> qualifiedNamesIn(PartialElement element) { | 929 Set<String> qualifiedNamesIn(PartialElement element) { |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 950 | 1010 |
| 951 ClassEmitter get classEmitter => backend.emitter.oldEmitter.classEmitter; | 1011 ClassEmitter get classEmitter => backend.emitter.oldEmitter.classEmitter; |
| 952 | 1012 |
| 953 List<String> computeFields(ClassElement cls) { | 1013 List<String> computeFields(ClassElement cls) { |
| 954 // TODO(ahe): Rewrite for new emitter. | 1014 // TODO(ahe): Rewrite for new emitter. |
| 955 ClassBuilder builder = new ClassBuilder(cls, namer); | 1015 ClassBuilder builder = new ClassBuilder(cls, namer); |
| 956 classEmitter.emitFields(cls, builder, ""); | 1016 classEmitter.emitFields(cls, builder, ""); |
| 957 return builder.fields; | 1017 return builder.fields; |
| 958 } | 1018 } |
| 959 } | 1019 } |
| OLD | NEW |