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 |