Move more methods to ClassHierarchy.

Change-Id: I6f7f0266a77db1e64a40307a4878bfd9b1ca5f07
Reviewed-on: https://dart-review.googlesource.com/61932
Reviewed-by: Sigmund Cherem <sigmund@google.com>
diff --git a/pkg/compiler/lib/src/dump_info.dart b/pkg/compiler/lib/src/dump_info.dart
index 7abea41..8a440d5 100644
--- a/pkg/compiler/lib/src/dump_info.dart
+++ b/pkg/compiler/lib/src/dump_info.dart
@@ -113,7 +113,8 @@
   FieldInfo visitField(FieldEntity field, {ClassEntity containingClass}) {
     var isInInstantiatedClass = false;
     if (containingClass != null) {
-      isInInstantiatedClass = closedWorld.isInstantiated(containingClass);
+      isInInstantiatedClass =
+          closedWorld.classHierarchy.isInstantiated(containingClass);
     }
     if (!isInInstantiatedClass && !_hasBeenResolved(field)) {
       return null;
diff --git a/pkg/compiler/lib/src/inferrer/builder_kernel.dart b/pkg/compiler/lib/src/inferrer/builder_kernel.dart
index 0587561..c028b90 100644
--- a/pkg/compiler/lib/src/inferrer/builder_kernel.dart
+++ b/pkg/compiler/lib/src/inferrer/builder_kernel.dart
@@ -116,7 +116,7 @@
   bool _isInClassOrSubclass(MemberEntity member) {
     ClassEntity cls = _elementMap.getMemberThisType(_analyzedMember)?.element;
     if (cls == null) return false;
-    return _closedWorld.isSubclassOf(member.enclosingClass, cls);
+    return _closedWorld.classHierarchy.isSubclassOf(member.enclosingClass, cls);
   }
 
   /// Checks whether the access or update of [selector] on [mask] potentially
@@ -274,7 +274,7 @@
     _inferrer.recordExposesThis(_analyzedMember, _isThisExposed);
 
     if (cls.isAbstract) {
-      if (_closedWorld.isInstantiated(cls)) {
+      if (_closedWorld.classHierarchy.isInstantiated(cls)) {
         _returnType = _types.nonNullSubclass(cls);
       } else {
         // TODO(johnniwinther): Avoid analyzing [_analyzedMember] in this
@@ -1048,9 +1048,10 @@
     ClassEntity cls = constructor.enclosingClass;
     return cls.library.canonicalUri == Uris.dart__native_typed_data &&
         _closedWorld.nativeData.isNativeClass(cls) &&
-        _closedWorld.isSubtypeOf(
-            cls, _closedWorld.commonElements.typedDataClass) &&
-        _closedWorld.isSubtypeOf(cls, _closedWorld.commonElements.listClass) &&
+        _closedWorld.classHierarchy
+            .isSubtypeOf(cls, _closedWorld.commonElements.typedDataClass) &&
+        _closedWorld.classHierarchy
+            .isSubtypeOf(cls, _closedWorld.commonElements.listClass) &&
         constructor.name == '';
   }
 
diff --git a/pkg/compiler/lib/src/inferrer/type_system.dart b/pkg/compiler/lib/src/inferrer/type_system.dart
index 6fa9191..d761d3f 100644
--- a/pkg/compiler/lib/src/inferrer/type_system.dart
+++ b/pkg/compiler/lib/src/inferrer/type_system.dart
@@ -458,7 +458,7 @@
     assert(strategy.checkListNode(node));
     ClassEntity typedDataClass = _closedWorld.commonElements.typedDataClass;
     bool isTypedArray = typedDataClass != null &&
-        _closedWorld.isInstantiated(typedDataClass) &&
+        _closedWorld.classHierarchy.isInstantiated(typedDataClass) &&
         _abstractValueDomain.isInstanceOfOrNull(type.type, typedDataClass);
     bool isConst = (type.type == _abstractValueDomain.constListType);
     bool isFixed = (type.type == _abstractValueDomain.fixedListType) ||
diff --git a/pkg/compiler/lib/src/inferrer/typemasks/flat_type_mask.dart b/pkg/compiler/lib/src/inferrer/typemasks/flat_type_mask.dart
index a270a6f..20150d5 100644
--- a/pkg/compiler/lib/src/inferrer/typemasks/flat_type_mask.dart
+++ b/pkg/compiler/lib/src/inferrer/typemasks/flat_type_mask.dart
@@ -55,11 +55,13 @@
       return new FlatTypeMask.internal(base, flags);
     }
     if ((flags >> 1) == SUBTYPE) {
-      if (!world.hasAnyStrictSubtype(base) || world.hasOnlySubclasses(base)) {
+      if (!world.classHierarchy.hasAnyStrictSubtype(base) ||
+          world.classHierarchy.hasOnlySubclasses(base)) {
         flags = (flags & 0x1) | (SUBCLASS << 1);
       }
     }
-    if (((flags >> 1) == SUBCLASS) && !world.hasAnyStrictSubclass(base)) {
+    if (((flags >> 1) == SUBCLASS) &&
+        !world.classHierarchy.hasAnyStrictSubclass(base)) {
       flags = (flags & 0x1) | (EXACT << 1);
     }
     CommonMasks commonMasks = world.abstractValueDomain;
@@ -102,10 +104,10 @@
     } else if (isExact) {
       return false;
     } else if (isSubclass) {
-      return closedWorld.isSubclassOf(other, base);
+      return closedWorld.classHierarchy.isSubclassOf(other, base);
     } else {
       assert(isSubtype);
-      return closedWorld.isSubtypeOf(other, base);
+      return closedWorld.classHierarchy.isSubtypeOf(other, base);
     }
   }
 
@@ -164,7 +166,7 @@
     if (flatOther.isSubclass) {
       if (isSubtype)
         return (otherBase == closedWorld.commonElements.objectClass);
-      return closedWorld.isSubclassOf(base, otherBase);
+      return closedWorld.classHierarchy.isSubclassOf(base, otherBase);
     }
     assert(flatOther.isSubtype);
     // Check whether this TypeMask satisfies otherBase's interface.
@@ -212,7 +214,7 @@
 
   bool satisfies(ClassEntity cls, JClosedWorld closedWorld) {
     if (isEmptyOrNull) return false;
-    if (closedWorld.isSubtypeOf(base, cls)) return true;
+    if (closedWorld.classHierarchy.isSubtypeOf(base, cls)) return true;
     return false;
   }
 
@@ -224,7 +226,9 @@
     if (isExact) {
       return base;
     } else if (isSubclass) {
-      return closedWorld.hasAnyStrictSubclass(base) ? null : base;
+      return closedWorld.classHierarchy.hasAnyStrictSubclass(base)
+          ? null
+          : base;
     } else {
       assert(isSubtype);
       return null;
@@ -251,13 +255,13 @@
       return flatOther.isNullable ? nullable() : this;
     } else if (base == flatOther.base) {
       return unionSame(flatOther, closedWorld);
-    } else if (closedWorld.isSubclassOf(flatOther.base, base)) {
+    } else if (closedWorld.classHierarchy.isSubclassOf(flatOther.base, base)) {
       return unionStrictSubclass(flatOther, closedWorld);
-    } else if (closedWorld.isSubclassOf(base, flatOther.base)) {
+    } else if (closedWorld.classHierarchy.isSubclassOf(base, flatOther.base)) {
       return flatOther.unionStrictSubclass(this, closedWorld);
-    } else if (closedWorld.isSubtypeOf(flatOther.base, base)) {
+    } else if (closedWorld.classHierarchy.isSubtypeOf(flatOther.base, base)) {
       return unionStrictSubtype(flatOther, closedWorld);
-    } else if (closedWorld.isSubtypeOf(base, flatOther.base)) {
+    } else if (closedWorld.classHierarchy.isSubtypeOf(base, flatOther.base)) {
       return flatOther.unionStrictSubtype(this, closedWorld);
     } else {
       return new UnionTypeMask._internal(<FlatTypeMask>[this, flatOther]);
@@ -286,7 +290,7 @@
 
   TypeMask unionStrictSubclass(FlatTypeMask other, JClosedWorld closedWorld) {
     assert(base != other.base);
-    assert(closedWorld.isSubclassOf(other.base, base));
+    assert(closedWorld.classHierarchy.isSubclassOf(other.base, base));
     assert(TypeMask.assertIsNormalized(this, closedWorld));
     assert(TypeMask.assertIsNormalized(other, closedWorld));
     int combined;
@@ -313,8 +317,8 @@
 
   TypeMask unionStrictSubtype(FlatTypeMask other, JClosedWorld closedWorld) {
     assert(base != other.base);
-    assert(!closedWorld.isSubclassOf(other.base, base));
-    assert(closedWorld.isSubtypeOf(other.base, base));
+    assert(!closedWorld.classHierarchy.isSubclassOf(other.base, base));
+    assert(closedWorld.classHierarchy.isSubtypeOf(other.base, base));
     assert(TypeMask.assertIsNormalized(this, closedWorld));
     assert(TypeMask.assertIsNormalized(other, closedWorld));
     // Since the other mask is a subtype of this mask, we need the
@@ -416,8 +420,12 @@
     // Normalization guarantees that isExact === !isSubclass && !isSubtype.
     // Both are subclass or subtype masks, so if there is a subclass
     // relationship, they are not disjoint.
-    if (closedWorld.isSubclassOf(flatOther.base, base)) return false;
-    if (closedWorld.isSubclassOf(base, flatOther.base)) return false;
+    if (closedWorld.classHierarchy.isSubclassOf(flatOther.base, base)) {
+      return false;
+    }
+    if (closedWorld.classHierarchy.isSubclassOf(base, flatOther.base)) {
+      return false;
+    }
 
     // Two different base classes have no common subclass unless one is a
     // subclass of the other (checked above).
@@ -434,10 +442,10 @@
     assert(a.isSubclass || a.isSubtype);
     assert(b.isSubtype);
     var elements = a.isSubclass
-        ? closedWorld.strictSubclassesOf(a.base)
-        : closedWorld.strictSubtypesOf(a.base);
+        ? closedWorld.classHierarchy.strictSubclassesOf(a.base)
+        : closedWorld.classHierarchy.strictSubtypesOf(a.base);
     for (var element in elements) {
-      if (closedWorld.isSubtypeOf(element, b.base)) return false;
+      if (closedWorld.classHierarchy.isSubtypeOf(element, b.base)) return false;
     }
     return true;
   }
@@ -463,7 +471,7 @@
   TypeMask intersectionStrictSubclass(
       FlatTypeMask other, JClosedWorld closedWorld) {
     assert(base != other.base);
-    assert(closedWorld.isSubclassOf(other.base, base));
+    assert(closedWorld.classHierarchy.isSubclassOf(other.base, base));
     // If this mask isn't at least a subclass mask, then the
     // intersection with the other mask is empty.
     if (isExact) return intersectionEmpty(other);
@@ -508,12 +516,12 @@
       return closedWorld.hasElementIn(base, selector, element);
     } else if (isSubclass) {
       return closedWorld.hasElementIn(base, selector, element) ||
-          closedWorld.isSubclassOf(other, base) ||
+          closedWorld.classHierarchy.isSubclassOf(other, base) ||
           closedWorld.hasAnySubclassThatMixes(base, other);
     } else {
       assert(isSubtype);
       bool result = closedWorld.hasElementIn(base, selector, element) ||
-          closedWorld.isSubtypeOf(other, base) ||
+          closedWorld.classHierarchy.isSubtypeOf(other, base) ||
           closedWorld.hasAnySubclassThatImplements(other, base) ||
           closedWorld.hasAnySubclassOfMixinUseThatImplements(other, base);
       if (result) return true;
@@ -522,7 +530,7 @@
       Iterable<ClassEntity> mixinUses = closedWorld.mixinUsesOf(base);
       return mixinUses.any((mixinApplication) =>
           closedWorld.hasElementIn(mixinApplication, selector, element) ||
-          closedWorld.isSubclassOf(other, mixinApplication) ||
+          closedWorld.classHierarchy.isSubclassOf(other, mixinApplication) ||
           closedWorld.hasAnySubclassThatMixes(mixinApplication, other));
     }
   }
@@ -560,7 +568,9 @@
       //}
       return null;
     } else {
-      if (closedWorld.isSubclassOf(base, enclosing)) return result;
+      if (closedWorld.classHierarchy.isSubclassOf(base, enclosing)) {
+        return result;
+      }
       if (closedWorld.isSubclassOfMixinUseOf(base, enclosing)) return result;
     }
     return null;
diff --git a/pkg/compiler/lib/src/inferrer/typemasks/masks.dart b/pkg/compiler/lib/src/inferrer/typemasks/masks.dart
index 23752a0..df920fc 100644
--- a/pkg/compiler/lib/src/inferrer/typemasks/masks.dart
+++ b/pkg/compiler/lib/src/inferrer/typemasks/masks.dart
@@ -198,7 +198,7 @@
     // interface `JavaScriptIndexingBehavior`.
     ClassEntity typedDataClass = _closedWorld.commonElements.typedDataClass;
     return typedDataClass != null &&
-        _closedWorld.isInstantiated(typedDataClass) &&
+        _closedWorld.classHierarchy.isInstantiated(typedDataClass) &&
         mask.satisfies(typedDataClass, _closedWorld) &&
         mask.satisfies(_closedWorld.commonElements.jsIndexingBehaviorInterface,
             _closedWorld);
@@ -212,7 +212,7 @@
     //               jsIndexingBehaviourInterface.
     ClassEntity typedDataClass = _closedWorld.commonElements.typedDataClass;
     return typedDataClass != null &&
-        _closedWorld.isInstantiated(typedDataClass) &&
+        _closedWorld.classHierarchy.isInstantiated(typedDataClass) &&
         intersects(mask, new TypeMask.subtype(typedDataClass, _closedWorld)) &&
         intersects(
             mask,
@@ -254,13 +254,14 @@
 
   @override
   bool containsType(TypeMask typeMask, ClassEntity cls) {
-    return _closedWorld.isInstantiated(cls) &&
+    return _closedWorld.classHierarchy.isInstantiated(cls) &&
         typeMask.contains(cls, _closedWorld);
   }
 
   @override
   bool containsOnlyType(TypeMask typeMask, ClassEntity cls) {
-    return _closedWorld.isInstantiated(cls) && typeMask.containsOnly(cls);
+    return _closedWorld.classHierarchy.isInstantiated(cls) &&
+        typeMask.containsOnly(cls);
   }
 
   @override
@@ -550,7 +551,7 @@
 
   @override
   AbstractValue computeReceiver(Iterable<MemberEntity> members) {
-    assert(_closedWorld
+    assert(_closedWorld.classHierarchy
         .hasAnyStrictSubclass(_closedWorld.commonElements.objectClass));
     return new TypeMask.unionOf(
         members.expand((MemberEntity element) {
@@ -559,7 +560,7 @@
         }).map((cls) {
           if (_closedWorld.commonElements.jsNullClass == cls) {
             return const TypeMask.empty();
-          } else if (_closedWorld.isInstantiated(cls)) {
+          } else if (_closedWorld.classHierarchy.isInstantiated(cls)) {
             return new TypeMask.nonNullSubclass(cls, _closedWorld);
           } else {
             // TODO(johnniwinther): Avoid the need for this case.
diff --git a/pkg/compiler/lib/src/inferrer/typemasks/type_mask.dart b/pkg/compiler/lib/src/inferrer/typemasks/type_mask.dart
index ee7d4b2..225f21c 100644
--- a/pkg/compiler/lib/src/inferrer/typemasks/type_mask.dart
+++ b/pkg/compiler/lib/src/inferrer/typemasks/type_mask.dart
@@ -107,30 +107,31 @@
 
   factory TypeMask.exact(ClassEntity base, JClosedWorld closedWorld) {
     assert(
-        closedWorld.isInstantiated(base),
+        closedWorld.classHierarchy.isInstantiated(base),
         failedAt(
             base ?? CURRENT_ELEMENT_SPANNABLE,
             "Cannot create exact type mask for uninstantiated "
-            "class $base.\n${closedWorld.dump(base)}"));
+            "class $base.\n${closedWorld.classHierarchy.dump(base)}"));
     return new FlatTypeMask.exact(base);
   }
 
   factory TypeMask.exactOrEmpty(ClassEntity base, JClosedWorld closedWorld) {
-    if (closedWorld.isInstantiated(base)) return new FlatTypeMask.exact(base);
+    if (closedWorld.classHierarchy.isInstantiated(base))
+      return new FlatTypeMask.exact(base);
     return const TypeMask.empty();
   }
 
   factory TypeMask.subclass(ClassEntity base, JClosedWorld closedWorld) {
     assert(
-        closedWorld.isInstantiated(base),
+        closedWorld.classHierarchy.isInstantiated(base),
         failedAt(
             base ?? CURRENT_ELEMENT_SPANNABLE,
             "Cannot create subclass type mask for uninstantiated "
-            "class $base.\n${closedWorld.dump(base)}"));
+            "class $base.\n${closedWorld.classHierarchy.dump(base)}"));
     ClassEntity topmost = closedWorld.getLubOfInstantiatedSubclasses(base);
     if (topmost == null) {
       return new TypeMask.empty();
-    } else if (closedWorld.hasAnyStrictSubclass(topmost)) {
+    } else if (closedWorld.classHierarchy.hasAnyStrictSubclass(topmost)) {
       return new FlatTypeMask.subclass(topmost);
     } else {
       return new TypeMask.exact(topmost, closedWorld);
@@ -142,10 +143,10 @@
     if (topmost == null) {
       return new TypeMask.empty();
     }
-    if (closedWorld.hasOnlySubclasses(topmost)) {
+    if (closedWorld.classHierarchy.hasOnlySubclasses(topmost)) {
       return new TypeMask.subclass(topmost, closedWorld);
     }
-    if (closedWorld.hasAnyStrictSubtype(topmost)) {
+    if (closedWorld.classHierarchy.hasAnyStrictSubtype(topmost)) {
       return new FlatTypeMask.subtype(topmost);
     } else {
       return new TypeMask.exact(topmost, closedWorld);
@@ -156,17 +157,17 @@
 
   factory TypeMask.nonNullExact(ClassEntity base, JClosedWorld closedWorld) {
     assert(
-        closedWorld.isInstantiated(base),
+        closedWorld.classHierarchy.isInstantiated(base),
         failedAt(
             base ?? CURRENT_ELEMENT_SPANNABLE,
             "Cannot create exact type mask for uninstantiated "
-            "class $base.\n${closedWorld.dump(base)}"));
+            "class $base.\n${closedWorld.classHierarchy.dump(base)}"));
     return new FlatTypeMask.nonNullExact(base);
   }
 
   factory TypeMask.nonNullExactOrEmpty(
       ClassEntity base, JClosedWorld closedWorld) {
-    if (closedWorld.isInstantiated(base)) {
+    if (closedWorld.classHierarchy.isInstantiated(base)) {
       return new FlatTypeMask.nonNullExact(base);
     }
     return const TypeMask.nonNullEmpty();
@@ -174,15 +175,15 @@
 
   factory TypeMask.nonNullSubclass(ClassEntity base, JClosedWorld closedWorld) {
     assert(
-        closedWorld.isInstantiated(base),
+        closedWorld.classHierarchy.isInstantiated(base),
         failedAt(
             base ?? CURRENT_ELEMENT_SPANNABLE,
             "Cannot create subclass type mask for uninstantiated "
-            "class $base.\n${closedWorld.dump(base)}"));
+            "class $base.\n${closedWorld.classHierarchy.dump(base)}"));
     ClassEntity topmost = closedWorld.getLubOfInstantiatedSubclasses(base);
     if (topmost == null) {
       return new TypeMask.nonNullEmpty();
-    } else if (closedWorld.hasAnyStrictSubclass(topmost)) {
+    } else if (closedWorld.classHierarchy.hasAnyStrictSubclass(topmost)) {
       return new FlatTypeMask.nonNullSubclass(topmost);
     } else {
       return new TypeMask.nonNullExact(topmost, closedWorld);
@@ -194,10 +195,10 @@
     if (topmost == null) {
       return new TypeMask.nonNullEmpty();
     }
-    if (closedWorld.hasOnlySubclasses(topmost)) {
+    if (closedWorld.classHierarchy.hasOnlySubclasses(topmost)) {
       return new TypeMask.nonNullSubclass(topmost, closedWorld);
     }
-    if (closedWorld.hasAnyStrictSubtype(topmost)) {
+    if (closedWorld.classHierarchy.hasAnyStrictSubtype(topmost)) {
       return new FlatTypeMask.nonNullSubtype(topmost);
     } else {
       return new TypeMask.nonNullExact(topmost, closedWorld);
@@ -239,22 +240,22 @@
     if (mask is FlatTypeMask) {
       if (mask.isEmptyOrNull) return null;
       if (mask.isExact) {
-        if (!closedWorld.isInstantiated(mask.base)) {
+        if (!closedWorld.classHierarchy.isInstantiated(mask.base)) {
           return 'Exact ${mask.base} is not instantiated.';
         }
         return null;
       }
       if (mask.isSubclass) {
-        if (!closedWorld.hasAnyStrictSubclass(mask.base)) {
+        if (!closedWorld.classHierarchy.hasAnyStrictSubclass(mask.base)) {
           return 'Subclass ${mask.base} does not have any subclasses.';
         }
         return null;
       }
       assert(mask.isSubtype);
-      if (!closedWorld.hasAnyStrictSubtype(mask.base)) {
+      if (!closedWorld.classHierarchy.hasAnyStrictSubtype(mask.base)) {
         return 'Subtype ${mask.base} does not have any subclasses.';
       }
-      if (closedWorld.hasOnlySubclasses(mask.base)) {
+      if (closedWorld.classHierarchy.hasOnlySubclasses(mask.base)) {
         return 'Subtype ${mask.base} only has subclasses.';
       }
       return null;
diff --git a/pkg/compiler/lib/src/inferrer/typemasks/union_type_mask.dart b/pkg/compiler/lib/src/inferrer/typemasks/union_type_mask.dart
index 6121c08..0da519c 100644
--- a/pkg/compiler/lib/src/inferrer/typemasks/union_type_mask.dart
+++ b/pkg/compiler/lib/src/inferrer/typemasks/union_type_mask.dart
@@ -107,8 +107,8 @@
     for (ClassEntity candidate in candidates) {
       bool isInstantiatedStrictSubclass(cls) =>
           cls != candidate &&
-          closedWorld.isExplicitlyInstantiated(cls) &&
-          closedWorld.isSubclassOf(cls, candidate);
+          closedWorld.classHierarchy.isExplicitlyInstantiated(cls) &&
+          closedWorld.classHierarchy.isSubclassOf(cls, candidate);
 
       int size;
       int kind;
@@ -121,11 +121,12 @@
         // TODO(sigmund, johnniwinther): computing length here (and below) is
         // expensive. If we can't prevent `flatten` from being called a lot, it
         // might be worth caching results.
-        size = closedWorld.strictSubclassCount(candidate);
-        assert(size <= closedWorld.strictSubtypeCount(candidate));
+        size = closedWorld.classHierarchy.strictSubclassCount(candidate);
+        assert(
+            size <= closedWorld.classHierarchy.strictSubtypeCount(candidate));
       } else {
         kind = FlatTypeMask.SUBTYPE;
-        size = closedWorld.strictSubtypeCount(candidate);
+        size = closedWorld.classHierarchy.strictSubtypeCount(candidate);
       }
       // Update the best candidate if the new one is better.
       if (bestElement == null || size < bestSize) {
@@ -237,10 +238,10 @@
     // Check for other members.
     Iterable<ClassEntity> members;
     if (flat.isSubclass) {
-      members = closedWorld.strictSubclassesOf(flat.base);
+      members = closedWorld.classHierarchy.strictSubclassesOf(flat.base);
     } else {
       assert(flat.isSubtype);
-      members = closedWorld.strictSubtypesOf(flat.base);
+      members = closedWorld.classHierarchy.strictSubtypesOf(flat.base);
     }
     return members.every((ClassEntity cls) => this.contains(cls, closedWorld));
   }
diff --git a/pkg/compiler/lib/src/js_backend/interceptor_data.dart b/pkg/compiler/lib/src/js_backend/interceptor_data.dart
index abed251..f621411 100644
--- a/pkg/compiler/lib/src/js_backend/interceptor_data.dart
+++ b/pkg/compiler/lib/src/js_backend/interceptor_data.dart
@@ -182,7 +182,8 @@
     Iterable<ClassEntity> uses = closedWorld.mixinUsesOf(mixin);
     Set<ClassEntity> result = null;
     for (ClassEntity use in uses) {
-      closedWorld.forEachStrictSubclassOf(use, (ClassEntity subclass) {
+      closedWorld.classHierarchy.forEachStrictSubclassOf(use,
+          (ClassEntity subclass) {
         if (_nativeData.isNativeOrExtendsNative(subclass)) {
           if (result == null) result = new Set<ClassEntity>();
           result.add(subclass);
@@ -212,7 +213,7 @@
     InterfaceType interfaceType = type;
     ClassEntity classElement = interfaceType.element;
     if (isInterceptedClass(classElement)) return false;
-    return closedWorld.hasOnlySubclasses(classElement);
+    return closedWorld.classHierarchy.hasOnlySubclasses(classElement);
   }
 }
 
diff --git a/pkg/compiler/lib/src/js_backend/runtime_types.dart b/pkg/compiler/lib/src/js_backend/runtime_types.dart
index 118dddf..0835bf8 100644
--- a/pkg/compiler/lib/src/js_backend/runtime_types.dart
+++ b/pkg/compiler/lib/src/js_backend/runtime_types.dart
@@ -242,7 +242,7 @@
     rtiChecksBuilderClosed = true;
 
     Map<ClassEntity, ClassUse> classUseMap = <ClassEntity, ClassUse>{};
-    for (ClassEntity cls in _closedWorld
+    for (ClassEntity cls in _closedWorld.classHierarchy
         .getClassSet(_closedWorld.commonElements.objectClass)
         .subtypes()) {
       ClassUse classUse = new ClassUse()
@@ -261,7 +261,7 @@
 
   Set<ClassEntity> computeCheckedClasses(
       CodegenWorldBuilder codegenWorldBuilder, Set<DartType> implicitIsChecks) {
-    return _closedWorld
+    return _closedWorld.classHierarchy
         .getClassSet(_closedWorld.commonElements.objectClass)
         .subtypes()
         .toSet();
diff --git a/pkg/compiler/lib/src/js_emitter/interceptor_stub_generator.dart b/pkg/compiler/lib/src/js_emitter/interceptor_stub_generator.dart
index f5d7ab1..547f81d 100644
--- a/pkg/compiler/lib/src/js_emitter/interceptor_stub_generator.dart
+++ b/pkg/compiler/lib/src/js_emitter/interceptor_stub_generator.dart
@@ -301,8 +301,8 @@
       bool containsJsIndexable = _closedWorld
               .isImplemented(_commonElements.jsIndexingBehaviorInterface) &&
           classes.any((cls) {
-            return _closedWorld.isSubtypeOf(
-                cls, _commonElements.jsIndexingBehaviorInterface);
+            return _closedWorld.classHierarchy
+                .isSubtypeOf(cls, _commonElements.jsIndexingBehaviorInterface);
           });
       // The index set operator requires a check on its set value in
       // checked mode, so we don't optimize the interceptor if the
diff --git a/pkg/compiler/lib/src/js_model/js_strategy.dart b/pkg/compiler/lib/src/js_model/js_strategy.dart
index f6aa274..1ede50a 100644
--- a/pkg/compiler/lib/src/js_model/js_strategy.dart
+++ b/pkg/compiler/lib/src/js_model/js_strategy.dart
@@ -674,11 +674,6 @@
   AbstractValueDomain get abstractValueDomain {
     return _abstractValueDomain;
   }
-
-  @override
-  void registerClosureClass(ClassEntity cls) {
-    throw new UnsupportedError('JsClosedWorld.registerClosureClass');
-  }
 }
 
 class ConstantConverter implements ConstantValueVisitor<ConstantValue, Null> {
diff --git a/pkg/compiler/lib/src/kernel/element_map_impl.dart b/pkg/compiler/lib/src/kernel/element_map_impl.dart
index 1f3fbe8..0623dec 100644
--- a/pkg/compiler/lib/src/kernel/element_map_impl.dart
+++ b/pkg/compiler/lib/src/kernel/element_map_impl.dart
@@ -2013,8 +2013,8 @@
   @override
   bool hasConcreteMatch(ClassEntity cls, Selector selector,
       {ClassEntity stopAtSuperclass}) {
-    assert(
-        isInstantiated(cls), failedAt(cls, '$cls has not been instantiated.'));
+    assert(classHierarchy.isInstantiated(cls),
+        failedAt(cls, '$cls has not been instantiated.'));
     MemberEntity element = elementEnvironment
         .lookupClassMember(cls, selector.name, setter: selector.isSetter);
     if (element == null) return false;
@@ -2057,13 +2057,6 @@
   OrderedTypeSet getOrderedTypeSet(ClassEntity cls) {
     return elementMap._getOrderedTypeSet(cls);
   }
-
-  @override
-  bool checkInvariants(ClassEntity cls, {bool mustBeInstantiated: true}) =>
-      true;
-
-  @override
-  bool checkEntity(Entity element) => true;
 }
 
 class KClosedWorldImpl extends ClosedWorldRtiNeedMixin implements KClosedWorld {
@@ -2996,10 +2989,4 @@
   ClassEntity getAppliedMixin(ClassEntity cls) {
     return elementMap._getAppliedMixin(cls);
   }
-
-  @override
-  bool validateClass(ClassEntity cls) => true;
-
-  @override
-  bool checkClass(ClassEntity cls) => true;
 }
diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart
index 40d863f..4254b73 100644
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
@@ -4144,10 +4144,10 @@
         Selector selector, MemberEntity element) {
       bool isLength = selector.isGetter && selector.name == "length";
       if (isLength || selector.isIndex) {
-        return closedWorld.isSubtypeOf(
+        return closedWorld.classHierarchy.isSubtypeOf(
             element.enclosingClass, commonElements.jsIndexableClass);
       } else if (selector.isIndexSet) {
-        return closedWorld.isSubtypeOf(
+        return closedWorld.classHierarchy.isSubtypeOf(
             element.enclosingClass, commonElements.jsMutableIndexableClass);
       } else {
         return false;
@@ -4830,11 +4830,12 @@
       js.Name operator = namer.operatorIs(element);
       HInstruction isFieldName =
           graph.addConstantStringFromName(operator, closedWorld);
-      HInstruction asFieldName = closedWorld.hasAnyStrictSubtype(element) ||
-              closedWorld.nativeData.isJsInteropClass(element)
-          ? graph.addConstantStringFromName(
-              namer.substitutionName(element), closedWorld)
-          : graph.addConstantNull(closedWorld);
+      HInstruction asFieldName =
+          closedWorld.classHierarchy.hasAnyStrictSubtype(element) ||
+                  closedWorld.nativeData.isJsInteropClass(element)
+              ? graph.addConstantStringFromName(
+                  namer.substitutionName(element), closedWorld)
+              : graph.addConstantNull(closedWorld);
       List<HInstruction> inputs = <HInstruction>[
         expression,
         isFieldName,
@@ -5581,8 +5582,8 @@
       // constructor's factory.  A simplified version is to check this is a
       // constructor body for a leaf class.
       ClassEntity class_ = element.enclosingClass;
-      if (closedWorld.isDirectlyInstantiated(class_)) {
-        return !closedWorld.isIndirectlyInstantiated(class_);
+      if (closedWorld.classHierarchy.isDirectlyInstantiated(class_)) {
+        return !closedWorld.classHierarchy.isIndirectlyInstantiated(class_);
       }
       return false;
     }
diff --git a/pkg/compiler/lib/src/ssa/codegen.dart b/pkg/compiler/lib/src/ssa/codegen.dart
index 3d08315..d72a6b5 100644
--- a/pkg/compiler/lib/src/ssa/codegen.dart
+++ b/pkg/compiler/lib/src/ssa/codegen.dart
@@ -1835,7 +1835,7 @@
       // type because our optimizations might end up in a state where the
       // invoke dynamic knows more than the receiver.
       ClassEntity enclosing = node.element.enclosingClass;
-      if (_closedWorld.isInstantiated(enclosing)) {
+      if (_closedWorld.classHierarchy.isInstantiated(enclosing)) {
         return _abstractValueDomain.createNonNullExact(enclosing);
       } else {
         // The element is mixed in so a non-null subtype mask is the most
@@ -3141,7 +3141,8 @@
 
     if (_closedWorld.isUsedAsMixin(cls)) return true;
 
-    return _closedWorld.anyStrictSubclassOf(cls, (ClassEntity subclass) {
+    return _closedWorld.classHierarchy.anyStrictSubclassOf(cls,
+        (ClassEntity subclass) {
       return !_rtiSubstitutions.isTrivialSubstitution(subclass, cls);
     });
   }
diff --git a/pkg/compiler/lib/src/ssa/optimize.dart b/pkg/compiler/lib/src/ssa/optimize.dart
index a0ac620..0837246 100644
--- a/pkg/compiler/lib/src/ssa/optimize.dart
+++ b/pkg/compiler/lib/src/ssa/optimize.dart
@@ -1326,7 +1326,8 @@
   bool needsSubstitutionForTypeVariableAccess(ClassEntity cls) {
     if (_closedWorld.isUsedAsMixin(cls)) return true;
 
-    return _closedWorld.anyStrictSubclassOf(cls, (ClassEntity subclass) {
+    return _closedWorld.classHierarchy.anyStrictSubclassOf(cls,
+        (ClassEntity subclass) {
       return !_rtiSubstitutions.isTrivialSubstitution(subclass, cls);
     });
   }
diff --git a/pkg/compiler/lib/src/universe/class_hierarchy.dart b/pkg/compiler/lib/src/universe/class_hierarchy.dart
index e0d14f1..cc91490 100644
--- a/pkg/compiler/lib/src/universe/class_hierarchy.dart
+++ b/pkg/compiler/lib/src/universe/class_hierarchy.dart
@@ -11,24 +11,94 @@
 // TODO(johnniwinther): Move more methods from `JClosedWorld` to
 // `ClassHierarchy`.
 abstract class ClassHierarchy {
-  /// Returns [ClassHierarchyNode] for [cls] used to model the class hierarchies
-  /// of known classes.
-  ///
-  /// This method is only provided for testing. For queries on classes, use the
-  /// methods defined in [JClosedWorld].
-  ClassHierarchyNode getClassHierarchyNode(ClassEntity cls);
+  /// Returns `true` if [cls] is either directly or indirectly instantiated.
+  bool isInstantiated(ClassEntity cls);
 
-  /// Returns [ClassSet] for [cls] used to model the extends and implements
-  /// relations of known classes.
+  /// Returns `true` if [cls] is directly instantiated. This means that at
+  /// runtime instances of exactly [cls] are assumed to exist.
+  bool isDirectlyInstantiated(ClassEntity cls);
+
+  /// Returns `true` if [cls] is abstractly instantiated. This means that at
+  /// runtime instances of [cls] or unknown subclasses of [cls] are assumed to
+  /// exist.
   ///
-  /// This method is only provided for testing. For queries on classes, use the
-  /// methods defined in [JClosedWorld].
-  ClassSet getClassSet(ClassEntity cls);
+  /// This is used to mark native and/or reflectable classes as instantiated.
+  /// For native classes we do not know the exact class that instantiates [cls]
+  /// so [cls] here represents the root of the subclasses. For reflectable
+  /// classes we need event abstract classes to be 'live' even though they
+  /// cannot themselves be instantiated.
+  bool isAbstractlyInstantiated(ClassEntity cls);
+
+  /// Returns `true` if [cls] is either directly or abstractly instantiated.
+  ///
+  /// See [isDirectlyInstantiated] and [isAbstractlyInstantiated].
+  bool isExplicitlyInstantiated(ClassEntity cls);
+
+  /// Returns `true` if [cls] is indirectly instantiated, that is through a
+  /// subclass.
+  bool isIndirectlyInstantiated(ClassEntity cls);
+
+  /// Return `true` if [x] is a subclass of [y].
+  bool isSubclassOf(ClassEntity x, ClassEntity y);
 
   /// Returns `true` if [x] is a subtype of [y], that is, if [x] implements an
   /// instance of [y].
   bool isSubtypeOf(ClassEntity x, ClassEntity y);
 
+  /// Returns an iterable over the live classes that extend [cls] including
+  /// [cls] itself.
+  Iterable<ClassEntity> subclassesOf(ClassEntity cls);
+
+  /// Returns an iterable over the live classes that extend [cls] _not_
+  /// including [cls] itself.
+  Iterable<ClassEntity> strictSubclassesOf(ClassEntity cls);
+
+  /// Returns the number of live classes that extend [cls] _not_
+  /// including [cls] itself.
+  int strictSubclassCount(ClassEntity cls);
+
+  /// Applies [f] to each live class that extend [cls] _not_ including [cls]
+  /// itself.
+  void forEachStrictSubclassOf(
+      ClassEntity cls, IterationStep f(ClassEntity cls));
+
+  /// Returns `true` if [predicate] applies to any live class that extend [cls]
+  /// _not_ including [cls] itself.
+  bool anyStrictSubclassOf(ClassEntity cls, bool predicate(ClassEntity cls));
+
+  /// Returns an iterable over the directly instantiated that implement [cls]
+  /// possibly including [cls] itself, if it is live.
+  Iterable<ClassEntity> subtypesOf(ClassEntity cls);
+
+  /// Returns an iterable over the live classes that implement [cls] _not_
+  /// including [cls] if it is live.
+  Iterable<ClassEntity> strictSubtypesOf(ClassEntity cls);
+
+  /// Returns the number of live classes that implement [cls] _not_
+  /// including [cls] itself.
+  int strictSubtypeCount(ClassEntity cls);
+
+  /// Applies [f] to each live class that implements [cls] _not_ including [cls]
+  /// itself.
+  void forEachStrictSubtypeOf(
+      ClassEntity cls, IterationStep f(ClassEntity cls));
+
+  /// Returns `true` if [predicate] applies to any live class that implements
+  /// [cls] _not_ including [cls] itself.
+  bool anyStrictSubtypeOf(ClassEntity cls, bool predicate(ClassEntity cls));
+
+  /// Returns `true` if [a] and [b] have any known common subtypes.
+  bool haveAnyCommonSubtypes(ClassEntity a, ClassEntity b);
+
+  /// Returns `true` if any live class other than [cls] extends [cls].
+  bool hasAnyStrictSubclass(ClassEntity cls);
+
+  /// Returns `true` if any live class other than [cls] implements [cls].
+  bool hasAnyStrictSubtype(ClassEntity cls);
+
+  /// Returns `true` if all live classes that implement [cls] extend it.
+  bool hasOnlySubclasses(ClassEntity cls);
+
   /// Returns a [SubclassResult] for the subclasses that are contained in
   /// the subclass/subtype sets of both [cls1] and [cls2].
   ///
@@ -50,18 +120,24 @@
   SubclassResult commonSubclasses(
       ClassEntity cls1, ClassQuery query1, ClassEntity cls2, ClassQuery query2);
 
-  /// Returns an iterable over the directly instantiated that implement [cls]
-  /// possibly including [cls] itself, if it is live.
-  Iterable<ClassEntity> subtypesOf(ClassEntity cls);
+  /// Returns [ClassHierarchyNode] for [cls] used to model the class hierarchies
+  /// of known classes.
+  ///
+  /// This method is only provided for testing. For queries on classes, use the
+  /// methods defined in [JClosedWorld].
+  ClassHierarchyNode getClassHierarchyNode(ClassEntity cls);
 
-  /// Returns an iterable over the live classes that extend [cls] including
-  /// [cls] itself.
-  Iterable<ClassEntity> subclassesOf(ClassEntity cls);
+  /// Returns [ClassSet] for [cls] used to model the extends and implements
+  /// relations of known classes.
+  ///
+  /// This method is only provided for testing. For queries on classes, use the
+  /// methods defined in [JClosedWorld].
+  ClassSet getClassSet(ClassEntity cls);
 
-  /// Applies [f] to each live class that implements [cls] _not_ including [cls]
-  /// itself.
-  void forEachStrictSubtypeOf(
-      ClassEntity cls, IterationStep f(ClassEntity cls));
+  /// Returns a string representation of the closed world.
+  ///
+  /// If [cls] is provided, the dump will contain only classes related to [cls].
+  String dump([ClassEntity cls]);
 }
 
 class ClassHierarchyImpl implements ClassHierarchy {
@@ -72,33 +148,49 @@
   ClassHierarchyImpl(
       this._commonElements, this._classHierarchyNodes, this._classSets);
 
-  /// Returns [ClassHierarchyNode] for [cls] used to model the class hierarchies
-  /// of known classes.
-  ///
-  /// This method is only provided for testing. For queries on classes, use the
-  /// methods defined in [JClosedWorld].
-  ClassHierarchyNode getClassHierarchyNode(ClassEntity cls) {
-    return _classHierarchyNodes[cls];
+  @override
+  bool isInstantiated(ClassEntity cls) {
+    ClassHierarchyNode node = _classHierarchyNodes[cls];
+    return node != null && node.isInstantiated;
   }
 
-  /// Returns [ClassSet] for [cls] used to model the extends and implements
-  /// relations of known classes.
-  ///
-  /// This method is only provided for testing. For queries on classes, use the
-  /// methods defined in [JClosedWorld].
-  ClassSet getClassSet(ClassEntity cls) {
-    return _classSets[cls];
+  @override
+  bool isDirectlyInstantiated(ClassEntity cls) {
+    ClassHierarchyNode node = _classHierarchyNodes[cls];
+    return node != null && node.isDirectlyInstantiated;
+  }
+
+  @override
+  bool isAbstractlyInstantiated(ClassEntity cls) {
+    ClassHierarchyNode node = _classHierarchyNodes[cls];
+    return node != null && node.isAbstractlyInstantiated;
+  }
+
+  @override
+  bool isExplicitlyInstantiated(ClassEntity cls) {
+    ClassHierarchyNode node = _classHierarchyNodes[cls];
+    return node != null && node.isExplicitlyInstantiated;
+  }
+
+  @override
+  bool isIndirectlyInstantiated(ClassEntity cls) {
+    ClassHierarchyNode node = _classHierarchyNodes[cls];
+    return node != null && node.isIndirectlyInstantiated;
   }
 
   /// Returns `true` if [x] is a subtype of [y], that is, if [x] implements an
   /// instance of [y].
   bool isSubtypeOf(ClassEntity x, ClassEntity y) {
     ClassSet classSet = _classSets[y];
-    assert(classSet != null,
-        failedAt(y, "No ClassSet for $y (${y.runtimeType}): ${_classSets}"));
+    assert(
+        classSet != null,
+        failedAt(
+            y,
+            "No ClassSet for $y (${y.runtimeType}): "
+            "${dump(y)} : ${_classSets}"));
     ClassHierarchyNode classHierarchyNode = _classHierarchyNodes[x];
     assert(classHierarchyNode != null,
-        failedAt(x, "No ClassHierarchyNode for $x"));
+        failedAt(x, "No ClassHierarchyNode for $x: ${dump(x)}"));
     return classSet.hasSubtype(classHierarchyNode);
   }
 
@@ -107,6 +199,53 @@
     return _classHierarchyNodes[y].hasSubclass(_classHierarchyNodes[x]);
   }
 
+  /// Returns an iterable over the directly instantiated classes that extend
+  /// [cls] possibly including [cls] itself, if it is live.
+  Iterable<ClassEntity> subclassesOf(ClassEntity cls) {
+    ClassHierarchyNode hierarchy = _classHierarchyNodes[cls];
+    if (hierarchy == null) return const <ClassEntity>[];
+    return hierarchy
+        .subclassesByMask(ClassHierarchyNode.EXPLICITLY_INSTANTIATED);
+  }
+
+  /// Returns an iterable over the directly instantiated classes that extend
+  /// [cls] _not_ including [cls] itself.
+  Iterable<ClassEntity> strictSubclassesOf(ClassEntity cls) {
+    ClassHierarchyNode subclasses = _classHierarchyNodes[cls];
+    if (subclasses == null) return const <ClassEntity>[];
+    return subclasses.subclassesByMask(
+        ClassHierarchyNode.EXPLICITLY_INSTANTIATED,
+        strict: true);
+  }
+
+  /// Returns the number of live classes that extend [cls] _not_
+  /// including [cls] itself.
+  int strictSubclassCount(ClassEntity cls) {
+    ClassHierarchyNode subclasses = _classHierarchyNodes[cls];
+    if (subclasses == null) return 0;
+    return subclasses.instantiatedSubclassCount;
+  }
+
+  /// Applies [f] to each live class that extend [cls] _not_ including [cls]
+  /// itself.
+  void forEachStrictSubclassOf(
+      ClassEntity cls, IterationStep f(ClassEntity cls)) {
+    ClassHierarchyNode subclasses = _classHierarchyNodes[cls];
+    if (subclasses == null) return;
+    subclasses.forEachSubclass(f, ClassHierarchyNode.EXPLICITLY_INSTANTIATED,
+        strict: true);
+  }
+
+  /// Returns `true` if [predicate] applies to any live class that extend [cls]
+  /// _not_ including [cls] itself.
+  bool anyStrictSubclassOf(ClassEntity cls, bool predicate(ClassEntity cls)) {
+    ClassHierarchyNode subclasses = _classHierarchyNodes[cls];
+    if (subclasses == null) return false;
+    return subclasses.anySubclass(
+        predicate, ClassHierarchyNode.EXPLICITLY_INSTANTIATED,
+        strict: true);
+  }
+
   /// Returns an iterable over the directly instantiated that implement [cls]
   /// possibly including [cls] itself, if it is live.
   Iterable<ClassEntity> subtypesOf(ClassEntity cls) {
@@ -119,15 +258,6 @@
     }
   }
 
-  /// Returns an iterable over the directly instantiated classes that extend
-  /// [cls] possibly including [cls] itself, if it is live.
-  Iterable<ClassEntity> subclassesOf(ClassEntity cls) {
-    ClassHierarchyNode hierarchy = _classHierarchyNodes[cls];
-    if (hierarchy == null) return const <ClassEntity>[];
-    return hierarchy
-        .subclassesByMask(ClassHierarchyNode.EXPLICITLY_INSTANTIATED);
-  }
-
   /// Returns an iterable over the directly instantiated that implement [cls]
   /// _not_ including [cls].
   Iterable<ClassEntity> strictSubtypesOf(ClassEntity cls) {
@@ -140,24 +270,12 @@
     }
   }
 
-  /// Returns an iterable over the directly instantiated classes that extend
-  /// [cls] _not_ including [cls] itself.
-  Iterable<ClassEntity> strictSubclassesOf(ClassEntity cls) {
-    ClassHierarchyNode subclasses = _classHierarchyNodes[cls];
-    if (subclasses == null) return const <ClassEntity>[];
-    return subclasses.subclassesByMask(
-        ClassHierarchyNode.EXPLICITLY_INSTANTIATED,
-        strict: true);
-  }
-
-  /// Applies [f] to each live class that extend [cls] _not_ including [cls]
-  /// itself.
-  void forEachStrictSubclassOf(
-      ClassEntity cls, IterationStep f(ClassEntity cls)) {
-    ClassHierarchyNode subclasses = _classHierarchyNodes[cls];
-    if (subclasses == null) return;
-    subclasses.forEachSubclass(f, ClassHierarchyNode.EXPLICITLY_INSTANTIATED,
-        strict: true);
+  /// Returns the number of live classes that implement [cls] _not_
+  /// including [cls] itself.
+  int strictSubtypeCount(ClassEntity cls) {
+    ClassSet classSet = _classSets[cls];
+    if (classSet == null) return 0;
+    return classSet.instantiatedSubtypeCount;
   }
 
   /// Applies [f] to each live class that implements [cls] _not_ including [cls]
@@ -170,6 +288,58 @@
         strict: true);
   }
 
+  /// Returns `true` if [predicate] applies to any live class that extend [cls]
+  /// _not_ including [cls] itself.
+  bool anyStrictSubtypeOf(ClassEntity cls, bool predicate(ClassEntity cls)) {
+    ClassSet classSet = _classSets[cls];
+    if (classSet == null) return false;
+    return classSet.anySubtype(
+        predicate, ClassHierarchyNode.EXPLICITLY_INSTANTIATED,
+        strict: true);
+  }
+
+  /// Returns `true` if [a] and [b] have any known common subtypes.
+  bool haveAnyCommonSubtypes(ClassEntity a, ClassEntity b) {
+    ClassSet classSetA = _classSets[a];
+    ClassSet classSetB = _classSets[b];
+    if (classSetA == null || classSetB == null) return false;
+    // TODO(johnniwinther): Implement an optimized query on [ClassSet].
+    Set<ClassEntity> subtypesOfB = classSetB.subtypes().toSet();
+    for (ClassEntity subtypeOfA in classSetA.subtypes()) {
+      if (subtypesOfB.contains(subtypeOfA)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  /// Returns `true` if any directly instantiated class other than [cls] extends
+  /// [cls].
+  bool hasAnyStrictSubclass(ClassEntity cls) {
+    ClassHierarchyNode subclasses = _classHierarchyNodes[cls];
+    if (subclasses == null) return false;
+    return subclasses.isIndirectlyInstantiated;
+  }
+
+  /// Returns `true` if any directly instantiated class other than [cls]
+  /// implements [cls].
+  bool hasAnyStrictSubtype(ClassEntity cls) {
+    return strictSubtypeCount(cls) > 0;
+  }
+
+  /// Returns `true` if all directly instantiated classes that implement [cls]
+  /// extend it.
+  bool hasOnlySubclasses(ClassEntity cls) {
+    // TODO(johnniwinther): move this to ClassSet?
+    if (cls == _commonElements.objectClass) return true;
+    ClassSet classSet = _classSets[cls];
+    if (classSet == null) {
+      // Vacuously true.
+      return true;
+    }
+    return classSet.hasOnlyInstantiatedSubclasses;
+  }
+
   SubclassResult commonSubclasses(ClassEntity cls1, ClassQuery query1,
       ClassEntity cls2, ClassQuery query2) {
     if (query1 == ClassQuery.EXACT && query2 == ClassQuery.EXACT) {
@@ -314,6 +484,37 @@
       return new SubclassResult(classes);
     }
   }
+
+  /// Returns [ClassHierarchyNode] for [cls] used to model the class hierarchies
+  /// of known classes.
+  ///
+  /// This method is only provided for testing. For queries on classes, use the
+  /// methods defined in [JClosedWorld].
+  ClassHierarchyNode getClassHierarchyNode(ClassEntity cls) {
+    return _classHierarchyNodes[cls];
+  }
+
+  /// Returns [ClassSet] for [cls] used to model the extends and implements
+  /// relations of known classes.
+  ///
+  /// This method is only provided for testing. For queries on classes, use the
+  /// methods defined in [JClosedWorld].
+  ClassSet getClassSet(ClassEntity cls) {
+    return _classSets[cls];
+  }
+
+  @override
+  String dump([ClassEntity cls]) {
+    StringBuffer sb = new StringBuffer();
+    if (cls != null) {
+      sb.write("Classes in the closed world related to $cls:\n");
+    } else {
+      sb.write("Instantiated classes in the closed world:\n");
+    }
+    getClassHierarchyNode(_commonElements.objectClass)
+        .printOn(sb, ' ', instantiatedOnly: cls == null, withRespectTo: cls);
+    return sb.toString();
+  }
 }
 
 class ClassHierarchyBuilder {
@@ -335,7 +536,6 @@
   }
 
   ClassHierarchyNode _ensureClassHierarchyNode(ClassEntity cls) {
-    assert(_classQueries.checkClass(cls));
     return classHierarchyNodes.putIfAbsent(cls, () {
       ClassHierarchyNode parentNode;
       ClassEntity superclass = _classQueries.getSuperClass(cls);
@@ -348,7 +548,6 @@
   }
 
   ClassSet _ensureClassSet(ClassEntity cls) {
-    assert(_classQueries.checkClass(cls));
     return classSets.putIfAbsent(cls, () {
       ClassHierarchyNode node = _ensureClassHierarchyNode(cls);
       ClassSet classSet = new ClassSet(node);
@@ -460,9 +659,6 @@
 }
 
 abstract class ClassQueries {
-  bool checkClass(covariant ClassEntity cls);
-  bool validateClass(covariant ClassEntity cls);
-
   /// Returns the declaration of [cls].
   ClassEntity getDeclaration(covariant ClassEntity cls);
 
diff --git a/pkg/compiler/lib/src/universe/resolution_world_builder.dart b/pkg/compiler/lib/src/universe/resolution_world_builder.dart
index b472c00..d3f30e2 100644
--- a/pkg/compiler/lib/src/universe/resolution_world_builder.dart
+++ b/pkg/compiler/lib/src/universe/resolution_world_builder.dart
@@ -912,11 +912,6 @@
       if (!info.hasInstantiation) {
         return;
       }
-      assert(_classQueries.checkClass(cls));
-      if (!_classQueries.validateClass(cls)) {
-        failedAt(cls, 'Class "${cls.name}" is not resolved.');
-      }
-
       _classHierarchyBuilder.updateClassHierarchyNodeForClass(cls,
           directlyInstantiated: info.isDirectlyInstantiated,
           abstractlyInstantiated: info.isAbstractlyInstantiated);
diff --git a/pkg/compiler/lib/src/world.dart b/pkg/compiler/lib/src/world.dart
index d440deb..652cde7 100644
--- a/pkg/compiler/lib/src/world.dart
+++ b/pkg/compiler/lib/src/world.dart
@@ -71,97 +71,9 @@
 
   ClassHierarchy get classHierarchy;
 
-  /// Returns `true` if [cls] is either directly or indirectly instantiated.
-  bool isInstantiated(ClassEntity cls);
-
-  /// Returns `true` if [cls] is directly instantiated. This means that at
-  /// runtime instances of exactly [cls] are assumed to exist.
-  bool isDirectlyInstantiated(ClassEntity cls);
-
-  /// Returns `true` if [cls] is abstractly instantiated. This means that at
-  /// runtime instances of [cls] or unknown subclasses of [cls] are assumed to
-  /// exist.
-  ///
-  /// This is used to mark native and/or reflectable classes as instantiated.
-  /// For native classes we do not know the exact class that instantiates [cls]
-  /// so [cls] here represents the root of the subclasses. For reflectable
-  /// classes we need event abstract classes to be 'live' even though they
-  /// cannot themselves be instantiated.
-  bool isAbstractlyInstantiated(ClassEntity cls);
-
-  /// Returns `true` if [cls] is either directly or abstractly instantiated.
-  ///
-  /// See [isDirectlyInstantiated] and [isAbstractlyInstantiated].
-  bool isExplicitlyInstantiated(ClassEntity cls);
-
-  /// Returns `true` if [cls] is indirectly instantiated, that is through a
-  /// subclass.
-  bool isIndirectlyInstantiated(ClassEntity cls);
-
   /// Returns `true` if [cls] is implemented by an instantiated class.
   bool isImplemented(ClassEntity cls);
 
-  /// Return `true` if [x] is a subclass of [y].
-  bool isSubclassOf(ClassEntity x, ClassEntity y);
-
-  /// Returns `true` if [x] is a subtype of [y], that is, if [x] implements an
-  /// instance of [y].
-  bool isSubtypeOf(ClassEntity x, ClassEntity y);
-
-  /// Returns an iterable over the live classes that extend [cls] including
-  /// [cls] itself.
-  Iterable<ClassEntity> subclassesOf(ClassEntity cls);
-
-  /// Returns an iterable over the live classes that extend [cls] _not_
-  /// including [cls] itself.
-  Iterable<ClassEntity> strictSubclassesOf(ClassEntity cls);
-
-  /// Returns the number of live classes that extend [cls] _not_
-  /// including [cls] itself.
-  int strictSubclassCount(ClassEntity cls);
-
-  /// Applies [f] to each live class that extend [cls] _not_ including [cls]
-  /// itself.
-  void forEachStrictSubclassOf(
-      ClassEntity cls, IterationStep f(ClassEntity cls));
-
-  /// Returns `true` if [predicate] applies to any live class that extend [cls]
-  /// _not_ including [cls] itself.
-  bool anyStrictSubclassOf(ClassEntity cls, bool predicate(ClassEntity cls));
-
-  /// Returns an iterable over the directly instantiated that implement [cls]
-  /// possibly including [cls] itself, if it is live.
-  Iterable<ClassEntity> subtypesOf(ClassEntity cls);
-
-  /// Returns an iterable over the live classes that implement [cls] _not_
-  /// including [cls] if it is live.
-  Iterable<ClassEntity> strictSubtypesOf(ClassEntity cls);
-
-  /// Returns the number of live classes that implement [cls] _not_
-  /// including [cls] itself.
-  int strictSubtypeCount(ClassEntity cls);
-
-  /// Applies [f] to each live class that implements [cls] _not_ including [cls]
-  /// itself.
-  void forEachStrictSubtypeOf(
-      ClassEntity cls, IterationStep f(ClassEntity cls));
-
-  /// Returns `true` if [predicate] applies to any live class that implements
-  /// [cls] _not_ including [cls] itself.
-  bool anyStrictSubtypeOf(ClassEntity cls, bool predicate(ClassEntity cls));
-
-  /// Returns `true` if [a] and [b] have any known common subtypes.
-  bool haveAnyCommonSubtypes(ClassEntity a, ClassEntity b);
-
-  /// Returns `true` if any live class other than [cls] extends [cls].
-  bool hasAnyStrictSubclass(ClassEntity cls);
-
-  /// Returns `true` if any live class other than [cls] implements [cls].
-  bool hasAnyStrictSubtype(ClassEntity cls);
-
-  /// Returns `true` if all live classes that implement [cls] extend it.
-  bool hasOnlySubclasses(ClassEntity cls);
-
   /// Returns the most specific subclass of [cls] (including [cls]) that is
   /// directly instantiated or a superclass of all directly instantiated
   /// subclasses. If [cls] is not instantiated, `null` is returned.
@@ -246,20 +158,6 @@
   bool hasElementIn(
       covariant ClassEntity cls, Selector selector, covariant Entity element);
 
-  /// Returns [ClassHierarchyNode] for [cls] used to model the class hierarchies
-  /// of known classes.
-  ///
-  /// This method is only provided for testing. For queries on classes, use the
-  /// methods defined in [JClosedWorld].
-  ClassHierarchyNode getClassHierarchyNode(ClassEntity cls);
-
-  /// Returns [ClassSet] for [cls] used to model the extends and implements
-  /// relations of known classes.
-  ///
-  /// This method is only provided for testing. For queries on classes, use the
-  /// methods defined in [JClosedWorld].
-  ClassSet getClassSet(ClassEntity cls);
-
   /// Returns `true` if the field [element] is known to be effectively final.
   bool fieldNeverChanges(MemberEntity element);
 
@@ -300,17 +198,6 @@
   /// [receiver]. If multiple targets exist or the single target is not a field,
   /// `null` is returned.
   FieldEntity locateSingleField(Selector selector, AbstractValue receiver);
-
-  /// Returns a string representation of the closed world.
-  ///
-  /// If [cls] is provided, the dump will contain only classes related to [cls].
-  String dump([ClassEntity cls]);
-
-  /// Adds the closure class [cls] to the inference world. The class is
-  /// considered directly instantiated. If [fromInstanceMember] is true, this
-  /// closure class represents a closure that is inside an instance member, thus
-  /// has access to `this`.
-  void registerClosureClass(ClassEntity cls);
 }
 
 abstract class OpenWorld implements World {
@@ -400,11 +287,6 @@
         classHierarchy = new ClassHierarchyImpl(
             commonElements, classHierarchyNodes, classSets) {}
 
-  bool checkEntity(covariant Entity element);
-
-  bool checkInvariants(covariant ClassEntity cls,
-      {bool mustBeInstantiated: true});
-
   OrderedTypeSet getOrderedTypeSet(covariant ClassEntity cls);
 
   int getHierarchyDepth(covariant ClassEntity cls);
@@ -417,207 +299,11 @@
 
   bool isNamedMixinApplication(covariant ClassEntity cls);
 
-  @override
-  bool isInstantiated(ClassEntity cls) {
-    ClassHierarchyNode node = _classHierarchyNodes[cls];
-    return node != null && node.isInstantiated;
-  }
-
-  @override
-  bool isDirectlyInstantiated(ClassEntity cls) {
-    ClassHierarchyNode node = _classHierarchyNodes[cls];
-    return node != null && node.isDirectlyInstantiated;
-  }
-
-  @override
-  bool isAbstractlyInstantiated(ClassEntity cls) {
-    ClassHierarchyNode node = _classHierarchyNodes[cls];
-    return node != null && node.isAbstractlyInstantiated;
-  }
-
-  @override
-  bool isExplicitlyInstantiated(ClassEntity cls) {
-    ClassHierarchyNode node = _classHierarchyNodes[cls];
-    return node != null && node.isExplicitlyInstantiated;
-  }
-
-  @override
-  bool isIndirectlyInstantiated(ClassEntity cls) {
-    ClassHierarchyNode node = _classHierarchyNodes[cls];
-    return node != null && node.isIndirectlyInstantiated;
-  }
-
   /// Returns `true` if [cls] is implemented by an instantiated class.
   bool isImplemented(ClassEntity cls) {
     return _implementedClasses.contains(cls);
   }
 
-  /// Returns `true` if [x] is a subtype of [y], that is, if [x] implements an
-  /// instance of [y].
-  bool isSubtypeOf(ClassEntity x, ClassEntity y) {
-    assert(checkInvariants(x));
-    assert(checkInvariants(y, mustBeInstantiated: false));
-    ClassSet classSet = _classSets[y];
-    assert(
-        classSet != null,
-        failedAt(
-            y,
-            "No ClassSet for $y (${y.runtimeType}): "
-            "${dump(y)} : ${_classSets}"));
-    ClassHierarchyNode classHierarchyNode = _classHierarchyNodes[x];
-    assert(classHierarchyNode != null,
-        failedAt(x, "No ClassHierarchyNode for $x: ${dump(x)}"));
-    return classSet.hasSubtype(classHierarchyNode);
-  }
-
-  /// Return `true` if [x] is a (non-strict) subclass of [y].
-  bool isSubclassOf(ClassEntity x, ClassEntity y) {
-    assert(checkInvariants(x));
-    assert(checkInvariants(y));
-    return _classHierarchyNodes[y].hasSubclass(_classHierarchyNodes[x]);
-  }
-
-  /// Returns an iterable over the directly instantiated classes that extend
-  /// [cls] possibly including [cls] itself, if it is live.
-  Iterable<ClassEntity> subclassesOf(ClassEntity cls) {
-    ClassHierarchyNode hierarchy = _classHierarchyNodes[cls];
-    if (hierarchy == null) return const <ClassEntity>[];
-    return hierarchy
-        .subclassesByMask(ClassHierarchyNode.EXPLICITLY_INSTANTIATED);
-  }
-
-  /// Returns an iterable over the directly instantiated classes that extend
-  /// [cls] _not_ including [cls] itself.
-  Iterable<ClassEntity> strictSubclassesOf(ClassEntity cls) {
-    ClassHierarchyNode subclasses = _classHierarchyNodes[cls];
-    if (subclasses == null) return const <ClassEntity>[];
-    return subclasses.subclassesByMask(
-        ClassHierarchyNode.EXPLICITLY_INSTANTIATED,
-        strict: true);
-  }
-
-  /// Returns the number of live classes that extend [cls] _not_
-  /// including [cls] itself.
-  int strictSubclassCount(ClassEntity cls) {
-    ClassHierarchyNode subclasses = _classHierarchyNodes[cls];
-    if (subclasses == null) return 0;
-    return subclasses.instantiatedSubclassCount;
-  }
-
-  /// Applies [f] to each live class that extend [cls] _not_ including [cls]
-  /// itself.
-  void forEachStrictSubclassOf(
-      ClassEntity cls, IterationStep f(ClassEntity cls)) {
-    ClassHierarchyNode subclasses = _classHierarchyNodes[cls];
-    if (subclasses == null) return;
-    subclasses.forEachSubclass(f, ClassHierarchyNode.EXPLICITLY_INSTANTIATED,
-        strict: true);
-  }
-
-  /// Returns `true` if [predicate] applies to any live class that extend [cls]
-  /// _not_ including [cls] itself.
-  bool anyStrictSubclassOf(ClassEntity cls, bool predicate(ClassEntity cls)) {
-    ClassHierarchyNode subclasses = _classHierarchyNodes[cls];
-    if (subclasses == null) return false;
-    return subclasses.anySubclass(
-        predicate, ClassHierarchyNode.EXPLICITLY_INSTANTIATED,
-        strict: true);
-  }
-
-  /// Returns an iterable over the directly instantiated that implement [cls]
-  /// possibly including [cls] itself, if it is live.
-  Iterable<ClassEntity> subtypesOf(ClassEntity cls) {
-    ClassSet classSet = _classSets[cls];
-    if (classSet == null) {
-      return const <ClassEntity>[];
-    } else {
-      return classSet
-          .subtypesByMask(ClassHierarchyNode.EXPLICITLY_INSTANTIATED);
-    }
-  }
-
-  /// Returns an iterable over the directly instantiated that implement [cls]
-  /// _not_ including [cls].
-  Iterable<ClassEntity> strictSubtypesOf(ClassEntity cls) {
-    ClassSet classSet = _classSets[cls];
-    if (classSet == null) {
-      return const <ClassEntity>[];
-    } else {
-      return classSet.subtypesByMask(ClassHierarchyNode.EXPLICITLY_INSTANTIATED,
-          strict: true);
-    }
-  }
-
-  /// Returns the number of live classes that implement [cls] _not_
-  /// including [cls] itself.
-  int strictSubtypeCount(ClassEntity cls) {
-    ClassSet classSet = _classSets[cls];
-    if (classSet == null) return 0;
-    return classSet.instantiatedSubtypeCount;
-  }
-
-  /// Applies [f] to each live class that implements [cls] _not_ including [cls]
-  /// itself.
-  void forEachStrictSubtypeOf(
-      ClassEntity cls, IterationStep f(ClassEntity cls)) {
-    ClassSet classSet = _classSets[cls];
-    if (classSet == null) return;
-    classSet.forEachSubtype(f, ClassHierarchyNode.EXPLICITLY_INSTANTIATED,
-        strict: true);
-  }
-
-  /// Returns `true` if [predicate] applies to any live class that extend [cls]
-  /// _not_ including [cls] itself.
-  bool anyStrictSubtypeOf(ClassEntity cls, bool predicate(ClassEntity cls)) {
-    ClassSet classSet = _classSets[cls];
-    if (classSet == null) return false;
-    return classSet.anySubtype(
-        predicate, ClassHierarchyNode.EXPLICITLY_INSTANTIATED,
-        strict: true);
-  }
-
-  /// Returns `true` if [a] and [b] have any known common subtypes.
-  bool haveAnyCommonSubtypes(ClassEntity a, ClassEntity b) {
-    ClassSet classSetA = _classSets[a];
-    ClassSet classSetB = _classSets[b];
-    if (classSetA == null || classSetB == null) return false;
-    // TODO(johnniwinther): Implement an optimized query on [ClassSet].
-    Set<ClassEntity> subtypesOfB = classSetB.subtypes().toSet();
-    for (ClassEntity subtypeOfA in classSetA.subtypes()) {
-      if (subtypesOfB.contains(subtypeOfA)) {
-        return true;
-      }
-    }
-    return false;
-  }
-
-  /// Returns `true` if any directly instantiated class other than [cls] extends
-  /// [cls].
-  bool hasAnyStrictSubclass(ClassEntity cls) {
-    ClassHierarchyNode subclasses = _classHierarchyNodes[cls];
-    if (subclasses == null) return false;
-    return subclasses.isIndirectlyInstantiated;
-  }
-
-  /// Returns `true` if any directly instantiated class other than [cls]
-  /// implements [cls].
-  bool hasAnyStrictSubtype(ClassEntity cls) {
-    return strictSubtypeCount(cls) > 0;
-  }
-
-  /// Returns `true` if all directly instantiated classes that implement [cls]
-  /// extend it.
-  bool hasOnlySubclasses(ClassEntity cls) {
-    // TODO(johnniwinther): move this to ClassSet?
-    if (cls == commonElements.objectClass) return true;
-    ClassSet classSet = _classSets[cls];
-    if (classSet == null) {
-      // Vacuously true.
-      return true;
-    }
-    return classSet.hasOnlyInstantiatedSubclasses;
-  }
-
   @override
   ClassEntity getLubOfInstantiatedSubclasses(ClassEntity cls) {
     if (nativeData.isJsInteropClass(cls)) {
@@ -655,8 +341,10 @@
   bool everySubtypeIsSubclassOfOrMixinUseOf(ClassEntity x, ClassEntity y) {
     Map<ClassEntity, bool> secondMap =
         _subtypeCoveredByCache[x] ??= <ClassEntity, bool>{};
-    return secondMap[y] ??= subtypesOf(x).every((ClassEntity cls) =>
-        isSubclassOf(cls, y) || isSubclassOfMixinUseOf(cls, y));
+    return secondMap[y] ??= classHierarchy.subtypesOf(x).every(
+        (ClassEntity cls) =>
+            classHierarchy.isSubclassOf(cls, y) ||
+            isSubclassOfMixinUseOf(cls, y));
   }
 
   /// Returns `true` if any subclass of [superclass] implements [type].
@@ -726,7 +414,6 @@
     if (!iterator.moveNext()) return const <ClassEntity>[];
 
     ClassEntity cls = iterator.current;
-    assert(checkInvariants(cls));
     OrderedTypeSet typeSet = getOrderedTypeSet(cls);
     if (!iterator.moveNext()) return typeSet.types.map((type) => type.element);
 
@@ -734,7 +421,6 @@
     Link<OrderedTypeSet> otherTypeSets = const Link<OrderedTypeSet>();
     do {
       ClassEntity otherClass = iterator.current;
-      assert(checkInvariants(otherClass));
       OrderedTypeSet otherTypeSet = getOrderedTypeSet(otherClass);
       otherTypeSets = otherTypeSets.prepend(otherTypeSet);
       if (otherTypeSet.maxDepth < depth) {
@@ -769,7 +455,7 @@
         List<ClassEntity> uses = <ClassEntity>[];
 
         void addLiveUse(ClassEntity mixinApplication) {
-          if (isInstantiated(mixinApplication)) {
+          if (classHierarchy.isInstantiated(mixinApplication)) {
             uses.add(mixinApplication);
           } else if (isNamedMixinApplication(mixinApplication)) {
             Set<ClassEntity> next = mixinUses[mixinApplication];
@@ -793,7 +479,7 @@
   /// of [superclass].
   bool hasAnySubclassThatMixes(ClassEntity superclass, ClassEntity mixin) {
     return mixinUsesOf(mixin).any((ClassEntity each) {
-      return isSubclassOf(each, superclass);
+      return classHierarchy.isSubclassOf(each, superclass);
     });
   }
 
@@ -913,19 +599,6 @@
     return false;
   }
 
-  @override
-  String dump([ClassEntity cls]) {
-    StringBuffer sb = new StringBuffer();
-    if (cls != null) {
-      sb.write("Classes in the closed world related to $cls:\n");
-    } else {
-      sb.write("Instantiated classes in the closed world:\n");
-    }
-    getClassHierarchyNode(commonElements.objectClass)
-        .printOn(sb, ' ', instantiatedOnly: cls == null, withRespectTo: cls);
-    return sb.toString();
-  }
-
   /// Should only be called by subclasses.
   void addClassHierarchyNode(ClassEntity cls, ClassHierarchyNode node) {
     _classHierarchyNodes[cls] = node;
diff --git a/tests/compiler/dart2js/inference/type_mask2_test.dart b/tests/compiler/dart2js/inference/type_mask2_test.dart
index 200f245..904a4c4 100644
--- a/tests/compiler/dart2js/inference/type_mask2_test.dart
+++ b/tests/compiler/dart2js/inference/type_mask2_test.dart
@@ -222,17 +222,17 @@
   ClassEntity String_ = env.getElement("String");
   ClassEntity JSString = closedWorld.commonElements.jsStringClass;
 
-  Expect.isFalse(closedWorld.isDirectlyInstantiated(Object_));
-  Expect.isTrue(closedWorld.isIndirectlyInstantiated(Object_));
-  Expect.isTrue(closedWorld.isInstantiated(Object_));
+  Expect.isFalse(closedWorld.classHierarchy.isDirectlyInstantiated(Object_));
+  Expect.isTrue(closedWorld.classHierarchy.isIndirectlyInstantiated(Object_));
+  Expect.isTrue(closedWorld.classHierarchy.isInstantiated(Object_));
 
-  Expect.isFalse(closedWorld.isDirectlyInstantiated(String_));
-  Expect.isFalse(closedWorld.isIndirectlyInstantiated(String_));
-  Expect.isFalse(closedWorld.isInstantiated(String_));
+  Expect.isFalse(closedWorld.classHierarchy.isDirectlyInstantiated(String_));
+  Expect.isFalse(closedWorld.classHierarchy.isIndirectlyInstantiated(String_));
+  Expect.isFalse(closedWorld.classHierarchy.isInstantiated(String_));
 
-  Expect.isTrue(closedWorld.isDirectlyInstantiated(JSString));
-  Expect.isFalse(closedWorld.isIndirectlyInstantiated(JSString));
-  Expect.isTrue(closedWorld.isInstantiated(JSString));
+  Expect.isTrue(closedWorld.classHierarchy.isDirectlyInstantiated(JSString));
+  Expect.isFalse(closedWorld.classHierarchy.isIndirectlyInstantiated(JSString));
+  Expect.isTrue(closedWorld.classHierarchy.isInstantiated(JSString));
 
   TypeMask subtypeString = new TypeMask.nonNullSubtype(String_, closedWorld);
   TypeMask exactJSString = new TypeMask.nonNullExact(JSString, closedWorld);
diff --git a/tests/compiler/dart2js/jsinterop/world_test.dart b/tests/compiler/dart2js/jsinterop/world_test.dart
index 25377d5..8233d0b 100644
--- a/tests/compiler/dart2js/jsinterop/world_test.dart
+++ b/tests/compiler/dart2js/jsinterop/world_test.dart
@@ -150,16 +150,16 @@
       if (directlyInstantiated.contains(name)) {
         isInstantiated = true;
         Expect.isTrue(
-            world.isDirectlyInstantiated(cls),
+            world.classHierarchy.isDirectlyInstantiated(cls),
             "Expected $name to be directly instantiated in `${mainSource}`:"
-            "\n${world.dump(cls)}");
+            "\n${world.classHierarchy.dump(cls)}");
       }
       if (abstractlyInstantiated.contains(name)) {
         isInstantiated = true;
         Expect.isTrue(
-            world.isAbstractlyInstantiated(cls),
+            world.classHierarchy.isAbstractlyInstantiated(cls),
             "Expected $name to be abstractly instantiated in `${mainSource}`:"
-            "\n${world.dump(cls)}");
+            "\n${world.classHierarchy.dump(cls)}");
         Expect.isTrue(
             world.needsNoSuchMethod(cls, nonExisting, ClassQuery.EXACT),
             "Expected $name to need noSuchMethod for $nonExisting.");
@@ -173,15 +173,15 @@
       if (indirectlyInstantiated.contains(name)) {
         isInstantiated = true;
         Expect.isTrue(
-            world.isIndirectlyInstantiated(cls),
+            world.classHierarchy.isIndirectlyInstantiated(cls),
             "Expected $name to be indirectly instantiated in `${mainSource}`:"
-            "\n${world.dump(cls)}");
+            "\n${world.classHierarchy.dump(cls)}");
       }
       if (!isInstantiated && (name != 'Object' && name != 'Interceptor')) {
         Expect.isFalse(
-            world.isInstantiated(cls),
+            world.classHierarchy.isInstantiated(cls),
             "Expected $name to be uninstantiated in `${mainSource}`:"
-            "\n${world.dump(cls)}");
+            "\n${world.classHierarchy.dump(cls)}");
       }
     }
   }
diff --git a/tests/compiler/dart2js/model/class_set_test.dart b/tests/compiler/dart2js/model/class_set_test.dart
index 833334f..70b8807 100644
--- a/tests/compiler/dart2js/model/class_set_test.dart
+++ b/tests/compiler/dart2js/model/class_set_test.dart
@@ -612,12 +612,12 @@
   checkIsFunction(ClassEntity cls, {bool expected: true}) {
     Expect.equals(
         expected,
-        world.isSubtypeOf(cls, functionClass),
+        world.classHierarchy.isSubtypeOf(cls, functionClass),
         "Expected $cls ${expected ? '' : 'not '}to be a subtype "
         "of $functionClass.");
   }
 
   checkIsFunction(A, expected: !strongMode);
 
-  world.forEachStrictSubtypeOf(closureClass, checkIsFunction);
+  world.classHierarchy.forEachStrictSubtypeOf(closureClass, checkIsFunction);
 }
diff --git a/tests/compiler/dart2js/model/world_test.dart b/tests/compiler/dart2js/model/world_test.dart
index 8975dba..e4599ef 100644
--- a/tests/compiler/dart2js/model/world_test.dart
+++ b/tests/compiler/dart2js/model/world_test.dart
@@ -74,7 +74,7 @@
           foundClasses.contains(expectedClass),
           "Expect $expectedClass in '$property' on $cls. "
           "Found:\n ${foundClasses.join('\n ')}\n"
-          "${closedWorld.dump(cls)}");
+          "${closedWorld.classHierarchy.dump(cls)}");
     }
     if (exact) {
       Expect.equals(
@@ -83,7 +83,7 @@
           "Unexpected classes "
           "${foundClasses.where((c) => !expectedClasses.contains(c))} "
           "in '$property' on $cls.\n"
-          "${closedWorld.dump(cls)}");
+          "${closedWorld.classHierarchy.dump(cls)}");
     }
   }
 
@@ -109,32 +109,33 @@
           expectedClasses.length,
           count,
           "Unexpected class count in '$property' on $cls.\n"
-          "${closedWorld.dump(cls)}");
+          "${closedWorld.classHierarchy.dump(cls)}");
     }
   }
 
   void testSubclasses(ClassEntity cls, List<ClassEntity> expectedClasses,
       {bool exact: true}) {
-    check('subclassesOf', cls, closedWorld.subclassesOf(cls), expectedClasses,
+    check('subclassesOf', cls, closedWorld.classHierarchy.subclassesOf(cls),
+        expectedClasses,
         exact: exact);
   }
 
   void testStrictSubclasses(ClassEntity cls, List<ClassEntity> expectedClasses,
       {bool exact: true}) {
-    check('strictSubclassesOf', cls, closedWorld.strictSubclassesOf(cls),
-        expectedClasses,
+    check('strictSubclassesOf', cls,
+        closedWorld.classHierarchy.strictSubclassesOf(cls), expectedClasses,
         exact: exact,
-        forEach: closedWorld.forEachStrictSubclassOf,
-        getCount: closedWorld.strictSubclassCount);
+        forEach: closedWorld.classHierarchy.forEachStrictSubclassOf,
+        getCount: closedWorld.classHierarchy.strictSubclassCount);
   }
 
   void testStrictSubtypes(ClassEntity cls, List<ClassEntity> expectedClasses,
       {bool exact: true}) {
-    check('strictSubtypesOf', cls, closedWorld.strictSubtypesOf(cls),
-        expectedClasses,
+    check('strictSubtypesOf', cls,
+        closedWorld.classHierarchy.strictSubtypesOf(cls), expectedClasses,
         exact: exact,
-        forEach: closedWorld.forEachStrictSubtypeOf,
-        getCount: closedWorld.strictSubtypeCount);
+        forEach: closedWorld.classHierarchy.forEachStrictSubtypeOf,
+        getCount: closedWorld.classHierarchy.strictSubtypeCount);
   }
 
   void testMixinUses(ClassEntity cls, List<ClassEntity> expectedClasses,
@@ -248,9 +249,13 @@
 
   check(String name, {bool hasStrictSubtype, bool hasOnlySubclasses}) {
     ClassEntity cls = env.getElement(name);
-    Expect.equals(hasStrictSubtype, closedWorld.hasAnyStrictSubtype(cls),
+    Expect.equals(
+        hasStrictSubtype,
+        closedWorld.classHierarchy.hasAnyStrictSubtype(cls),
         "Unexpected hasAnyStrictSubtype property on $cls.");
-    Expect.equals(hasOnlySubclasses, closedWorld.hasOnlySubclasses(cls),
+    Expect.equals(
+        hasOnlySubclasses,
+        closedWorld.classHierarchy.hasOnlySubclasses(cls),
         "Unexpected hasOnlySubclasses property on $cls.");
   }
 
@@ -360,26 +365,30 @@
       int instantiatedSubtypeCount,
       List<ClassEntity> subclasses: const <ClassEntity>[],
       List<ClassEntity> subtypes: const <ClassEntity>[]}) {
-    ClassSet classSet = closedWorld.getClassSet(cls);
+    ClassSet classSet = closedWorld.classHierarchy.getClassSet(cls);
     ClassHierarchyNode node = classSet.node;
 
-    String dumpText = '\n${closedWorld.dump(cls)}';
+    String dumpText = '\n${closedWorld.classHierarchy.dump(cls)}';
 
     Expect.equals(
         isDirectlyInstantiated,
-        closedWorld.isDirectlyInstantiated(cls),
+        closedWorld.classHierarchy.isDirectlyInstantiated(cls),
         "Unexpected isDirectlyInstantiated property on $cls.$dumpText");
     Expect.equals(
         isAbstractlyInstantiated,
-        closedWorld.isAbstractlyInstantiated(cls),
+        closedWorld.classHierarchy.isAbstractlyInstantiated(cls),
         "Unexpected isAbstractlyInstantiated property on $cls.$dumpText");
     Expect.equals(
         isIndirectlyInstantiated,
-        closedWorld.isIndirectlyInstantiated(cls),
+        closedWorld.classHierarchy.isIndirectlyInstantiated(cls),
         "Unexpected isIndirectlyInstantiated property on $cls.$dumpText");
-    Expect.equals(hasStrictSubtype, closedWorld.hasAnyStrictSubtype(cls),
+    Expect.equals(
+        hasStrictSubtype,
+        closedWorld.classHierarchy.hasAnyStrictSubtype(cls),
         "Unexpected hasAnyStrictSubtype property on $cls.$dumpText");
-    Expect.equals(hasOnlySubclasses, closedWorld.hasOnlySubclasses(cls),
+    Expect.equals(
+        hasOnlySubclasses,
+        closedWorld.classHierarchy.hasOnlySubclasses(cls),
         "Unexpected hasOnlySubclasses property on $cls.$dumpText");
     Expect.equals(
         lubOfInstantiatedSubclasses,
@@ -399,19 +408,20 @@
     }
     for (ClassEntity other in allClasses) {
       if (other == cls) continue;
-      if (!closedWorld.isExplicitlyInstantiated(other)) continue;
+      if (!closedWorld.classHierarchy.isExplicitlyInstantiated(other)) continue;
       Expect.equals(
           subclasses.contains(other),
-          closedWorld.isSubclassOf(other, cls),
+          closedWorld.classHierarchy.isSubclassOf(other, cls),
           "Unexpected subclass relation between $other and $cls.");
       Expect.equals(
           subtypes.contains(other),
-          closedWorld.isSubtypeOf(other, cls),
+          closedWorld.classHierarchy.isSubtypeOf(other, cls),
           "Unexpected subtype relation between $other and $cls.");
     }
 
     Set<ClassEntity> strictSubclasses = new Set<ClassEntity>();
-    closedWorld.forEachStrictSubclassOf(cls, (ClassEntity other) {
+    closedWorld.classHierarchy.forEachStrictSubclassOf(cls,
+        (ClassEntity other) {
       if (allClasses.contains(other)) {
         strictSubclasses.add(other);
       }
@@ -420,7 +430,7 @@
         "Unexpected strict subclasses of $cls: ${strictSubclasses}.");
 
     Set<ClassEntity> strictSubtypes = new Set<ClassEntity>();
-    closedWorld.forEachStrictSubtypeOf(cls, (ClassEntity other) {
+    closedWorld.classHierarchy.forEachStrictSubtypeOf(cls, (ClassEntity other) {
       if (allClasses.contains(other)) {
         strictSubtypes.add(other);
       }
diff --git a/tests/compiler/dart2js/needs_no_such_method_test.dart b/tests/compiler/dart2js/needs_no_such_method_test.dart
index 735e390..db958ac 100644
--- a/tests/compiler/dart2js/needs_no_such_method_test.dart
+++ b/tests/compiler/dart2js/needs_no_such_method_test.dart
@@ -65,7 +65,7 @@
   void check(ClassEntity cls, ClassQuery query, Selector selector,
       bool expectedResult) {
     bool result;
-    if (closedWorld.getClassSet(cls) == null) {
+    if (closedWorld.classHierarchy.getClassSet(cls) == null) {
       // The class isn't live, so it can't need a noSuchMethod for [selector].
       result = false;
     } else {
@@ -80,16 +80,17 @@
 
   await run([]);
 
-  Expect.isFalse(closedWorld.isDirectlyInstantiated(superclass));
-  Expect.isFalse(closedWorld.isIndirectlyInstantiated(superclass));
+  Expect.isFalse(closedWorld.classHierarchy.isDirectlyInstantiated(superclass));
+  Expect.isFalse(
+      closedWorld.classHierarchy.isIndirectlyInstantiated(superclass));
   Expect.isFalse(closedWorld.isImplemented(superclass));
 
-  Expect.isFalse(closedWorld.isDirectlyInstantiated(subclass));
-  Expect.isFalse(closedWorld.isIndirectlyInstantiated(subclass));
+  Expect.isFalse(closedWorld.classHierarchy.isDirectlyInstantiated(subclass));
+  Expect.isFalse(closedWorld.classHierarchy.isIndirectlyInstantiated(subclass));
   Expect.isFalse(closedWorld.isImplemented(subclass));
 
-  Expect.isFalse(closedWorld.isDirectlyInstantiated(subtype));
-  Expect.isFalse(closedWorld.isIndirectlyInstantiated(subtype));
+  Expect.isFalse(closedWorld.classHierarchy.isDirectlyInstantiated(subtype));
+  Expect.isFalse(closedWorld.classHierarchy.isIndirectlyInstantiated(subtype));
   Expect.isFalse(closedWorld.isImplemented(subtype));
 
   check(superclass, ClassQuery.EXACT, foo, false);
@@ -124,16 +125,17 @@
 
   await run(['Superclass']);
 
-  Expect.isTrue(closedWorld.isDirectlyInstantiated(superclass));
-  Expect.isFalse(closedWorld.isIndirectlyInstantiated(superclass));
+  Expect.isTrue(closedWorld.classHierarchy.isDirectlyInstantiated(superclass));
+  Expect.isFalse(
+      closedWorld.classHierarchy.isIndirectlyInstantiated(superclass));
   Expect.isTrue(closedWorld.isImplemented(superclass));
 
-  Expect.isFalse(closedWorld.isDirectlyInstantiated(subclass));
-  Expect.isFalse(closedWorld.isIndirectlyInstantiated(subclass));
+  Expect.isFalse(closedWorld.classHierarchy.isDirectlyInstantiated(subclass));
+  Expect.isFalse(closedWorld.classHierarchy.isIndirectlyInstantiated(subclass));
   Expect.isFalse(closedWorld.isImplemented(subclass));
 
-  Expect.isFalse(closedWorld.isDirectlyInstantiated(subtype));
-  Expect.isFalse(closedWorld.isIndirectlyInstantiated(subtype));
+  Expect.isFalse(closedWorld.classHierarchy.isDirectlyInstantiated(subtype));
+  Expect.isFalse(closedWorld.classHierarchy.isIndirectlyInstantiated(subtype));
   Expect.isFalse(closedWorld.isImplemented(subtype));
 
   check(superclass, ClassQuery.EXACT, foo, false);
@@ -168,16 +170,17 @@
 
   await run(['Subclass']);
 
-  Expect.isFalse(closedWorld.isDirectlyInstantiated(superclass));
-  Expect.isTrue(closedWorld.isIndirectlyInstantiated(superclass));
+  Expect.isFalse(closedWorld.classHierarchy.isDirectlyInstantiated(superclass));
+  Expect.isTrue(
+      closedWorld.classHierarchy.isIndirectlyInstantiated(superclass));
   Expect.isTrue(closedWorld.isImplemented(superclass));
 
-  Expect.isTrue(closedWorld.isDirectlyInstantiated(subclass));
-  Expect.isFalse(closedWorld.isIndirectlyInstantiated(subclass));
+  Expect.isTrue(closedWorld.classHierarchy.isDirectlyInstantiated(subclass));
+  Expect.isFalse(closedWorld.classHierarchy.isIndirectlyInstantiated(subclass));
   Expect.isTrue(closedWorld.isImplemented(subclass));
 
-  Expect.isFalse(closedWorld.isDirectlyInstantiated(subtype));
-  Expect.isFalse(closedWorld.isIndirectlyInstantiated(subtype));
+  Expect.isFalse(closedWorld.classHierarchy.isDirectlyInstantiated(subtype));
+  Expect.isFalse(closedWorld.classHierarchy.isIndirectlyInstantiated(subtype));
   Expect.isFalse(closedWorld.isImplemented(subtype));
 
   check(superclass, ClassQuery.EXACT, foo, false);
@@ -212,16 +215,17 @@
 
   await run(['Subtype']);
 
-  Expect.isFalse(closedWorld.isDirectlyInstantiated(superclass));
-  Expect.isFalse(closedWorld.isIndirectlyInstantiated(superclass));
+  Expect.isFalse(closedWorld.classHierarchy.isDirectlyInstantiated(superclass));
+  Expect.isFalse(
+      closedWorld.classHierarchy.isIndirectlyInstantiated(superclass));
   Expect.isTrue(closedWorld.isImplemented(superclass));
 
-  Expect.isFalse(closedWorld.isDirectlyInstantiated(subclass));
-  Expect.isFalse(closedWorld.isIndirectlyInstantiated(subclass));
+  Expect.isFalse(closedWorld.classHierarchy.isDirectlyInstantiated(subclass));
+  Expect.isFalse(closedWorld.classHierarchy.isIndirectlyInstantiated(subclass));
   Expect.isFalse(closedWorld.isImplemented(subclass));
 
-  Expect.isTrue(closedWorld.isDirectlyInstantiated(subtype));
-  Expect.isFalse(closedWorld.isIndirectlyInstantiated(subtype));
+  Expect.isTrue(closedWorld.classHierarchy.isDirectlyInstantiated(subtype));
+  Expect.isFalse(closedWorld.classHierarchy.isIndirectlyInstantiated(subtype));
   Expect.isTrue(closedWorld.isImplemented(subtype));
 
   check(superclass, ClassQuery.EXACT, foo, false);
@@ -256,16 +260,17 @@
 
   await run(['Subclass', 'Subtype']);
 
-  Expect.isFalse(closedWorld.isDirectlyInstantiated(superclass));
-  Expect.isTrue(closedWorld.isIndirectlyInstantiated(superclass));
+  Expect.isFalse(closedWorld.classHierarchy.isDirectlyInstantiated(superclass));
+  Expect.isTrue(
+      closedWorld.classHierarchy.isIndirectlyInstantiated(superclass));
   Expect.isTrue(closedWorld.isImplemented(superclass));
 
-  Expect.isTrue(closedWorld.isDirectlyInstantiated(subclass));
-  Expect.isFalse(closedWorld.isIndirectlyInstantiated(subclass));
+  Expect.isTrue(closedWorld.classHierarchy.isDirectlyInstantiated(subclass));
+  Expect.isFalse(closedWorld.classHierarchy.isIndirectlyInstantiated(subclass));
   Expect.isTrue(closedWorld.isImplemented(subclass));
 
-  Expect.isTrue(closedWorld.isDirectlyInstantiated(subtype));
-  Expect.isFalse(closedWorld.isIndirectlyInstantiated(subtype));
+  Expect.isTrue(closedWorld.classHierarchy.isDirectlyInstantiated(subtype));
+  Expect.isFalse(closedWorld.classHierarchy.isIndirectlyInstantiated(subtype));
   Expect.isTrue(closedWorld.isImplemented(subtype));
 
   check(superclass, ClassQuery.EXACT, foo, false);
diff --git a/tests/compiler/dart2js/receiver_type_test.dart b/tests/compiler/dart2js/receiver_type_test.dart
index 50b8fc3..c158073 100644
--- a/tests/compiler/dart2js/receiver_type_test.dart
+++ b/tests/compiler/dart2js/receiver_type_test.dart
@@ -47,8 +47,8 @@
   JClosedWorld closedWorld = env.jClosedWorld;
   int closureCount = 0;
   Selector callSelector = new Selector.callClosure(0);
-  closedWorld.forEachStrictSubclassOf(closedWorld.commonElements.objectClass,
-      (ClassEntity cls) {
+  closedWorld.classHierarchy.forEachStrictSubclassOf(
+      closedWorld.commonElements.objectClass, (ClassEntity cls) {
     if (cls.library.canonicalUri.scheme != 'memory') return;
 
     TypeMask mask = new TypeMask.nonNullSubclass(cls, closedWorld);