| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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.serialization_model_test; | 5 library dart2js.serialization_model_test; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:io'; | 8 import 'dart:io'; |
| 9 import 'package:async_helper/async_helper.dart'; | 9 import 'package:async_helper/async_helper.dart'; |
| 10 import 'package:expect/expect.dart'; | 10 import 'package:expect/expect.dart'; |
| (...skipping 20 matching lines...) Expand all Loading... |
| 31 /// Number of groups that the [TESTS] are split into. | 31 /// Number of groups that the [TESTS] are split into. |
| 32 int SPLIT_COUNT = 5; | 32 int SPLIT_COUNT = 5; |
| 33 | 33 |
| 34 main(List<String> args) { | 34 main(List<String> args) { |
| 35 asyncTest(() async { | 35 asyncTest(() async { |
| 36 Arguments arguments = new Arguments.from(args); | 36 Arguments arguments = new Arguments.from(args); |
| 37 SerializedData serializedData = | 37 SerializedData serializedData = |
| 38 await serializeDartCore(arguments: arguments); | 38 await serializeDartCore(arguments: arguments); |
| 39 if (arguments.filename != null) { | 39 if (arguments.filename != null) { |
| 40 Uri entryPoint = Uri.base.resolve(nativeToUriPath(arguments.filename)); | 40 Uri entryPoint = Uri.base.resolve(nativeToUriPath(arguments.filename)); |
| 41 SerializationResult result = await measure( | 41 SerializationResult result = |
| 42 '${entryPoint}', 'serialize', () { | 42 await measure('${entryPoint}', 'serialize', () { |
| 43 return serialize( | 43 return serialize(entryPoint, |
| 44 entryPoint, | |
| 45 memorySourceFiles: serializedData.toMemorySourceFiles(), | 44 memorySourceFiles: serializedData.toMemorySourceFiles(), |
| 46 resolutionInputs: serializedData.toUris(), | 45 resolutionInputs: serializedData.toUris(), |
| 47 dataUri: Uri.parse('memory:test.data')); | 46 dataUri: Uri.parse('memory:test.data')); |
| 48 }); | 47 }); |
| 49 await checkModels(entryPoint, | 48 await checkModels(entryPoint, |
| 50 sourceFiles: serializedData.toMemorySourceFiles( | 49 sourceFiles: serializedData |
| 51 result.serializedData.toMemorySourceFiles()), | 50 .toMemorySourceFiles(result.serializedData.toMemorySourceFiles()), |
| 52 resolutionInputs: serializedData.toUris( | 51 resolutionInputs: |
| 53 result.serializedData.toUris())); | 52 serializedData.toUris(result.serializedData.toUris())); |
| 54 } else { | 53 } else { |
| 55 Uri entryPoint = Uri.parse('memory:main.dart'); | 54 Uri entryPoint = Uri.parse('memory:main.dart'); |
| 56 await arguments.forEachTest(serializedData, TESTS, checkModels); | 55 await arguments.forEachTest(serializedData, TESTS, checkModels); |
| 57 } | 56 } |
| 58 printMeasurementResults(); | 57 printMeasurementResults(); |
| 59 }); | 58 }); |
| 60 } | 59 } |
| 61 | 60 |
| 62 Future checkModels( | 61 Future checkModels(Uri entryPoint, |
| 63 Uri entryPoint, | |
| 64 {Map<String, String> sourceFiles: const <String, String>{}, | 62 {Map<String, String> sourceFiles: const <String, String>{}, |
| 65 List<Uri> resolutionInputs, | 63 List<Uri> resolutionInputs, |
| 66 int index, | 64 int index, |
| 67 Test test, | 65 Test test, |
| 68 bool verbose: false}) async { | 66 bool verbose: false}) async { |
| 69 String testDescription = test != null ? test.name : '${entryPoint}'; | 67 String testDescription = test != null ? test.name : '${entryPoint}'; |
| 70 String id = index != null ? '$index: ' : ''; | 68 String id = index != null ? '$index: ' : ''; |
| 71 String title = '${id}${testDescription}'; | 69 String title = '${id}${testDescription}'; |
| 72 Compiler compilerNormal = await measure( | 70 Compiler compilerNormal = await measure(title, 'compile normal', () async { |
| 73 title, 'compile normal', () async { | |
| 74 Compiler compilerNormal = compilerFor( | 71 Compiler compilerNormal = compilerFor( |
| 75 memorySourceFiles: sourceFiles, | 72 memorySourceFiles: sourceFiles, options: [Flags.analyzeOnly]); |
| 76 options: [Flags.analyzeOnly]); | |
| 77 compilerNormal.resolution.retainCachesForTesting = true; | 73 compilerNormal.resolution.retainCachesForTesting = true; |
| 78 await compilerNormal.run(entryPoint); | 74 await compilerNormal.run(entryPoint); |
| 79 compilerNormal.phase = Compiler.PHASE_DONE_RESOLVING; | 75 compilerNormal.phase = Compiler.PHASE_DONE_RESOLVING; |
| 80 compilerNormal.world.populate(); | 76 compilerNormal.world.populate(); |
| 81 compilerNormal.backend.onResolutionComplete(); | 77 compilerNormal.backend.onResolutionComplete(); |
| 82 compilerNormal.deferredLoadTask.onResolutionComplete( | 78 compilerNormal.deferredLoadTask |
| 83 compilerNormal.mainFunction); | 79 .onResolutionComplete(compilerNormal.mainFunction); |
| 84 return compilerNormal; | 80 return compilerNormal; |
| 85 }); | 81 }); |
| 86 | 82 |
| 87 Compiler compilerDeserialized = await measure( | 83 Compiler compilerDeserialized = |
| 88 title, 'compile deserialized', () async { | 84 await measure(title, 'compile deserialized', () async { |
| 89 Compiler compilerDeserialized = compilerFor( | 85 Compiler compilerDeserialized = compilerFor( |
| 90 memorySourceFiles: sourceFiles, | 86 memorySourceFiles: sourceFiles, |
| 91 resolutionInputs: resolutionInputs, | 87 resolutionInputs: resolutionInputs, |
| 92 options: [Flags.analyzeOnly]); | 88 options: [Flags.analyzeOnly]); |
| 93 compilerDeserialized.resolution.retainCachesForTesting = true; | 89 compilerDeserialized.resolution.retainCachesForTesting = true; |
| 94 await compilerDeserialized.run(entryPoint); | 90 await compilerDeserialized.run(entryPoint); |
| 95 compilerDeserialized.phase = Compiler.PHASE_DONE_RESOLVING; | 91 compilerDeserialized.phase = Compiler.PHASE_DONE_RESOLVING; |
| 96 compilerDeserialized.world.populate(); | 92 compilerDeserialized.world.populate(); |
| 97 compilerDeserialized.backend.onResolutionComplete(); | 93 compilerDeserialized.backend.onResolutionComplete(); |
| 98 compilerDeserialized.deferredLoadTask.onResolutionComplete( | 94 compilerDeserialized.deferredLoadTask |
| 99 compilerDeserialized.mainFunction); | 95 .onResolutionComplete(compilerDeserialized.mainFunction); |
| 100 return compilerDeserialized; | 96 return compilerDeserialized; |
| 101 }); | 97 }); |
| 102 | 98 |
| 103 return measure(title, 'check models', () async { | 99 return measure(title, 'check models', () async { |
| 104 checkAllImpacts( | 100 checkAllImpacts(compilerNormal, compilerDeserialized, verbose: verbose); |
| 105 compilerNormal, compilerDeserialized, | |
| 106 verbose: verbose); | |
| 107 | 101 |
| 108 checkSets( | 102 checkSets( |
| 109 compilerNormal.resolverWorld.directlyInstantiatedClasses, | 103 compilerNormal.resolverWorld.directlyInstantiatedClasses, |
| 110 compilerDeserialized.resolverWorld.directlyInstantiatedClasses, | 104 compilerDeserialized.resolverWorld.directlyInstantiatedClasses, |
| 111 "Directly instantiated classes mismatch", | 105 "Directly instantiated classes mismatch", |
| 112 areElementsEquivalent, | 106 areElementsEquivalent, |
| 113 verbose: verbose); | 107 verbose: verbose); |
| 114 | 108 |
| 115 checkSets( | 109 checkSets( |
| 116 compilerNormal.resolverWorld.instantiatedTypes, | 110 compilerNormal.resolverWorld.instantiatedTypes, |
| 117 compilerDeserialized.resolverWorld.instantiatedTypes, | 111 compilerDeserialized.resolverWorld.instantiatedTypes, |
| 118 "Instantiated types mismatch", | 112 "Instantiated types mismatch", |
| 119 areTypesEquivalent, | 113 areTypesEquivalent, |
| 120 verbose: verbose); | 114 verbose: verbose); |
| 121 | 115 |
| 122 checkSets( | 116 checkSets( |
| 123 compilerNormal.resolverWorld.isChecks, | 117 compilerNormal.resolverWorld.isChecks, |
| 124 compilerDeserialized.resolverWorld.isChecks, | 118 compilerDeserialized.resolverWorld.isChecks, |
| 125 "Is-check mismatch", | 119 "Is-check mismatch", |
| 126 areTypesEquivalent, | 120 areTypesEquivalent, |
| 127 verbose: verbose); | 121 verbose: verbose); |
| 128 | 122 |
| 129 checkSets( | 123 checkSets( |
| 130 compilerNormal.enqueuer.resolution.processedElements, | 124 compilerNormal.enqueuer.resolution.processedElements, |
| 131 compilerDeserialized.enqueuer.resolution.processedElements, | 125 compilerDeserialized.enqueuer.resolution.processedElements, |
| 132 "Processed element mismatch", | 126 "Processed element mismatch", |
| 133 areElementsEquivalent, | 127 areElementsEquivalent, onSameElement: (a, b) { |
| 134 onSameElement: (a, b) { | 128 checkElements(compilerNormal, compilerDeserialized, a, b, |
| 135 checkElements( | 129 verbose: verbose); |
| 136 compilerNormal, compilerDeserialized, a, b, verbose: verbose); | 130 }, verbose: verbose); |
| 137 }, | |
| 138 verbose: verbose); | |
| 139 | 131 |
| 140 checkClassHierarchyNodes( | 132 checkClassHierarchyNodes( |
| 141 compilerNormal, | 133 compilerNormal, |
| 142 compilerDeserialized, | 134 compilerDeserialized, |
| 143 compilerNormal.world.getClassHierarchyNode( | 135 compilerNormal.world |
| 144 compilerNormal.coreClasses.objectClass), | 136 .getClassHierarchyNode(compilerNormal.coreClasses.objectClass), |
| 145 compilerDeserialized.world.getClassHierarchyNode( | 137 compilerDeserialized.world.getClassHierarchyNode( |
| 146 compilerDeserialized.coreClasses.objectClass), | 138 compilerDeserialized.coreClasses.objectClass), |
| 147 verbose: verbose); | 139 verbose: verbose); |
| 148 | 140 |
| 149 Expect.equals(compilerNormal.enabledInvokeOn, | 141 Expect.equals( |
| 142 compilerNormal.enabledInvokeOn, |
| 150 compilerDeserialized.enabledInvokeOn, | 143 compilerDeserialized.enabledInvokeOn, |
| 151 "Compiler.enabledInvokeOn mismatch"); | 144 "Compiler.enabledInvokeOn mismatch"); |
| 152 Expect.equals(compilerNormal.enabledFunctionApply, | 145 Expect.equals( |
| 146 compilerNormal.enabledFunctionApply, |
| 153 compilerDeserialized.enabledFunctionApply, | 147 compilerDeserialized.enabledFunctionApply, |
| 154 "Compiler.enabledFunctionApply mismatch"); | 148 "Compiler.enabledFunctionApply mismatch"); |
| 155 Expect.equals(compilerNormal.enabledRuntimeType, | 149 Expect.equals( |
| 150 compilerNormal.enabledRuntimeType, |
| 156 compilerDeserialized.enabledRuntimeType, | 151 compilerDeserialized.enabledRuntimeType, |
| 157 "Compiler.enabledRuntimeType mismatch"); | 152 "Compiler.enabledRuntimeType mismatch"); |
| 158 Expect.equals(compilerNormal.hasIsolateSupport, | 153 Expect.equals( |
| 154 compilerNormal.hasIsolateSupport, |
| 159 compilerDeserialized.hasIsolateSupport, | 155 compilerDeserialized.hasIsolateSupport, |
| 160 "Compiler.hasIsolateSupport mismatch"); | 156 "Compiler.hasIsolateSupport mismatch"); |
| 161 Expect.equals( | 157 Expect.equals( |
| 162 compilerNormal.deferredLoadTask.isProgramSplit, | 158 compilerNormal.deferredLoadTask.isProgramSplit, |
| 163 compilerDeserialized.deferredLoadTask.isProgramSplit, | 159 compilerDeserialized.deferredLoadTask.isProgramSplit, |
| 164 "isProgramSplit mismatch"); | 160 "isProgramSplit mismatch"); |
| 165 | 161 |
| 166 Map<ConstantValue, OutputUnit> constants1 = | 162 Map<ConstantValue, OutputUnit> constants1 = |
| 167 compilerNormal.deferredLoadTask.outputUnitForConstantsForTesting; | 163 compilerNormal.deferredLoadTask.outputUnitForConstantsForTesting; |
| 168 Map<ConstantValue, OutputUnit> constants2 = | 164 Map<ConstantValue, OutputUnit> constants2 = |
| 169 compilerDeserialized.deferredLoadTask.outputUnitForConstantsForTesting; | 165 compilerDeserialized.deferredLoadTask.outputUnitForConstantsForTesting; |
| 170 checkSets( | 166 checkSets( |
| 171 constants1.keys, | 167 constants1.keys, |
| 172 constants2.keys, | 168 constants2.keys, |
| 173 'deferredLoadTask._outputUnitForConstants.keys', | 169 'deferredLoadTask._outputUnitForConstants.keys', |
| 174 areConstantValuesEquivalent, | 170 areConstantValuesEquivalent, |
| 175 failOnUnfound: false, | 171 failOnUnfound: false, |
| 176 failOnExtra: false, | 172 failOnExtra: false, |
| 177 onSameElement: (ConstantValue value1, ConstantValue value2) { | 173 onSameElement: (ConstantValue value1, ConstantValue value2) { |
| 178 OutputUnit outputUnit1 = constants1[value1]; | 174 OutputUnit outputUnit1 = constants1[value1]; |
| 179 OutputUnit outputUnit2 = constants2[value2]; | 175 OutputUnit outputUnit2 = constants2[value2]; |
| 180 checkOutputUnits(outputUnit1, outputUnit2, | 176 checkOutputUnits( |
| 181 'for ${value1.toStructuredText()} ' | 177 outputUnit1, |
| 182 'vs ${value2.toStructuredText()}'); | 178 outputUnit2, |
| 183 }, | 179 'for ${value1.toStructuredText()} ' |
| 184 onUnfoundElement: (ConstantValue value1) { | 180 'vs ${value2.toStructuredText()}'); |
| 185 OutputUnit outputUnit1 = constants1[value1]; | 181 }, onUnfoundElement: (ConstantValue value1) { |
| 186 Expect.isTrue(outputUnit1.isMainOutput, | 182 OutputUnit outputUnit1 = constants1[value1]; |
| 187 "Missing deferred constant: ${value1.toStructuredText()}"); | 183 Expect.isTrue(outputUnit1.isMainOutput, |
| 188 }, | 184 "Missing deferred constant: ${value1.toStructuredText()}"); |
| 189 onExtraElement: (ConstantValue value2) { | 185 }, onExtraElement: (ConstantValue value2) { |
| 190 OutputUnit outputUnit2 = constants2[value2]; | 186 OutputUnit outputUnit2 = constants2[value2]; |
| 191 Expect.isTrue(outputUnit2.isMainOutput, | 187 Expect.isTrue(outputUnit2.isMainOutput, |
| 192 "Extra deferred constant: ${value2.toStructuredText()}"); | 188 "Extra deferred constant: ${value2.toStructuredText()}"); |
| 193 }, | 189 }, elementToString: (a) { |
| 194 elementToString: (a) { | 190 return '${a.toStructuredText()} -> ${constants1[a]}/${constants2[a]}'; |
| 195 return '${a.toStructuredText()} -> ${constants1[a]}/${constants2[a]}'; | 191 }); |
| 196 }); | |
| 197 }); | 192 }); |
| 198 } | 193 } |
| 199 | 194 |
| 200 void checkElements( | 195 void checkElements( |
| 201 Compiler compiler1, Compiler compiler2, | 196 Compiler compiler1, Compiler compiler2, Element element1, Element element2, |
| 202 Element element1, Element element2, | |
| 203 {bool verbose: false}) { | 197 {bool verbose: false}) { |
| 204 if (element1.isFunction || | 198 if (element1.isFunction || |
| 205 element1.isConstructor || | 199 element1.isConstructor || |
| 206 (element1.isField && element1.isInstanceMember)) { | 200 (element1.isField && element1.isInstanceMember)) { |
| 207 AstElement astElement1 = element1; | 201 AstElement astElement1 = element1; |
| 208 AstElement astElement2 = element2; | 202 AstElement astElement2 = element2; |
| 209 ClosureClassMap closureData1 = | 203 ClosureClassMap closureData1 = compiler1.closureToClassMapper |
| 210 compiler1.closureToClassMapper.computeClosureToClassMapping( | 204 .computeClosureToClassMapping(astElement1.resolvedAst); |
| 211 astElement1.resolvedAst); | 205 ClosureClassMap closureData2 = compiler2.closureToClassMapper |
| 212 ClosureClassMap closureData2 = | 206 .computeClosureToClassMapping(astElement2.resolvedAst); |
| 213 compiler2.closureToClassMapper.computeClosureToClassMapping( | |
| 214 astElement2.resolvedAst); | |
| 215 | 207 |
| 216 checkElementIdentities(closureData1, closureData2, | 208 checkElementIdentities( |
| 209 closureData1, |
| 210 closureData2, |
| 217 '$element1.closureElement', | 211 '$element1.closureElement', |
| 218 closureData1.closureElement, closureData2.closureElement); | 212 closureData1.closureElement, |
| 219 checkElementIdentities(closureData1, closureData2, | 213 closureData2.closureElement); |
| 214 checkElementIdentities( |
| 215 closureData1, |
| 216 closureData2, |
| 220 '$element1.closureClassElement', | 217 '$element1.closureClassElement', |
| 221 closureData1.closureClassElement, closureData2.closureClassElement); | 218 closureData1.closureClassElement, |
| 222 checkElementIdentities(closureData1, closureData2, | 219 closureData2.closureClassElement); |
| 223 '$element1.callElement', | 220 checkElementIdentities(closureData1, closureData2, '$element1.callElement', |
| 224 closureData1.callElement, closureData2.callElement); | 221 closureData1.callElement, closureData2.callElement); |
| 225 check(closureData1, closureData2, | 222 check(closureData1, closureData2, '$element1.thisLocal', |
| 226 '$element1.thisLocal', | 223 closureData1.thisLocal, closureData2.thisLocal, areLocalsEquivalent); |
| 227 closureData1.thisLocal, closureData2.thisLocal, | |
| 228 areLocalsEquivalent); | |
| 229 checkMaps( | 224 checkMaps( |
| 230 closureData1.freeVariableMap, | 225 closureData1.freeVariableMap, |
| 231 closureData2.freeVariableMap, | 226 closureData2.freeVariableMap, |
| 232 "$element1.freeVariableMap", | 227 "$element1.freeVariableMap", |
| 233 areLocalsEquivalent, | 228 areLocalsEquivalent, |
| 234 areCapturedVariablesEquivalent, | 229 areCapturedVariablesEquivalent, |
| 235 verbose: verbose); | 230 verbose: verbose); |
| 236 checkMaps( | 231 checkMaps( |
| 237 closureData1.capturingScopes, | 232 closureData1.capturingScopes, |
| 238 closureData2.capturingScopes, | 233 closureData2.capturingScopes, |
| 239 "$element1.capturingScopes", | 234 "$element1.capturingScopes", |
| 240 areNodesEquivalent, | 235 areNodesEquivalent, |
| 241 areClosureScopesEquivalent, | 236 areClosureScopesEquivalent, |
| 242 verbose: verbose, | 237 verbose: verbose, |
| 243 keyToString: nodeToString); | 238 keyToString: nodeToString); |
| 244 checkSets( | 239 checkSets( |
| 245 closureData1.variablesUsedInTryOrGenerator, | 240 closureData1.variablesUsedInTryOrGenerator, |
| 246 closureData2.variablesUsedInTryOrGenerator, | 241 closureData2.variablesUsedInTryOrGenerator, |
| 247 "$element1.variablesUsedInTryOrGenerator", | 242 "$element1.variablesUsedInTryOrGenerator", |
| 248 areLocalsEquivalent, | 243 areLocalsEquivalent, |
| 249 verbose: verbose); | 244 verbose: verbose); |
| 250 if (element1 is MemberElement && element2 is MemberElement) { | 245 if (element1 is MemberElement && element2 is MemberElement) { |
| 251 MemberElement member1 = element1.implementation; | 246 MemberElement member1 = element1.implementation; |
| 252 MemberElement member2 = element2.implementation; | 247 MemberElement member2 = element2.implementation; |
| 253 checkSets( | 248 checkSets(member1.nestedClosures, member2.nestedClosures, |
| 254 member1.nestedClosures, | 249 "$member1.nestedClosures", areElementsEquivalent, verbose: verbose, |
| 255 member2.nestedClosures, | |
| 256 "$member1.nestedClosures", | |
| 257 areElementsEquivalent, | |
| 258 verbose: verbose, | |
| 259 onSameElement: (a, b) { | 250 onSameElement: (a, b) { |
| 260 LocalFunctionElement localFunction1 = a.expression; | 251 LocalFunctionElement localFunction1 = a.expression; |
| 261 LocalFunctionElement localFunction2 = b.expression; | 252 LocalFunctionElement localFunction2 = b.expression; |
| 262 checkElementIdentities( | 253 checkElementIdentities(localFunction1, localFunction2, 'enclosingClass', |
| 263 localFunction1, localFunction2, | 254 localFunction1.enclosingClass, localFunction2.enclosingClass); |
| 264 'enclosingClass', | 255 testResolvedAstEquivalence(localFunction1.resolvedAst, |
| 265 localFunction1.enclosingClass, localFunction2.enclosingClass); | 256 localFunction2.resolvedAst, const CheckStrategy()); |
| 266 testResolvedAstEquivalence( | 257 }); |
| 267 localFunction1.resolvedAst, | |
| 268 localFunction2.resolvedAst, | |
| 269 const CheckStrategy()); | |
| 270 }); | |
| 271 } | 258 } |
| 272 } | 259 } |
| 273 JavaScriptBackend backend1 = compiler1.backend; | 260 JavaScriptBackend backend1 = compiler1.backend; |
| 274 JavaScriptBackend backend2 = compiler2.backend; | 261 JavaScriptBackend backend2 = compiler2.backend; |
| 275 Expect.equals( | 262 Expect.equals( |
| 276 backend1.inlineCache.getCurrentCacheDecisionForTesting(element1), | 263 backend1.inlineCache.getCurrentCacheDecisionForTesting(element1), |
| 277 backend2.inlineCache.getCurrentCacheDecisionForTesting(element2), | 264 backend2.inlineCache.getCurrentCacheDecisionForTesting(element2), |
| 278 "Inline cache decision mismatch for $element1 vs $element2"); | 265 "Inline cache decision mismatch for $element1 vs $element2"); |
| 279 | 266 |
| 280 checkElementOutputUnits(compiler1, compiler2, element1, element2); | 267 checkElementOutputUnits(compiler1, compiler2, element1, element2); |
| 281 } | 268 } |
| 282 | 269 |
| 283 void checkMixinUses( | 270 void checkMixinUses(Compiler compiler1, Compiler compiler2, ClassElement class1, |
| 284 Compiler compiler1, Compiler compiler2, | 271 ClassElement class2, |
| 285 ClassElement class1, ClassElement class2, | |
| 286 {bool verbose: false}) { | 272 {bool verbose: false}) { |
| 287 | |
| 288 checkSets( | 273 checkSets( |
| 289 compiler1.world.mixinUsesOf(class1), | 274 compiler1.world.mixinUsesOf(class1), |
| 290 compiler2.world.mixinUsesOf(class2), | 275 compiler2.world.mixinUsesOf(class2), |
| 291 "Mixin uses of $class1 vs $class2", | 276 "Mixin uses of $class1 vs $class2", |
| 292 areElementsEquivalent, | 277 areElementsEquivalent, |
| 293 verbose: verbose); | 278 verbose: verbose); |
| 294 | |
| 295 } | 279 } |
| 296 | 280 |
| 297 void checkClassHierarchyNodes( | 281 void checkClassHierarchyNodes(Compiler compiler1, Compiler compiler2, |
| 298 Compiler compiler1, | |
| 299 Compiler compiler2, | |
| 300 ClassHierarchyNode node1, ClassHierarchyNode node2, | 282 ClassHierarchyNode node1, ClassHierarchyNode node2, |
| 301 {bool verbose: false}) { | 283 {bool verbose: false}) { |
| 302 if (verbose) { | 284 if (verbose) { |
| 303 print('Checking $node1 vs $node2'); | 285 print('Checking $node1 vs $node2'); |
| 304 } | 286 } |
| 305 Expect.isTrue( | 287 Expect.isTrue(areElementsEquivalent(node1.cls, node2.cls), |
| 306 areElementsEquivalent(node1.cls, node2.cls), | |
| 307 "Element identity mismatch for ${node1.cls} vs ${node2.cls}."); | 288 "Element identity mismatch for ${node1.cls} vs ${node2.cls}."); |
| 308 Expect.equals( | 289 Expect.equals( |
| 309 node1.isDirectlyInstantiated, | 290 node1.isDirectlyInstantiated, |
| 310 node2.isDirectlyInstantiated, | 291 node2.isDirectlyInstantiated, |
| 311 "Value mismatch for 'isDirectlyInstantiated' " | 292 "Value mismatch for 'isDirectlyInstantiated' " |
| 312 "for ${node1.cls} vs ${node2.cls}."); | 293 "for ${node1.cls} vs ${node2.cls}."); |
| 313 Expect.equals( | 294 Expect.equals( |
| 314 node1.isIndirectlyInstantiated, | 295 node1.isIndirectlyInstantiated, |
| 315 node2.isIndirectlyInstantiated, | 296 node2.isIndirectlyInstantiated, |
| 316 "Value mismatch for 'isIndirectlyInstantiated' " | 297 "Value mismatch for 'isIndirectlyInstantiated' " |
| 317 "for ${node1.cls} vs ${node2.cls}."); | 298 "for ${node1.cls} vs ${node2.cls}."); |
| 318 // TODO(johnniwinther): Enforce a canonical and stable order on direct | 299 // TODO(johnniwinther): Enforce a canonical and stable order on direct |
| 319 // subclasses. | 300 // subclasses. |
| 320 for (ClassHierarchyNode child in node1.directSubclasses) { | 301 for (ClassHierarchyNode child in node1.directSubclasses) { |
| 321 bool found = false; | 302 bool found = false; |
| 322 for (ClassHierarchyNode other in node2.directSubclasses) { | 303 for (ClassHierarchyNode other in node2.directSubclasses) { |
| 323 if (areElementsEquivalent(child.cls, other.cls)) { | 304 if (areElementsEquivalent(child.cls, other.cls)) { |
| 324 checkClassHierarchyNodes(compiler1, compiler2, | 305 checkClassHierarchyNodes(compiler1, compiler2, child, other, |
| 325 child, other, verbose: verbose); | 306 verbose: verbose); |
| 326 found = true; | 307 found = true; |
| 327 break; | 308 break; |
| 328 } | 309 } |
| 329 } | 310 } |
| 330 if (!found) { | 311 if (!found) { |
| 331 if (child.isInstantiated) { | 312 if (child.isInstantiated) { |
| 332 print('Missing subclass ${child.cls} of ${node1.cls} ' | 313 print('Missing subclass ${child.cls} of ${node1.cls} ' |
| 333 'in ${node2.directSubclasses}'); | 314 'in ${node2.directSubclasses}'); |
| 334 print(compiler1.world.dump( | 315 print(compiler1.world |
| 335 verbose ? compiler1.coreClasses.objectClass : node1.cls)); | 316 .dump(verbose ? compiler1.coreClasses.objectClass : node1.cls)); |
| 336 print(compiler2.world.dump( | 317 print(compiler2.world |
| 337 verbose ? compiler2.coreClasses.objectClass : node2.cls)); | 318 .dump(verbose ? compiler2.coreClasses.objectClass : node2.cls)); |
| 338 } | 319 } |
| 339 Expect.isFalse(child.isInstantiated, | 320 Expect.isFalse( |
| 321 child.isInstantiated, |
| 340 'Missing subclass ${child.cls} of ${node1.cls} in ' | 322 'Missing subclass ${child.cls} of ${node1.cls} in ' |
| 341 '${node2.directSubclasses}'); | 323 '${node2.directSubclasses}'); |
| 342 } | 324 } |
| 343 } | 325 } |
| 344 checkMixinUses(compiler1, compiler2, node1.cls, node2.cls, verbose: verbose); | 326 checkMixinUses(compiler1, compiler2, node1.cls, node2.cls, verbose: verbose); |
| 345 } | 327 } |
| 346 | 328 |
| 347 bool areLocalsEquivalent(Local a, Local b) { | 329 bool areLocalsEquivalent(Local a, Local b) { |
| 348 if (a == b) return true; | 330 if (a == b) return true; |
| 349 if (a == null || b == null) return false; | 331 if (a == null || b == null) return false; |
| 350 | 332 |
| 351 if (a is Element) { | 333 if (a is Element) { |
| 352 return b is Element && areElementsEquivalent(a as Element, b as Element); | 334 return b is Element && areElementsEquivalent(a as Element, b as Element); |
| 353 } else { | 335 } else { |
| 354 return a.runtimeType == b.runtimeType && | 336 return a.runtimeType == b.runtimeType && |
| 355 areElementsEquivalent(a.executableContext, b.executableContext); | 337 areElementsEquivalent(a.executableContext, b.executableContext); |
| 356 } | 338 } |
| 357 } | 339 } |
| 358 | 340 |
| 359 bool areCapturedVariablesEquivalent(CapturedVariable a, CapturedVariable b) { | 341 bool areCapturedVariablesEquivalent(CapturedVariable a, CapturedVariable b) { |
| 360 if (a == b) return true; | 342 if (a == b) return true; |
| 361 if (a == null || b == null) return false; | 343 if (a == null || b == null) return false; |
| 362 if (a is ClosureFieldElement && b is ClosureFieldElement) { | 344 if (a is ClosureFieldElement && b is ClosureFieldElement) { |
| 363 return areElementsEquivalent(a.closureClass, b.closureClass) && | 345 return areElementsEquivalent(a.closureClass, b.closureClass) && |
| 364 areLocalsEquivalent(a.local, b.local); | 346 areLocalsEquivalent(a.local, b.local); |
| 365 } else if (a is BoxFieldElement && b is BoxFieldElement) { | 347 } else if (a is BoxFieldElement && b is BoxFieldElement) { |
| 366 return areElementsEquivalent(a.variableElement, b.variableElement) && | 348 return areElementsEquivalent(a.variableElement, b.variableElement) && |
| 367 areLocalsEquivalent(a.box, b.box); | 349 areLocalsEquivalent(a.box, b.box); |
| 368 } | 350 } |
| 369 return false; | 351 return false; |
| 370 } | 352 } |
| 371 | 353 |
| 372 bool areClosureScopesEquivalent(ClosureScope a, ClosureScope b) { | 354 bool areClosureScopesEquivalent(ClosureScope a, ClosureScope b) { |
| 373 if (a == b) return true; | 355 if (a == b) return true; |
| 374 if (a == null || b == null) return false; | 356 if (a == null || b == null) return false; |
| 375 if (!areLocalsEquivalent(a.boxElement, b.boxElement)) { | 357 if (!areLocalsEquivalent(a.boxElement, b.boxElement)) { |
| 376 return false; | 358 return false; |
| 377 } | 359 } |
| 378 checkMaps(a.capturedVariables, b.capturedVariables, | 360 checkMaps( |
| 361 a.capturedVariables, |
| 362 b.capturedVariables, |
| 379 'ClosureScope.capturedVariables', | 363 'ClosureScope.capturedVariables', |
| 380 areLocalsEquivalent, | 364 areLocalsEquivalent, |
| 381 areElementsEquivalent); | 365 areElementsEquivalent); |
| 382 checkSets(a.boxedLoopVariables, b.boxedLoopVariables, | 366 checkSets(a.boxedLoopVariables, b.boxedLoopVariables, |
| 383 'ClosureScope.boxedLoopVariables', | 367 'ClosureScope.boxedLoopVariables', areElementsEquivalent); |
| 384 areElementsEquivalent); | |
| 385 return true; | 368 return true; |
| 386 } | 369 } |
| 387 | 370 |
| 388 String nodeToString(Node node) { | 371 String nodeToString(Node node) { |
| 389 String text = '$node'; | 372 String text = '$node'; |
| 390 if (text.length > 40) { | 373 if (text.length > 40) { |
| 391 return '(${node.runtimeType}) ${text.substring(0, 37)}...'; | 374 return '(${node.runtimeType}) ${text.substring(0, 37)}...'; |
| 392 } | 375 } |
| 393 return '(${node.runtimeType}) $text'; | 376 return '(${node.runtimeType}) $text'; |
| 394 } | 377 } |
| 395 | 378 |
| 396 void checkElementOutputUnits( | 379 void checkElementOutputUnits(Compiler compiler1, Compiler compiler2, |
| 397 Compiler compiler1, Compiler compiler2, | |
| 398 Element element1, Element element2) { | 380 Element element1, Element element2) { |
| 399 OutputUnit outputUnit1 = | 381 OutputUnit outputUnit1 = |
| 400 compiler1.deferredLoadTask.getOutputUnitForElementForTesting(element1); | 382 compiler1.deferredLoadTask.getOutputUnitForElementForTesting(element1); |
| 401 OutputUnit outputUnit2 = | 383 OutputUnit outputUnit2 = |
| 402 compiler2.deferredLoadTask.getOutputUnitForElementForTesting(element2); | 384 compiler2.deferredLoadTask.getOutputUnitForElementForTesting(element2); |
| 403 checkOutputUnits(outputUnit1, outputUnit2, 'for $element1 vs $element2'); | 385 checkOutputUnits(outputUnit1, outputUnit2, 'for $element1 vs $element2'); |
| 404 } | 386 } |
| 405 | 387 |
| 406 void checkOutputUnits( | 388 void checkOutputUnits( |
| 407 OutputUnit outputUnit1, OutputUnit outputUnit2, String message) { | 389 OutputUnit outputUnit1, OutputUnit outputUnit2, String message) { |
| 408 if (outputUnit1 == null && outputUnit2 == null) return; | 390 if (outputUnit1 == null && outputUnit2 == null) return; |
| 409 check(outputUnit1, outputUnit2, | 391 check(outputUnit1, outputUnit2, 'OutputUnit.isMainOutput $message', |
| 410 'OutputUnit.isMainOutput $message', | |
| 411 outputUnit1.isMainOutput, outputUnit2.isMainOutput); | 392 outputUnit1.isMainOutput, outputUnit2.isMainOutput); |
| 412 checkSetEquivalence(outputUnit1, outputUnit2, | 393 checkSetEquivalence( |
| 394 outputUnit1, |
| 395 outputUnit2, |
| 413 'OutputUnit.imports $message', | 396 'OutputUnit.imports $message', |
| 414 outputUnit1.imports, outputUnit2.imports, | 397 outputUnit1.imports, |
| 398 outputUnit2.imports, |
| 415 (a, b) => areElementsEquivalent(a.declaration, b.declaration)); | 399 (a, b) => areElementsEquivalent(a.declaration, b.declaration)); |
| 416 } | 400 } |
| OLD | NEW |