Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(640)

Side by Side Diff: tests/compiler/dart2js/equivalence/check_functions.dart

Issue 2879593004: Reorganize equivalence test helpers (Closed)
Patch Set: Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
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.
4
5 /// Equivalence test functions for data objects.
6
7 library dart2js.equivalence.functions;
8
9 import 'package:expect/expect.dart';
10 import 'package:compiler/src/common/resolution.dart';
11 import 'package:compiler/src/common_elements.dart';
12 import 'package:compiler/src/compiler.dart';
13 import 'package:compiler/src/elements/types.dart';
14 import 'package:compiler/src/elements/elements.dart';
15 import 'package:compiler/src/elements/entities.dart';
16 import 'package:compiler/src/enqueue.dart';
17 import 'package:compiler/src/js_backend/backend_usage.dart';
18 import 'package:compiler/src/js_backend/native_data.dart';
19 import 'package:compiler/src/js_backend/interceptor_data.dart';
20 import 'package:compiler/src/serialization/equivalence.dart';
21 import 'package:compiler/src/universe/class_set.dart';
22 import 'package:compiler/src/universe/world_builder.dart';
23 import 'package:compiler/src/world.dart';
24 import 'check_helpers.dart';
25
26 void checkClosedWorlds(ClosedWorld closedWorld1, ClosedWorld closedWorld2,
27 {TestStrategy strategy: const TestStrategy(),
28 bool allowExtra: false,
29 bool verbose: false}) {
30 if (verbose) {
31 print(closedWorld1.dump());
32 print(closedWorld2.dump());
33 }
34 checkClassHierarchyNodes(
35 closedWorld1,
36 closedWorld2,
37 closedWorld1
38 .getClassHierarchyNode(closedWorld1.commonElements.objectClass),
39 closedWorld2
40 .getClassHierarchyNode(closedWorld2.commonElements.objectClass),
41 strategy.elementEquivalence,
42 verbose: verbose);
43
44 checkNativeData(closedWorld1.nativeData, closedWorld2.nativeData,
45 strategy: strategy, allowExtra: allowExtra, verbose: verbose);
46 checkInterceptorData(closedWorld1.interceptorData,
47 closedWorld2.interceptorData, strategy.elementEquivalence,
48 verbose: verbose);
49 }
50
51 void checkNativeData(NativeDataImpl data1, NativeDataImpl data2,
52 {TestStrategy strategy: const TestStrategy(),
53 bool allowExtra: false,
54 bool verbose: false}) {
55 checkMapEquivalence(data1, data2, 'nativeMemberName', data1.nativeMemberName,
56 data2.nativeMemberName, strategy.elementEquivalence, equality,
57 allowExtra: allowExtra);
58
59 checkMapEquivalence(
60 data1,
61 data2,
62 'nativeMethodBehavior',
63 data1.nativeMethodBehavior,
64 data2.nativeMethodBehavior,
65 strategy.elementEquivalence,
66 (a, b) => testNativeBehavior(a, b, strategy: strategy),
67 allowExtra: allowExtra);
68
69 checkMapEquivalence(
70 data1,
71 data2,
72 'nativeFieldLoadBehavior',
73 data1.nativeFieldLoadBehavior,
74 data2.nativeFieldLoadBehavior,
75 strategy.elementEquivalence,
76 (a, b) => testNativeBehavior(a, b, strategy: strategy),
77 allowExtra: allowExtra);
78
79 checkMapEquivalence(
80 data1,
81 data2,
82 'nativeFieldStoreBehavior',
83 data1.nativeFieldStoreBehavior,
84 data2.nativeFieldStoreBehavior,
85 strategy.elementEquivalence,
86 (a, b) => testNativeBehavior(a, b, strategy: strategy),
87 allowExtra: allowExtra);
88
89 checkMapEquivalence(
90 data1,
91 data2,
92 'jsInteropLibraryNames',
93 data1.jsInteropLibraryNames,
94 data2.jsInteropLibraryNames,
95 strategy.elementEquivalence,
96 equality);
97
98 checkSetEquivalence(
99 data1,
100 data2,
101 'anonymousJsInteropClasses',
102 data1.anonymousJsInteropClasses,
103 data2.anonymousJsInteropClasses,
104 strategy.elementEquivalence);
105
106 checkMapEquivalence(
107 data1,
108 data2,
109 'jsInteropClassNames',
110 data1.jsInteropClassNames,
111 data2.jsInteropClassNames,
112 strategy.elementEquivalence,
113 equality);
114
115 checkMapEquivalence(
116 data1,
117 data2,
118 'jsInteropMemberNames',
119 data1.jsInteropMemberNames,
120 data2.jsInteropMemberNames,
121 strategy.elementEquivalence,
122 equality);
123 }
124
125 void checkInterceptorData(InterceptorDataImpl data1, InterceptorDataImpl data2,
126 bool elementEquivalence(Entity a, Entity b),
127 {bool verbose: false}) {
128 checkMapEquivalence(
129 data1,
130 data2,
131 'interceptedElements',
132 data1.interceptedElementsForTesting,
133 data2.interceptedElementsForTesting,
134 equality,
135 (a, b) => areSetsEquivalent(a, b, elementEquivalence));
136
137 checkSetEquivalence(data1, data2, 'interceptedClasses',
138 data1.interceptedClasses, data2.interceptedClasses, elementEquivalence);
139
140 checkSetEquivalence(
141 data1,
142 data2,
143 'classesMixedIntoInterceptedClasses',
144 data1.classesMixedIntoInterceptedClassesForTesting,
145 data2.classesMixedIntoInterceptedClassesForTesting,
146 elementEquivalence);
147 }
148
149 void checkClassHierarchyNodes(
150 ClosedWorld closedWorld1,
151 ClosedWorld closedWorld2,
152 ClassHierarchyNode node1,
153 ClassHierarchyNode node2,
154 bool elementEquivalence(Entity a, Entity b),
155 {bool verbose: false}) {
156 if (verbose) {
157 print('Checking $node1 vs $node2');
158 }
159 ClassEntity cls1 = node1.cls;
160 ClassEntity cls2 = node2.cls;
161 Expect.isTrue(elementEquivalence(cls1, cls2),
162 "Element identity mismatch for ${cls1} vs ${cls2}.");
163 Expect.equals(
164 node1.isDirectlyInstantiated,
165 node2.isDirectlyInstantiated,
166 "Value mismatch for 'isDirectlyInstantiated' "
167 "for ${cls1} vs ${cls2}.");
168 Expect.equals(
169 node1.isIndirectlyInstantiated,
170 node2.isIndirectlyInstantiated,
171 "Value mismatch for 'isIndirectlyInstantiated' "
172 "for ${node1.cls} vs ${node2.cls}.");
173 // TODO(johnniwinther): Enforce a canonical and stable order on direct
174 // subclasses.
175 for (ClassHierarchyNode child in node1.directSubclasses) {
176 bool found = false;
177 for (ClassHierarchyNode other in node2.directSubclasses) {
178 ClassEntity child1 = child.cls;
179 ClassEntity child2 = other.cls;
180 if (elementEquivalence(child1, child2)) {
181 checkClassHierarchyNodes(
182 closedWorld1, closedWorld2, child, other, elementEquivalence,
183 verbose: verbose);
184 found = true;
185 break;
186 }
187 }
188 if (!found) {
189 if (child.isInstantiated) {
190 print('Missing subclass ${child.cls} of ${node1.cls} '
191 'in ${node2.directSubclasses}');
192 print(closedWorld1.dump(
193 verbose ? closedWorld1.commonElements.objectClass : node1.cls));
194 print(closedWorld2.dump(
195 verbose ? closedWorld2.commonElements.objectClass : node2.cls));
196 }
197 Expect.isFalse(
198 child.isInstantiated,
199 'Missing subclass ${child.cls} of ${node1.cls} in '
200 '${node2.directSubclasses}');
201 }
202 }
203 checkMixinUses(
204 closedWorld1, closedWorld2, node1.cls, node2.cls, elementEquivalence,
205 verbose: verbose);
206 }
207
208 void checkMixinUses(
209 ClosedWorld closedWorld1,
210 ClosedWorld closedWorld2,
211 ClassEntity class1,
212 ClassEntity class2,
213 bool elementEquivalence(Entity a, Entity b),
214 {bool verbose: false}) {
215 checkSets(closedWorld1.mixinUsesOf(class1), closedWorld2.mixinUsesOf(class2),
216 "Mixin uses of $class1 vs $class2", elementEquivalence,
217 verbose: verbose);
218 }
219
220 /// Check member property equivalence between all members common to [compiler1]
221 /// and [compiler2].
222 void checkLoadedLibraryMembers(
223 Compiler compiler1,
224 Compiler compiler2,
225 bool hasProperty(Element member1),
226 void checkMemberProperties(Compiler compiler1, Element member1,
227 Compiler compiler2, Element member2,
228 {bool verbose}),
229 {bool verbose: false}) {
230 void checkMembers(Element member1, Element member2) {
231 if (member1.isClass && member2.isClass) {
232 ClassElement class1 = member1;
233 ClassElement class2 = member2;
234 if (!class1.isResolved) return;
235
236 if (hasProperty(member1)) {
237 if (areElementsEquivalent(member1, member2)) {
238 checkMemberProperties(compiler1, member1, compiler2, member2,
239 verbose: verbose);
240 }
241 }
242
243 class1.forEachLocalMember((m1) {
244 checkMembers(m1, class2.localLookup(m1.name));
245 });
246 ClassElement superclass1 = class1.superclass;
247 ClassElement superclass2 = class2.superclass;
248 while (superclass1 != null && superclass1.isUnnamedMixinApplication) {
249 for (ConstructorElement c1 in superclass1.constructors) {
250 checkMembers(c1, superclass2.lookupConstructor(c1.name));
251 }
252 superclass1 = superclass1.superclass;
253 superclass2 = superclass2.superclass;
254 }
255 return;
256 }
257
258 if (!hasProperty(member1)) {
259 return;
260 }
261
262 if (member2 == null) {
263 throw 'Missing member for ${member1}';
264 }
265
266 if (areElementsEquivalent(member1, member2)) {
267 checkMemberProperties(compiler1, member1, compiler2, member2,
268 verbose: verbose);
269 }
270 }
271
272 for (LibraryElement library1 in compiler1.libraryLoader.libraries) {
273 LibraryElement library2 =
274 compiler2.libraryLoader.lookupLibrary(library1.canonicalUri);
275 if (library2 != null) {
276 library1.forEachLocalMember((Element member1) {
277 checkMembers(member1, library2.localLookup(member1.name));
278 });
279 }
280 }
281 }
282
283 /// Check equivalence of all resolution impacts.
284 void checkAllImpacts(Compiler compiler1, Compiler compiler2,
285 {bool verbose: false}) {
286 checkLoadedLibraryMembers(compiler1, compiler2, (Element member1) {
287 return compiler1.resolution.hasResolutionImpact(member1);
288 }, checkImpacts, verbose: verbose);
289 }
290
291 /// Check equivalence of resolution impact for [member1] and [member2].
292 void checkImpacts(
293 Compiler compiler1, Element member1, Compiler compiler2, Element member2,
294 {bool verbose: false}) {
295 ResolutionImpact impact1 = compiler1.resolution.getResolutionImpact(member1);
296 ResolutionImpact impact2 = compiler2.resolution.getResolutionImpact(member2);
297
298 if (impact1 == null && impact2 == null) return;
299
300 if (verbose) {
301 print('Checking impacts for $member1 vs $member2');
302 }
303
304 if (impact1 == null) {
305 throw 'Missing impact for $member1. $member2 has $impact2';
306 }
307 if (impact2 == null) {
308 throw 'Missing impact for $member2. $member1 has $impact1';
309 }
310
311 testResolutionImpactEquivalence(impact1, impact2,
312 strategy: const CheckStrategy());
313 }
314
315 void checkAllResolvedAsts(Compiler compiler1, Compiler compiler2,
316 {bool verbose: false}) {
317 checkLoadedLibraryMembers(compiler1, compiler2, (Element member1) {
318 return member1 is ExecutableElement &&
319 compiler1.resolution.hasResolvedAst(member1);
320 }, checkResolvedAsts, verbose: verbose);
321 }
322
323 /// Check equivalence of [impact1] and [impact2].
324 void checkResolvedAsts(
325 Compiler compiler1, Element member1, Compiler compiler2, Element member2,
326 {bool verbose: false}) {
327 if (!compiler2.serialization.isDeserialized(member2)) {
328 return;
329 }
330 ResolvedAst resolvedAst1 = compiler1.resolution.getResolvedAst(member1);
331 ResolvedAst resolvedAst2 = compiler2.serialization.getResolvedAst(member2);
332
333 if (resolvedAst1 == null || resolvedAst2 == null) return;
334
335 if (verbose) {
336 print('Checking resolved asts for $member1 vs $member2');
337 }
338
339 testResolvedAstEquivalence(resolvedAst1, resolvedAst2, const CheckStrategy());
340 }
341
342 void checkNativeClasses(
343 Compiler compiler1, Compiler compiler2, TestStrategy strategy) {
344 Iterable<ClassEntity> nativeClasses1 = compiler1
345 .backend.nativeResolutionEnqueuerForTesting.nativeClassesForTesting;
346 Iterable<ClassEntity> nativeClasses2 = compiler2
347 .backend.nativeResolutionEnqueuerForTesting.nativeClassesForTesting;
348
349 checkSetEquivalence(compiler1, compiler2, 'nativeClasses', nativeClasses1,
350 nativeClasses2, strategy.elementEquivalence);
351
352 Iterable<ClassEntity> registeredClasses1 = compiler1
353 .backend.nativeResolutionEnqueuerForTesting.registeredClassesForTesting;
354 Iterable<ClassEntity> registeredClasses2 = compiler2
355 .backend.nativeResolutionEnqueuerForTesting.registeredClassesForTesting;
356
357 checkSetEquivalence(compiler1, compiler2, 'registeredClasses',
358 registeredClasses1, registeredClasses2, strategy.elementEquivalence);
359 }
360
361 void checkNativeBasicData(NativeBasicDataImpl data1, NativeBasicDataImpl data2,
362 TestStrategy strategy) {
363 checkMapEquivalence(
364 data1,
365 data2,
366 'nativeClassTagInfo',
367 data1.nativeClassTagInfo,
368 data2.nativeClassTagInfo,
369 strategy.elementEquivalence,
370 (a, b) => a == b);
371 // TODO(johnniwinther): Check the remaining properties.
372 }
373
374 void checkBackendUsage(
375 BackendUsageImpl usage1, BackendUsageImpl usage2, TestStrategy strategy) {
376 checkSetEquivalence(
377 usage1,
378 usage2,
379 'globalClassDependencies',
380 usage1.globalClassDependencies,
381 usage2.globalClassDependencies,
382 strategy.elementEquivalence);
383 checkSetEquivalence(
384 usage1,
385 usage2,
386 'globalFunctionDependencies',
387 usage1.globalFunctionDependencies,
388 usage2.globalFunctionDependencies,
389 strategy.elementEquivalence);
390 checkSetEquivalence(
391 usage1,
392 usage2,
393 'helperClassesUsed',
394 usage1.helperClassesUsed,
395 usage2.helperClassesUsed,
396 strategy.elementEquivalence);
397 checkSetEquivalence(
398 usage1,
399 usage2,
400 'helperFunctionsUsed',
401 usage1.helperFunctionsUsed,
402 usage2.helperFunctionsUsed,
403 strategy.elementEquivalence);
404 check(
405 usage1,
406 usage2,
407 'needToInitializeIsolateAffinityTag',
408 usage1.needToInitializeIsolateAffinityTag,
409 usage2.needToInitializeIsolateAffinityTag);
410 check(
411 usage1,
412 usage2,
413 'needToInitializeDispatchProperty',
414 usage1.needToInitializeDispatchProperty,
415 usage2.needToInitializeDispatchProperty);
416 check(usage1, usage2, 'requiresPreamble', usage1.requiresPreamble,
417 usage2.requiresPreamble);
418 check(usage1, usage2, 'isInvokeOnUsed', usage1.isInvokeOnUsed,
419 usage2.isInvokeOnUsed);
420 check(usage1, usage2, 'isRuntimeTypeUsed', usage1.isRuntimeTypeUsed,
421 usage2.isRuntimeTypeUsed);
422 check(usage1, usage2, 'isIsolateInUse', usage1.isIsolateInUse,
423 usage2.isIsolateInUse);
424 check(usage1, usage2, 'isFunctionApplyUsed', usage1.isFunctionApplyUsed,
425 usage2.isFunctionApplyUsed);
426 check(usage1, usage2, 'isNoSuchMethodUsed', usage1.isNoSuchMethodUsed,
427 usage2.isNoSuchMethodUsed);
428 }
429
430 checkElementEnvironment(
431 ElementEnvironment env1, ElementEnvironment env2, TestStrategy strategy) {
432 checkMembers(MemberEntity member1, MemberEntity member2) {
433 Expect.equals(env1.isDeferredLoadLibraryGetter(member1),
434 env2.isDeferredLoadLibraryGetter(member2));
435
436 checkListEquivalence(
437 member1,
438 member2,
439 'metadata',
440 env1.getMemberMetadata(member1),
441 env2.getMemberMetadata(member2),
442 strategy.testConstantValues);
443 }
444
445 checkSetEquivalence(env1, env2, 'libraries', env1.libraries, env2.libraries,
446 strategy.elementEquivalence,
447 onSameElement: (LibraryEntity lib1, LibraryEntity lib2) {
448 Expect.identical(lib1, env1.lookupLibrary(lib1.canonicalUri));
449 Expect.identical(lib2, env2.lookupLibrary(lib2.canonicalUri));
450
451 List<ClassEntity> classes2 = <ClassEntity>[];
452 env1.forEachClass(lib1, (ClassEntity cls1) {
453 Expect.identical(cls1, env1.lookupClass(lib1, cls1.name));
454
455 String className = cls1.name;
456 ClassEntity cls2 = env2.lookupClass(lib2, className);
457 Expect.isNotNull(cls2, 'Missing class $className in $lib2');
458 Expect.identical(cls2, env2.lookupClass(lib2, cls2.name));
459
460 check(lib1, lib2, 'class:${className}', cls1, cls2,
461 strategy.elementEquivalence);
462
463 Expect.equals(env1.isGenericClass(cls1), env2.isGenericClass(cls2));
464
465 check(
466 cls1,
467 cls2,
468 'superclass',
469 env1.getSuperClass(cls1, skipUnnamedMixinApplications: false),
470 env2.getSuperClass(cls2, skipUnnamedMixinApplications: false),
471 strategy.elementEquivalence);
472 check(
473 cls1,
474 cls2,
475 'superclass',
476 env1.getSuperClass(cls1, skipUnnamedMixinApplications: true),
477 env2.getSuperClass(cls2, skipUnnamedMixinApplications: true),
478 strategy.elementEquivalence);
479
480 List<InterfaceType> supertypes1 = <InterfaceType>[];
481 env1.forEachSupertype(cls1, supertypes1.add);
482 List<InterfaceType> supertypes2 = <InterfaceType>[];
483 env2.forEachSupertype(cls2, supertypes1.add);
484 strategy.testTypeLists(
485 cls1, cls2, 'supertypes', supertypes1, supertypes2);
486
487 List<ClassEntity> mixins1 = <ClassEntity>[];
488 env1.forEachMixin(cls1, mixins1.add);
489 List<ClassEntity> mixins2 = <ClassEntity>[];
490 env2.forEachMixin(cls2, mixins2.add);
491 strategy.testLists(
492 cls1, cls2, 'mixins', mixins1, mixins2, strategy.elementEquivalence);
493
494 Map<MemberEntity, ClassEntity> members1 = <MemberEntity, ClassEntity>{};
495 Map<MemberEntity, ClassEntity> members2 = <MemberEntity, ClassEntity>{};
496 env1.forEachClassMember(cls1,
497 (ClassEntity declarer1, MemberEntity member1) {
498 if (cls1 == declarer1) {
499 Expect.identical(
500 member1,
501 env1.lookupClassMember(cls1, member1.name,
502 setter: member1.isSetter));
503 }
504 members1[member1] = declarer1;
505 });
506 env2.forEachClassMember(cls2,
507 (ClassEntity declarer2, MemberEntity member2) {
508 if (cls2 == declarer2) {
509 Expect.identical(
510 member2,
511 env2.lookupClassMember(cls2, member2.name,
512 setter: member2.isSetter));
513 }
514 members2[member2] = declarer2;
515 });
516 checkMapEquivalence(cls1, cls2, 'members', members1, members2, (a, b) {
517 bool result = strategy.elementEquivalence(a, b);
518 if (result) checkMembers(a, b);
519 return result;
520 }, strategy.elementEquivalence);
521
522 classes2.add(cls2);
523 });
524 env2.forEachClass(lib2, (ClassEntity cls2) {
525 Expect.isTrue(classes2.contains(cls2), "Extra class $cls2 in $lib2");
526 });
527 });
528 // TODO(johnniwinther): Test the remaining properties of [ElementEnvironment].
529 }
530
531 bool areInstantiationInfosEquivalent(
532 InstantiationInfo info1,
533 InstantiationInfo info2,
534 bool elementEquivalence(Entity a, Entity b),
535 bool typeEquivalence(DartType a, DartType b)) {
536 checkMaps(
537 info1.instantiationMap,
538 info2.instantiationMap,
539 'instantiationMap of\n '
540 '${info1.instantiationMap}\nvs ${info2.instantiationMap}',
541 elementEquivalence,
542 (a, b) => areSetsEquivalent(
543 a, b, (a, b) => areInstancesEquivalent(a, b, typeEquivalence)));
544 return true;
545 }
546
547 bool areInstancesEquivalent(Instance instance1, Instance instance2,
548 bool typeEquivalence(DartType a, DartType b)) {
549 InterfaceType type1 = instance1.type;
550 InterfaceType type2 = instance2.type;
551 return typeEquivalence(type1, type2) &&
552 instance1.kind == instance2.kind &&
553 instance1.isRedirection == instance2.isRedirection;
554 }
555
556 void checkResolutionEnqueuers(
557 BackendUsage backendUsage1,
558 BackendUsage backendUsage2,
559 ResolutionEnqueuer enqueuer1,
560 ResolutionEnqueuer enqueuer2,
561 {bool elementEquivalence(Entity a, Entity b): areElementsEquivalent,
562 bool typeEquivalence(DartType a, DartType b): areTypesEquivalent,
563 bool elementFilter(Element element),
564 bool verbose: false}) {
565 ResolutionWorldBuilderBase worldBuilder1 = enqueuer1.worldBuilder;
566 ResolutionWorldBuilderBase worldBuilder2 = enqueuer2.worldBuilder;
567
568 checkSets(
569 enqueuer1.worldBuilder.instantiatedTypes,
570 enqueuer2.worldBuilder.instantiatedTypes,
571 "Instantiated types mismatch",
572 typeEquivalence,
573 verbose: verbose);
574
575 checkSets(
576 enqueuer1.worldBuilder.directlyInstantiatedClasses,
577 enqueuer2.worldBuilder.directlyInstantiatedClasses,
578 "Directly instantiated classes mismatch",
579 elementEquivalence,
580 verbose: verbose);
581
582 checkMaps(
583 worldBuilder1.getInstantiationMap(),
584 worldBuilder2.getInstantiationMap(),
585 "Instantiated classes mismatch",
586 elementEquivalence,
587 (a, b) => areInstantiationInfosEquivalent(
588 a, b, elementEquivalence, typeEquivalence),
589 verbose: verbose);
590
591 checkSets(enqueuer1.processedEntities, enqueuer2.processedEntities,
592 "Processed element mismatch", elementEquivalence, elementFilter: (e) {
593 return elementFilter != null ? elementFilter(e) : true;
594 }, verbose: verbose);
595
596 checkSets(enqueuer1.worldBuilder.isChecks, enqueuer2.worldBuilder.isChecks,
597 "Is-check mismatch", typeEquivalence,
598 verbose: verbose);
599
600 Expect.equals(backendUsage1.isInvokeOnUsed, backendUsage2.isInvokeOnUsed,
601 "JavaScriptBackend.hasInvokeOnSupport mismatch");
602 Expect.equals(
603 backendUsage1.isFunctionApplyUsed,
604 backendUsage1.isFunctionApplyUsed,
605 "JavaScriptBackend.hasFunctionApplySupport mismatch");
606 Expect.equals(
607 backendUsage1.isRuntimeTypeUsed,
608 backendUsage2.isRuntimeTypeUsed,
609 "JavaScriptBackend.hasRuntimeTypeSupport mismatch");
610 Expect.equals(backendUsage1.isIsolateInUse, backendUsage2.isIsolateInUse,
611 "JavaScriptBackend.hasIsolateSupport mismatch");
612 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698