| 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 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 187 List<Difference> differences = computeDifference(element, newElement); | 187 List<Difference> differences = computeDifference(element, newElement); |
| 188 logTime('Differences computed.'); | 188 logTime('Differences computed.'); |
| 189 for (Difference difference in differences) { | 189 for (Difference difference in differences) { |
| 190 logTime('Looking at difference: $difference'); | 190 logTime('Looking at difference: $difference'); |
| 191 | 191 |
| 192 if (difference.before == null && difference.after is PartialElement) { | 192 if (difference.before == null && difference.after is PartialElement) { |
| 193 canReuseAddedElement(difference.after, element, newElement); | 193 canReuseAddedElement(difference.after, element, newElement); |
| 194 continue; | 194 continue; |
| 195 } | 195 } |
| 196 if (difference.after == null && difference.before is PartialElement) { | 196 if (difference.after == null && difference.before is PartialElement) { |
| 197 canReuseRemovedElement(difference.before); | 197 canReuseRemovedElement(difference.before, element); |
| 198 continue; | 198 continue; |
| 199 } | 199 } |
| 200 Token diffToken = difference.token; | 200 Token diffToken = difference.token; |
| 201 if (diffToken == null) { | 201 if (diffToken == null) { |
| 202 cannotReuse(difference, "No difference token."); | 202 cannotReuse(difference, "No difference token."); |
| 203 continue; | 203 continue; |
| 204 } | 204 } |
| 205 if (difference.after is! PartialElement && | 205 if (difference.after is! PartialElement && |
| 206 difference.before is! PartialElement) { | 206 difference.before is! PartialElement) { |
| 207 cannotReuse(difference, "Don't know how to recompile."); | 207 cannotReuse(difference, "Don't know how to recompile."); |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 275 PartialFieldList definition, | 275 PartialFieldList definition, |
| 276 ScopeContainerElement container, | 276 ScopeContainerElement container, |
| 277 ScopeContainerElement syntheticContainer) { | 277 ScopeContainerElement syntheticContainer) { |
| 278 List<FieldElementX> fields = <FieldElementX>[]; | 278 List<FieldElementX> fields = <FieldElementX>[]; |
| 279 syntheticContainer.forEachLocalMember((ElementX member) { | 279 syntheticContainer.forEachLocalMember((ElementX member) { |
| 280 if (member.declarationSite == definition) { | 280 if (member.declarationSite == definition) { |
| 281 fields.add(member); | 281 fields.add(member); |
| 282 } | 282 } |
| 283 }); | 283 }); |
| 284 for (FieldElementX field in fields) { | 284 for (FieldElementX field in fields) { |
| 285 // TODO(ahe): This only works when there's one field per |
| 286 // PartialFieldList. |
| 285 addField(field, container); | 287 addField(field, container); |
| 286 } | 288 } |
| 287 } | 289 } |
| 288 | 290 |
| 289 void addField(FieldElementX element, ScopeContainerElement container) { | 291 void addField(FieldElementX element, ScopeContainerElement container) { |
| 290 invalidateScopesAffectedBy(element, container); | 292 invalidateScopesAffectedBy(element, container); |
| 291 if (!element.isInstanceMember) { | 293 if (!element.isInstanceMember) { |
| 292 cannotReuse(element, "Not an instance field."); | 294 cannotReuse(element, "Not an instance field."); |
| 293 } else { | 295 } else { |
| 294 addInstanceField(element, container); | 296 addInstanceField(element, container); |
| 295 } | 297 } |
| 296 } | 298 } |
| 297 | 299 |
| 298 void addInstanceField(FieldElementX element, ClassElementX cls) { | 300 void addInstanceField(FieldElementX element, ClassElementX cls) { |
| 299 _classesWithSchemaChanges.add(cls); | 301 _classesWithSchemaChanges.add(cls); |
| 300 | 302 |
| 301 updates.add(new AddedFieldUpdate(compiler, element, cls)); | 303 updates.add(new AddedFieldUpdate(compiler, element, cls)); |
| 302 } | 304 } |
| 303 | 305 |
| 304 bool canReuseRemovedElement(PartialElement element) { | 306 bool canReuseRemovedElement( |
| 307 PartialElement element, |
| 308 ScopeContainerElement container) { |
| 305 if (element is PartialFunctionElement) { | 309 if (element is PartialFunctionElement) { |
| 306 removeFunction(element); | 310 removeFunction(element); |
| 307 return true; | 311 return true; |
| 308 } else if (element is PartialClassElement) { | 312 } else if (element is PartialClassElement) { |
| 309 removeClass(element); | 313 removeClass(element); |
| 310 return true; | 314 return true; |
| 315 } else if (element is PartialFieldList) { |
| 316 removeFields(element, container); |
| 317 return true; |
| 311 } | 318 } |
| 312 return cannotReuse(element, "Removed element that isn't a function."); | 319 return cannotReuse( |
| 320 element, "Removing ${element.runtimeType} not supported."); |
| 313 } | 321 } |
| 314 | 322 |
| 315 void removeFunction(PartialFunctionElement element) { | 323 void removeFunction(PartialFunctionElement element) { |
| 316 logVerbose("Removed method $element."); | 324 logVerbose("Removed method $element."); |
| 317 | 325 |
| 318 invalidateScopesAffectedBy(element, element.enclosingElement); | 326 invalidateScopesAffectedBy(element, element.enclosingElement); |
| 319 | 327 |
| 320 _removedElements.add(element); | 328 _removedElements.add(element); |
| 321 | 329 |
| 322 updates.add(new RemovedFunctionUpdate(compiler, element)); | 330 updates.add(new RemovedFunctionUpdate(compiler, element)); |
| 323 } | 331 } |
| 324 | 332 |
| 325 void removeClass(PartialClassElement element) { | 333 void removeClass(PartialClassElement element) { |
| 326 logVerbose("Removed class $element."); | 334 logVerbose("Removed class $element."); |
| 327 | 335 |
| 328 invalidateScopesAffectedBy(element, element.library); | 336 invalidateScopesAffectedBy(element, element.library); |
| 329 | 337 |
| 330 _removedElements.add(element); | 338 _removedElements.add(element); |
| 331 element.forEachLocalMember((ElementX member) { | 339 element.forEachLocalMember((ElementX member) { |
| 332 _removedElements.add(member); | 340 _removedElements.add(member); |
| 333 }); | 341 }); |
| 334 | 342 |
| 335 updates.add(new RemovedClassUpdate(compiler, element)); | 343 updates.add(new RemovedClassUpdate(compiler, element)); |
| 336 } | 344 } |
| 337 | 345 |
| 346 void removeFields( |
| 347 PartialFieldList definition, |
| 348 ScopeContainerElement container) { |
| 349 List<FieldElementX> fields = <FieldElementX>[]; |
| 350 container.forEachLocalMember((ElementX member) { |
| 351 if (member.declarationSite == definition) { |
| 352 fields.add(member); |
| 353 } |
| 354 }); |
| 355 for (FieldElementX field in fields) { |
| 356 // TODO(ahe): This only works when there's one field per |
| 357 // PartialFieldList. |
| 358 removeField(field); |
| 359 } |
| 360 } |
| 361 |
| 362 void removeField(FieldElementX element) { |
| 363 logVerbose("Removed field $element."); |
| 364 if (!element.isInstanceMember) { |
| 365 cannotReuse(element, "Not an instance field."); |
| 366 } else { |
| 367 removeInstanceField(element); |
| 368 } |
| 369 } |
| 370 |
| 371 void removeInstanceField(FieldElementX element) { |
| 372 PartialClassElement cls = element.enclosingClass; |
| 373 |
| 374 _classesWithSchemaChanges.add(cls); |
| 375 invalidateScopesAffectedBy(element, cls); |
| 376 |
| 377 _removedElements.add(element); |
| 378 |
| 379 updates.add(new RemovedFieldUpdate(compiler, element)); |
| 380 } |
| 381 |
| 338 void invalidateScopesAffectedBy( | 382 void invalidateScopesAffectedBy( |
| 339 ElementX element, | 383 ElementX element, |
| 340 /* ScopeContainerElement */ container) { | 384 /* ScopeContainerElement */ container) { |
| 341 for (ScopeContainerElement scope in scopesAffectedBy(element, container)) { | 385 for (ScopeContainerElement scope in scopesAffectedBy(element, container)) { |
| 342 scanSites(scope, (Element member, DeclarationSite site) { | 386 scanSites(scope, (Element member, DeclarationSite site) { |
| 343 // TODO(ahe): Cache qualifiedNamesIn to avoid quadratic behavior. | 387 // TODO(ahe): Cache qualifiedNamesIn to avoid quadratic behavior. |
| 344 Set<String> names = qualifiedNamesIn(site); | 388 Set<String> names = qualifiedNamesIn(site); |
| 345 if (canNamesResolveStaticallyTo(names, element, container)) { | 389 if (canNamesResolveStaticallyTo(names, element, container)) { |
| 346 _elementsToInvalidate.add(member); | 390 _elementsToInvalidate.add(member); |
| 347 } | 391 } |
| (...skipping 517 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 865 throw | 909 throw |
| 866 new StateError("captureState must be called before writeUpdateJsOn."); | 910 new StateError("captureState must be called before writeUpdateJsOn."); |
| 867 } | 911 } |
| 868 | 912 |
| 869 for (jsAst.Node access in accessToStatics) { | 913 for (jsAst.Node access in accessToStatics) { |
| 870 updates.add(js.statement('delete #', [access])); | 914 updates.add(js.statement('delete #', [access])); |
| 871 } | 915 } |
| 872 } | 916 } |
| 873 } | 917 } |
| 874 | 918 |
| 919 class RemovedFieldUpdate extends RemovalUpdate with JsFeatures { |
| 920 final FieldElementX element; |
| 921 |
| 922 bool wasStateCaptured; |
| 923 |
| 924 jsAst.Node elementAccess; |
| 925 |
| 926 String getterName; |
| 927 |
| 928 String setterName; |
| 929 |
| 930 RemovedFieldUpdate(Compiler compiler, this.element) |
| 931 : super(compiler); |
| 932 |
| 933 void captureState() { |
| 934 if (wasStateCaptured) throw "captureState was called twice."; |
| 935 wasStateCaptured = true; |
| 936 |
| 937 elementAccess = namer.elementAccess(element.enclosingClass); |
| 938 getterName = namer.getterName(element); |
| 939 setterName = namer.setterName(element); |
| 940 } |
| 941 |
| 942 FieldElementX apply() { |
| 943 if (!wasStateCaptured) { |
| 944 throw new StateError("captureState must be called before apply."); |
| 945 } |
| 946 |
| 947 removeFromEnclosing(); |
| 948 |
| 949 return element; |
| 950 } |
| 951 |
| 952 void writeUpdateJsOn(List<jsAst.Statement> updates) { |
| 953 if (!wasStateCaptured) { |
| 954 throw new StateError( |
| 955 "captureState must be called before writeUpdateJsOn."); |
| 956 } |
| 957 |
| 958 updates.add( |
| 959 js.statement('delete #.prototype.#', [elementAccess, getterName])); |
| 960 updates.add( |
| 961 js.statement('delete #.prototype.#', [elementAccess, setterName])); |
| 962 } |
| 963 } |
| 964 |
| 875 class AddedFunctionUpdate extends Update with JsFeatures { | 965 class AddedFunctionUpdate extends Update with JsFeatures { |
| 876 final PartialFunctionElement element; | 966 final PartialFunctionElement element; |
| 877 | 967 |
| 878 final /* ScopeContainerElement */ container; | 968 final /* ScopeContainerElement */ container; |
| 879 | 969 |
| 880 AddedFunctionUpdate(Compiler compiler, this.element, this.container) | 970 AddedFunctionUpdate(Compiler compiler, this.element, this.container) |
| 881 : super(compiler) { | 971 : super(compiler) { |
| 882 if (container == null) { | 972 if (container == null) { |
| 883 throw "container is null"; | 973 throw "container is null"; |
| 884 } | 974 } |
| (...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1068 | 1158 |
| 1069 ClassEmitter get classEmitter => backend.emitter.oldEmitter.classEmitter; | 1159 ClassEmitter get classEmitter => backend.emitter.oldEmitter.classEmitter; |
| 1070 | 1160 |
| 1071 List<String> computeFields(ClassElement cls) { | 1161 List<String> computeFields(ClassElement cls) { |
| 1072 // TODO(ahe): Rewrite for new emitter. | 1162 // TODO(ahe): Rewrite for new emitter. |
| 1073 ClassBuilder builder = new ClassBuilder(cls, namer); | 1163 ClassBuilder builder = new ClassBuilder(cls, namer); |
| 1074 classEmitter.emitFields(cls, builder, ""); | 1164 classEmitter.emitFields(cls, builder, ""); |
| 1075 return builder.fields; | 1165 return builder.fields; |
| 1076 } | 1166 } |
| 1077 } | 1167 } |
| OLD | NEW |