Use field for class hierarchy map

Change-Id: Iabcfd69f3ecbd3d87eb4c7dafd9c80a1be01a016
Reviewed-on: https://dart-review.googlesource.com/63540
Commit-Queue: Stephen Adams <sra@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
diff --git a/pkg/compiler/lib/src/js_model/elements.dart b/pkg/compiler/lib/src/js_model/elements.dart
index 5f2a4a1..79be26a 100644
--- a/pkg/compiler/lib/src/js_model/elements.dart
+++ b/pkg/compiler/lib/src/js_model/elements.dart
@@ -9,6 +9,7 @@
 import '../elements/names.dart';
 import '../elements/types.dart';
 import '../kernel/indexed.dart';
+import '../universe/class_set.dart' show ClassHierarchyNodesMapKey;
 
 /// Map from 'frontend' to 'backend' elements.
 ///
@@ -323,7 +324,7 @@
   String toString() => '${jsElementPrefix}library($name)';
 }
 
-class JClass extends IndexedClass {
+class JClass extends IndexedClass with ClassHierarchyNodesMapKey {
   final JLibrary library;
 
   final String name;
diff --git a/pkg/compiler/lib/src/js_model/js_strategy.dart b/pkg/compiler/lib/src/js_model/js_strategy.dart
index 6b68731..f1b1c84 100644
--- a/pkg/compiler/lib/src/js_model/js_strategy.dart
+++ b/pkg/compiler/lib/src/js_model/js_strategy.dart
@@ -230,7 +230,7 @@
 class JsClosedWorldBuilder {
   final JsKernelToElementMap _elementMap;
   final Map<ClassEntity, ClassHierarchyNode> _classHierarchyNodes =
-      <ClassEntity, ClassHierarchyNode>{};
+      new ClassHierarchyNodesMap();
   final Map<ClassEntity, ClassSet> _classSets = <ClassEntity, ClassSet>{};
   final KernelClosureConversionTask _closureConversionTask;
   final CompilerOptions _options;
diff --git a/pkg/compiler/lib/src/universe/class_set.dart b/pkg/compiler/lib/src/universe/class_set.dart
index e747c75..3d17859 100644
--- a/pkg/compiler/lib/src/universe/class_set.dart
+++ b/pkg/compiler/lib/src/universe/class_set.dart
@@ -4,7 +4,7 @@
 
 library dart2js.world.class_set;
 
-import 'dart:collection' show IterableBase;
+import 'dart:collection' show IterableBase, MapBase;
 
 import 'package:front_end/src/fasta/util/link.dart' show Link;
 
@@ -964,3 +964,44 @@
 /// and [ClassSet]. The return value controls the continued iteration. If `null`
 /// is returned, iteration continues to the end.
 typedef IterationStep ForEachFunction(ClassEntity cls);
+
+/// Singleton map implemented as a field on the key.
+class ClassHierarchyNodesMap extends MapBase<ClassEntity, ClassHierarchyNode> {
+  ClassHierarchyNode operator [](Object cls) {
+    // TOOD(sra): Change the key type to `covariant ClassHierarchyNodesMapKey`.
+    if (cls is ClassHierarchyNodesMapKey) {
+      return cls._classHierarchyNode;
+    }
+    throw new UnimplementedError('ClassHierarchyNodesMap for $cls');
+  }
+
+  operator []=(Object cls, ClassHierarchyNode node) {
+    // TOOD(sra): Change the key type to `covariant ClassHierarchyNodesMapKey`.
+    if (cls is ClassHierarchyNodesMapKey) {
+      cls._classHierarchyNode = node;
+      return;
+    }
+    throw new UnimplementedError('ClassHierarchyNodesMap for $cls');
+  }
+
+  ClassHierarchyNode putIfAbsent(
+      ClassEntity cls, ClassHierarchyNode ifAbsent()) {
+    return this[cls] ??= ifAbsent();
+  }
+
+  Iterable<ClassEntity> get keys {
+    throw new UnimplementedError('ClassHierarchyNodesMap.keys');
+  }
+
+  ClassHierarchyNode remove(Object key) {
+    throw new UnimplementedError('ClassHierarchyNodesMap.remove');
+  }
+
+  void clear() {
+    throw new UnimplementedError('ClassHierarchyNodesMap.clear');
+  }
+}
+
+abstract class ClassHierarchyNodesMapKey implements ClassEntity {
+  ClassHierarchyNode _classHierarchyNode;
+}