Flatten interface entries into the iftable.

Avoid an indirection when scanning the iftable by inlining the interface
entry into the iftable.
Copy the iftable for marker interfaces from parents to their children
(for example for exceptions).
Don't allocate method arrays for 0 element interface method tables.

Change-Id: I8402960d4ddbe4b1ffd335ed4ce4b4825210fd0d
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 40ca635..83661cb 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -166,7 +166,6 @@
   "Ljava/lang/Object;",
   "[Ljava/lang/Class;",
   "[Ljava/lang/Object;",
-  "[[Ljava/lang/Object;",
   "Ljava/lang/String;",
   "Ljava/lang/DexCache;",
   "Ljava/lang/ref/Reference;",
@@ -258,10 +257,6 @@
   SirtRef<Class> object_array_class(self, AllocClass(self, java_lang_Class.get(), sizeof(Class)));
   object_array_class->SetComponentType(java_lang_Object.get());
 
-  // Object[][] needed for iftables.
-  SirtRef<Class> object_array_array_class(self, AllocClass(self, java_lang_Class.get(), sizeof(Class)));
-  object_array_array_class->SetComponentType(object_array_class.get());
-
   // Setup the char class to be used for char[].
   SirtRef<Class> char_class(self, AllocClass(self, java_lang_Class.get(), sizeof(Class)));
 
@@ -283,7 +278,6 @@
   SetClassRoot(kJavaLangObject, java_lang_Object.get());
   SetClassRoot(kClassArrayClass, class_array_class.get());
   SetClassRoot(kObjectArrayClass, object_array_class.get());
-  SetClassRoot(kObjectArrayArrayClass, object_array_array_class.get());
   SetClassRoot(kCharArrayClass, char_array_class.get());
   SetClassRoot(kJavaLangString, java_lang_String.get());
 
@@ -428,9 +422,6 @@
   Class* found_object_array_class = FindSystemClass("[Ljava/lang/Object;");
   CHECK_EQ(object_array_class.get(), found_object_array_class);
 
-  Class* found_object_array_array_class = FindSystemClass("[[Ljava/lang/Object;");
-  CHECK_EQ(object_array_array_class.get(), found_object_array_array_class);
-
   // Setup the single, global copy of "iftable".
   Class* java_lang_Cloneable = FindSystemClass("Ljava/lang/Cloneable;");
   CHECK(java_lang_Cloneable != NULL);
@@ -438,8 +429,8 @@
   CHECK(java_io_Serializable != NULL);
   // We assume that Cloneable/Serializable don't have superinterfaces -- normally we'd have to
   // crawl up and explicitly list all of the supers as well.
-  array_iftable_->Set(0, AllocInterfaceEntry(self, java_lang_Cloneable));
-  array_iftable_->Set(1, AllocInterfaceEntry(self, java_io_Serializable));
+  array_iftable_->SetInterface(0, java_lang_Cloneable);
+  array_iftable_->SetInterface(1, java_io_Serializable);
 
   // Sanity check Class[] and Object[]'s interfaces.
   ClassHelper kh(class_array_class.get(), this);
@@ -1174,14 +1165,6 @@
   return dex_cache.get();
 }
 
-InterfaceEntry* ClassLinker::AllocInterfaceEntry(Thread* self, Class* interface) {
-  DCHECK(interface->IsInterface());
-  SirtRef<ObjectArray<Object> > array(self, AllocObjectArray<Object>(self, InterfaceEntry::LengthAsArray()));
-  SirtRef<InterfaceEntry> interface_entry(self, down_cast<InterfaceEntry*>(array.get()));
-  interface_entry->SetInterface(interface);
-  return interface_entry.get();
-}
-
 Class* ClassLinker::AllocClass(Thread* self, Class* java_lang_Class, size_t class_size) {
   DCHECK_GE(class_size, sizeof(Class));
   Heap* heap = Runtime::Current()->GetHeap();
@@ -1885,8 +1868,6 @@
       new_class.reset(GetClassRoot(kClassArrayClass));
     } else if (descriptor == "[Ljava/lang/Object;") {
       new_class.reset(GetClassRoot(kObjectArrayClass));
-    } else if (descriptor == "[[Ljava/lang/Object;") {
-      new_class.reset(GetClassRoot(kObjectArrayArrayClass));
     } else if (descriptor == class_roots_descriptors_[kJavaLangStringArrayClass]) {
       new_class.reset(GetClassRoot(kJavaLangStringArrayClass));
     } else if (descriptor == class_roots_descriptors_[kJavaLangReflectAbstractMethodArrayClass]) {
@@ -2683,12 +2664,12 @@
       }
     }
   }
+  IfTable* iftable = klass->GetIfTable();
   for (int32_t i = 0; i < klass->GetIfTableCount(); ++i) {
-    InterfaceEntry* interface_entry = klass->GetIfTable()->Get(i);
-    Class* interface = interface_entry->GetInterface();
+    Class* interface = iftable->GetInterface(i);
     if (klass->GetClassLoader() != interface->GetClassLoader()) {
       for (size_t j = 0; j < interface->NumVirtualMethods(); ++j) {
-        const AbstractMethod* method = interface_entry->GetMethodArray()->Get(j);
+        const AbstractMethod* method = iftable->GetMethodArray(i)->Get(j);
         if (!IsSameMethodSignatureInDifferentClassContexts(method, interface,
                                                            method->GetDeclaringClass())) {
           ThrowLinkageError("Class %s method %s resolves differently in interface %s",
@@ -3074,18 +3055,34 @@
     ifcount += interface->GetIfTableCount();
   }
   if (ifcount == 0) {
-    // TODO: enable these asserts with klass status validation
-    // DCHECK_EQ(klass->GetIfTableCount(), 0);
-    // DCHECK(klass->GetIfTable() == NULL);
+    // Class implements no interfaces.
+    DCHECK_EQ(klass->GetIfTableCount(), 0);
+    DCHECK(klass->GetIfTable() == NULL);
     return true;
   }
+  if (ifcount == super_ifcount) {
+    // Class implements same interfaces as parent, are any of these not marker interfaces?
+    bool has_non_marker_interface = false;
+    IfTable* super_iftable = klass->GetSuperClass()->GetIfTable();
+    for (size_t i = 0; i < ifcount; ++i) {
+      if (super_iftable->GetMethodArrayCount(i) > 0) {
+        has_non_marker_interface = true;
+        break;
+      }
+    }
+    if (!has_non_marker_interface) {
+      // Class just inherits marker interfaces from parent so recycle parent's iftable.
+      klass->SetIfTable(super_iftable);
+      return true;
+    }
+  }
   Thread* self = Thread::Current();
-  SirtRef<ObjectArray<InterfaceEntry> > iftable(self, AllocIfTable(self, ifcount));
+  SirtRef<IfTable> iftable(self, AllocIfTable(self, ifcount));
   if (super_ifcount != 0) {
-    ObjectArray<InterfaceEntry>* super_iftable = klass->GetSuperClass()->GetIfTable();
+    IfTable* super_iftable = klass->GetSuperClass()->GetIfTable();
     for (size_t i = 0; i < super_ifcount; i++) {
-      Class* super_interface = super_iftable->Get(i)->GetInterface();
-      iftable->Set(i, AllocInterfaceEntry(self, super_interface));
+      Class* super_interface = super_iftable->GetInterface(i);
+      iftable->SetInterface(i, super_interface);
     }
   }
   // Flatten the interface inheritance hierarchy.
@@ -3104,7 +3101,7 @@
     // Check if interface is already in iftable
     bool duplicate = false;
     for (size_t j = 0; j < idx; j++) {
-      Class* existing_interface = iftable->Get(j)->GetInterface();
+      Class* existing_interface = iftable->GetInterface(j);
       if (existing_interface == interface) {
         duplicate = true;
         break;
@@ -3112,27 +3109,27 @@
     }
     if (!duplicate) {
       // Add this non-duplicate interface.
-      iftable->Set(idx++, AllocInterfaceEntry(self, interface));
+      iftable->SetInterface(idx++, interface);
       // Add this interface's non-duplicate super-interfaces.
       for (int32_t j = 0; j < interface->GetIfTableCount(); j++) {
-        Class* super_interface = interface->GetIfTable()->Get(j)->GetInterface();
+        Class* super_interface = interface->GetIfTable()->GetInterface(j);
         bool super_duplicate = false;
         for (size_t k = 0; k < idx; k++) {
-          Class* existing_interface = iftable->Get(k)->GetInterface();
+          Class* existing_interface = iftable->GetInterface(k);
           if (existing_interface == super_interface) {
             super_duplicate = true;
             break;
           }
         }
         if (!super_duplicate) {
-          iftable->Set(idx++, AllocInterfaceEntry(self, super_interface));
+          iftable->SetInterface(idx++, super_interface);
         }
       }
     }
   }
   // Shrink iftable in case duplicates were found
   if (idx < ifcount) {
-    iftable.reset(iftable->CopyOf(self, idx));
+    iftable.reset(down_cast<IfTable*>(iftable->CopyOf(self, idx * IfTable::kMax)));
     ifcount = idx;
   } else {
     CHECK_EQ(idx, ifcount);
@@ -3140,60 +3137,62 @@
   klass->SetIfTable(iftable.get());
 
   // If we're an interface, we don't need the vtable pointers, so we're done.
-  if (klass->IsInterface() /*|| super_ifcount == ifcount*/) {
+  if (klass->IsInterface()) {
     return true;
   }
   std::vector<AbstractMethod*> miranda_list;
   MethodHelper vtable_mh(NULL, this);
   MethodHelper interface_mh(NULL, this);
   for (size_t i = 0; i < ifcount; ++i) {
-    InterfaceEntry* interface_entry = iftable->Get(i);
-    Class* interface = interface_entry->GetInterface();
-    ObjectArray<AbstractMethod>* method_array =
-        AllocMethodArray(self, interface->NumVirtualMethods());
-    interface_entry->SetMethodArray(method_array);
-    ObjectArray<AbstractMethod>* vtable = klass->GetVTableDuringLinking();
-    for (size_t j = 0; j < interface->NumVirtualMethods(); ++j) {
-      AbstractMethod* interface_method = interface->GetVirtualMethod(j);
-      interface_mh.ChangeMethod(interface_method);
-      int32_t k;
-      // For each method listed in the interface's method list, find the
-      // matching method in our class's method list.  We want to favor the
-      // subclass over the superclass, which just requires walking
-      // back from the end of the vtable.  (This only matters if the
-      // superclass defines a private method and this class redefines
-      // it -- otherwise it would use the same vtable slot.  In .dex files
-      // those don't end up in the virtual method table, so it shouldn't
-      // matter which direction we go.  We walk it backward anyway.)
-      for (k = vtable->GetLength() - 1; k >= 0; --k) {
-        AbstractMethod* vtable_method = vtable->Get(k);
-        vtable_mh.ChangeMethod(vtable_method);
-        if (interface_mh.HasSameNameAndSignature(&vtable_mh)) {
-          if (!vtable_method->IsPublic()) {
-            Thread::Current()->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
-                "Implementation not public: %s", PrettyMethod(vtable_method).c_str());
-            return false;
-          }
-          method_array->Set(j, vtable_method);
-          break;
-        }
-      }
-      if (k < 0) {
-        SirtRef<AbstractMethod> miranda_method(self, NULL);
-        for (size_t mir = 0; mir < miranda_list.size(); mir++) {
-          AbstractMethod* mir_method = miranda_list[mir];
-          vtable_mh.ChangeMethod(mir_method);
+    Class* interface = iftable->GetInterface(i);
+    size_t num_methods = interface->NumVirtualMethods();
+    if (num_methods > 0) {
+      ObjectArray<AbstractMethod>* method_array = AllocMethodArray(self, num_methods);
+      iftable->SetMethodArray(i, method_array);
+      ObjectArray<AbstractMethod>* vtable = klass->GetVTableDuringLinking();
+      for (size_t j = 0; j < interface->NumVirtualMethods(); ++j) {
+        AbstractMethod* interface_method = interface->GetVirtualMethod(j);
+        interface_mh.ChangeMethod(interface_method);
+        int32_t k;
+        // For each method listed in the interface's method list, find the
+        // matching method in our class's method list.  We want to favor the
+        // subclass over the superclass, which just requires walking
+        // back from the end of the vtable.  (This only matters if the
+        // superclass defines a private method and this class redefines
+        // it -- otherwise it would use the same vtable slot.  In .dex files
+        // those don't end up in the virtual method table, so it shouldn't
+        // matter which direction we go.  We walk it backward anyway.)
+        for (k = vtable->GetLength() - 1; k >= 0; --k) {
+          AbstractMethod* vtable_method = vtable->Get(k);
+          vtable_mh.ChangeMethod(vtable_method);
           if (interface_mh.HasSameNameAndSignature(&vtable_mh)) {
-            miranda_method.reset(miranda_list[mir]);
+            if (!vtable_method->IsPublic()) {
+              self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
+                                       "Implementation not public: %s",
+                                       PrettyMethod(vtable_method).c_str());
+              return false;
+            }
+            method_array->Set(j, vtable_method);
             break;
           }
         }
-        if (miranda_method.get() == NULL) {
-          // point the interface table at a phantom slot
-          miranda_method.reset(down_cast<AbstractMethod*>(interface_method->Clone(self)));
-          miranda_list.push_back(miranda_method.get());
+        if (k < 0) {
+          SirtRef<AbstractMethod> miranda_method(self, NULL);
+          for (size_t mir = 0; mir < miranda_list.size(); mir++) {
+            AbstractMethod* mir_method = miranda_list[mir];
+            vtable_mh.ChangeMethod(mir_method);
+            if (interface_mh.HasSameNameAndSignature(&vtable_mh)) {
+              miranda_method.reset(miranda_list[mir]);
+              break;
+            }
+          }
+          if (miranda_method.get() == NULL) {
+            // point the interface table at a phantom slot
+            miranda_method.reset(down_cast<AbstractMethod*>(interface_method->Clone(self)));
+            miranda_list.push_back(miranda_method.get());
+          }
+          method_array->Set(j, miranda_method.get());
         }
-        method_array->Set(j, miranda_method.get());
       }
     }
   }
diff --git a/src/class_linker.h b/src/class_linker.h
index fd404c1..096d602 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -337,9 +337,9 @@
         GetClassRoot(kJavaLangReflectMethodArrayClass), length);
   }
 
-  ObjectArray<InterfaceEntry>* AllocIfTable(Thread* self, size_t length)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return ObjectArray<InterfaceEntry>::Alloc(self, GetClassRoot(kObjectArrayArrayClass), length);
+  IfTable* AllocIfTable(Thread* self, size_t ifcount) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    return down_cast<IfTable*>(
+        IfTable::Alloc(self, GetClassRoot(kObjectArrayClass), ifcount * IfTable::kMax));
   }
 
   ObjectArray<Field>* AllocFieldArray(Thread* self, size_t length)
@@ -412,9 +412,6 @@
   Method* AllocMethod(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   Constructor* AllocConstructor(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  InterfaceEntry* AllocInterfaceEntry(Thread* self, Class* interface)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
   Class* CreatePrimitiveClass(Thread* self, Primitive::Type type)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     return InitializePrimitiveClass(AllocClass(self, sizeof(Class)), type);
@@ -574,7 +571,6 @@
     kJavaLangObject,
     kClassArrayClass,
     kObjectArrayClass,
-    kObjectArrayArrayClass,
     kJavaLangString,
     kJavaLangDexCache,
     kJavaLangRefReference,
@@ -637,7 +633,7 @@
     return descriptor;
   }
 
-  ObjectArray<InterfaceEntry>* array_iftable_;
+  IfTable* array_iftable_;
 
   bool init_done_;
 
diff --git a/src/class_linker_test.cc b/src/class_linker_test.cc
index 02512eb..1c41f3b 100644
--- a/src/class_linker_test.cc
+++ b/src/class_linker_test.cc
@@ -127,7 +127,7 @@
     EXPECT_EQ(2U, kh.NumDirectInterfaces());
     EXPECT_TRUE(array->GetVTable() != NULL);
     EXPECT_EQ(2, array->GetIfTableCount());
-    ObjectArray<InterfaceEntry>* iftable = array->GetIfTable();
+    IfTable* iftable = array->GetIfTable();
     ASSERT_TRUE(iftable != NULL);
     kh.ChangeClass(kh.GetDirectInterface(0));
     EXPECT_STREQ(kh.GetDescriptor(), "Ljava/lang/Cloneable;");
@@ -202,17 +202,14 @@
       }
     }
     EXPECT_EQ(klass->IsInterface(), klass->GetVTable() == NULL);
+    const IfTable* iftable = klass->GetIfTable();
     for (int i = 0; i < klass->GetIfTableCount(); i++) {
-      const InterfaceEntry* interface_entry = klass->GetIfTable()->Get(i);
-      ASSERT_TRUE(interface_entry != NULL);
-      Class* interface = interface_entry->GetInterface();
+      Class* interface = iftable->GetInterface(i);
       ASSERT_TRUE(interface != NULL);
-      EXPECT_TRUE(interface_entry->GetInterface() != NULL);
       if (klass->IsInterface()) {
-        EXPECT_EQ(0U, interface_entry->GetMethodArrayCount());
+        EXPECT_EQ(0U, iftable->GetMethodArrayCount(i));
       } else {
-        CHECK_EQ(interface->NumVirtualMethods(), interface_entry->GetMethodArrayCount());
-        EXPECT_EQ(interface->NumVirtualMethods(), interface_entry->GetMethodArrayCount());
+        EXPECT_EQ(interface->NumVirtualMethods(), iftable->GetMethodArrayCount(i));
       }
     }
     if (klass->IsAbstract()) {
diff --git a/src/object.cc b/src/object.cc
index e8381db..5fdea71 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -474,10 +474,9 @@
     } else {
       MethodHelper mh(this);
       MethodHelper interface_mh;
-      ObjectArray<InterfaceEntry>* iftable = GetDeclaringClass()->GetIfTable();
-      for (int32_t i = 0; i < iftable->GetLength() && result == NULL; i++) {
-        InterfaceEntry* entry = iftable->Get(i);
-        Class* interface = entry->GetInterface();
+      IfTable* iftable = GetDeclaringClass()->GetIfTable();
+      for (size_t i = 0; i < iftable->Count() && result == NULL; i++) {
+        Class* interface = iftable->GetInterface(i);
         for (size_t j = 0; j < interface->NumVirtualMethods(); ++j) {
           AbstractMethod* interface_method = interface->GetVirtualMethod(j);
           interface_mh.ChangeMethod(interface_method);
@@ -881,9 +880,9 @@
   // recursively all super-interfaces of those interfaces, are listed
   // in iftable_, so we can just do a linear scan through that.
   int32_t iftable_count = GetIfTableCount();
-  ObjectArray<InterfaceEntry>* iftable = GetIfTable();
+  IfTable* iftable = GetIfTable();
   for (int32_t i = 0; i < iftable_count; i++) {
-    if (iftable->Get(i)->GetInterface() == klass) {
+    if (iftable->GetInterface(i) == klass) {
       return true;
     }
   }
@@ -1007,11 +1006,10 @@
   DCHECK(declaring_class->IsInterface()) << PrettyMethod(method);
   // TODO cache to improve lookup speed
   int32_t iftable_count = GetIfTableCount();
-  ObjectArray<InterfaceEntry>* iftable = GetIfTable();
+  IfTable* iftable = GetIfTable();
   for (int32_t i = 0; i < iftable_count; i++) {
-    InterfaceEntry* interface_entry = iftable->Get(i);
-    if (interface_entry->GetInterface() == declaring_class) {
-      return interface_entry->GetMethodArray()->Get(method->GetMethodIndex());
+    if (iftable->GetInterface(i) == declaring_class) {
+      return iftable->GetMethodArray(i)->Get(method->GetMethodIndex());
     }
   }
   return NULL;
@@ -1025,9 +1023,9 @@
   }
 
   int32_t iftable_count = GetIfTableCount();
-  ObjectArray<InterfaceEntry>* iftable = GetIfTable();
+  IfTable* iftable = GetIfTable();
   for (int32_t i = 0; i < iftable_count; i++) {
-    method = iftable->Get(i)->GetInterface()->FindVirtualMethod(name, signature);
+    method = iftable->GetInterface(i)->FindVirtualMethod(name, signature);
     if (method != NULL) {
       return method;
     }
@@ -1043,9 +1041,9 @@
   }
 
   int32_t iftable_count = GetIfTableCount();
-  ObjectArray<InterfaceEntry>* iftable = GetIfTable();
+  IfTable* iftable = GetIfTable();
   for (int32_t i = 0; i < iftable_count; i++) {
-    method = iftable->Get(i)->GetInterface()->FindVirtualMethod(dex_cache, dex_method_idx);
+    method = iftable->GetInterface(i)->FindVirtualMethod(dex_cache, dex_method_idx);
     if (method != NULL) {
       return method;
     }
diff --git a/src/object.h b/src/object.h
index 1af30ea..43aed33 100644
--- a/src/object.h
+++ b/src/object.h
@@ -44,7 +44,7 @@
 class CodeAndDirectMethods;
 class DexCache;
 class Field;
-class InterfaceEntry;
+class IfTable;
 class Monitor;
 class Member;
 class AbstractMethod;
@@ -1173,6 +1173,57 @@
   return new_array;
 }
 
+class MANAGED IfTable : public ObjectArray<Object> {
+ public:
+  Class* GetInterface(int32_t i) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    Class* interface = Get((i * kMax) + kInterface)->AsClass();
+    DCHECK(interface != NULL);
+    return interface;
+  }
+
+  void SetInterface(int32_t i, Class* interface) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  ObjectArray<AbstractMethod>* GetMethodArray(int32_t i) const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    ObjectArray<AbstractMethod>* method_array =
+        down_cast<ObjectArray<AbstractMethod>*>(Get((i * kMax) + kMethodArray));
+    DCHECK(method_array != NULL);
+    return method_array;
+  }
+
+  size_t GetMethodArrayCount(int32_t i) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    ObjectArray<AbstractMethod>* method_array =
+        down_cast<ObjectArray<AbstractMethod>*>(Get((i * kMax) + kMethodArray));
+    if (method_array == NULL) {
+      return 0;
+    }
+    return method_array->GetLength();
+  }
+
+  void SetMethodArray(int32_t i, ObjectArray<AbstractMethod>* new_ma)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    DCHECK(new_ma != NULL);
+    DCHECK(Get((i * kMax) + kMethodArray) == NULL);
+    Set((i * kMax) + kMethodArray, new_ma);
+  }
+
+  size_t Count() const {
+    return GetLength() / kMax;
+  }
+
+  enum {
+    // Points to the interface class.
+    kInterface   = 0,
+    // Method pointers into the vtable, allow fast map from interface method index to concrete
+    // instance method.
+    kMethodArray = 1,
+    kMax         = 2,
+  };
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(IfTable);
+};
+
 // Type for the InitializedStaticStorage table. Currently the Class
 // provides the static storage. However, this might change to an Array
 // to improve image sharing, so we use this type to avoid assumptions
@@ -1746,20 +1797,18 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   int32_t GetIfTableCount() const {
-    ObjectArray<InterfaceEntry>* iftable = GetIfTable();
+    IfTable* iftable = GetIfTable();
     if (iftable == NULL) {
       return 0;
     }
-    return iftable->GetLength();
+    return iftable->Count();
   }
 
-  ObjectArray<InterfaceEntry>* GetIfTable() const {
-    DCHECK(IsResolved() || IsErroneous());
-    return GetFieldObject<ObjectArray<InterfaceEntry>*>(
-        OFFSET_OF_OBJECT_MEMBER(Class, iftable_), false);
+  IfTable* GetIfTable() const {
+    return GetFieldObject<IfTable*>(OFFSET_OF_OBJECT_MEMBER(Class, iftable_), false);
   }
 
-  void SetIfTable(ObjectArray<InterfaceEntry>* new_iftable)
+  void SetIfTable(IfTable* new_iftable)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, iftable_), new_iftable, false);
   }
@@ -1970,20 +2019,18 @@
   // specifies the number of reference fields.
   ObjectArray<Field>* ifields_;
 
-  // Interface table (iftable_), one entry per interface supported by
-  // this class.  That means one entry for each interface we support
-  // directly, indirectly via superclass, or indirectly via
-  // superinterface.  This will be null if neither we nor our
-  // superclass implement any interfaces.
+  // The interface table (iftable_) contains pairs of a interface class and an array of the
+  // interface methods. There is one pair per interface supported by this class.  That means one
+  // pair for each interface we support directly, indirectly via superclass, or indirectly via a
+  // superinterface.  This will be null if neither we nor our superclass implement any interfaces.
   //
-  // Why we need this: given "class Foo implements Face", declare
-  // "Face faceObj = new Foo()".  Invoke faceObj.blah(), where "blah"
-  // is part of the Face interface.  We can't easily use a single
-  // vtable.
+  // Why we need this: given "class Foo implements Face", declare "Face faceObj = new Foo()".
+  // Invoke faceObj.blah(), where "blah" is part of the Face interface.  We can't easily use a
+  // single vtable.
   //
-  // For every interface a concrete class implements, we create an array
-  // of the concrete vtable_ methods for the methods in the interface.
-  ObjectArray<InterfaceEntry>* iftable_;
+  // For every interface a concrete class implements, we create an array of the concrete vtable_
+  // methods for the methods in the interface.
+  IfTable* iftable_;
 
   // descriptor for the class such as "java.lang.Class" or "[C". Lazily initialized by ComputeName
   String* name_;
@@ -2246,6 +2293,13 @@
   }
 }
 
+inline void IfTable::SetInterface(int32_t i, Class* interface) {
+  DCHECK(interface != NULL);
+  DCHECK(interface->IsInterface());
+  DCHECK(Get((i * kMax) + kInterface) == NULL);
+  Set((i * kMax) + kInterface, interface);
+}
+
 class MANAGED ClassClass : public Class {
  private:
   int32_t padding_;
@@ -2648,60 +2702,6 @@
   DISALLOW_IMPLICIT_CONSTRUCTORS(StackTraceElement);
 };
 
-class MANAGED InterfaceEntry : public ObjectArray<Object> {
- public:
-  Class* GetInterface() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    Class* interface = Get(kInterface)->AsClass();
-    DCHECK(interface != NULL);
-    return interface;
-  }
-
-  void SetInterface(Class* interface) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    DCHECK(interface != NULL);
-    DCHECK(interface->IsInterface());
-    DCHECK(Get(kInterface) == NULL);
-    Set(kInterface, interface);
-  }
-
-  size_t GetMethodArrayCount() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    ObjectArray<AbstractMethod>* method_array = down_cast<ObjectArray<AbstractMethod>*>(Get(kMethodArray));
-    if (method_array == NULL) {
-      return 0;
-    }
-    return method_array->GetLength();
-  }
-
-  ObjectArray<AbstractMethod>* GetMethodArray() const
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    ObjectArray<AbstractMethod>* method_array = down_cast<ObjectArray<AbstractMethod>*>(Get(kMethodArray));
-    DCHECK(method_array != NULL);
-    return method_array;
-  }
-
-  void SetMethodArray(ObjectArray<AbstractMethod>* new_ma)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    DCHECK(new_ma != NULL);
-    DCHECK(Get(kMethodArray) == NULL);
-    Set(kMethodArray, new_ma);
-  }
-
-  static size_t LengthAsArray() {
-    return kMax;
-  }
-
- private:
-  enum {
-    // Points to the interface class.
-    kInterface   = 0,
-    // Method pointers into the vtable, allow fast map from interface
-    // method index to concrete instance method.
-    kMethodArray = 1,
-    kMax         = 2,
-  };
-
-  DISALLOW_IMPLICIT_CONSTRUCTORS(InterfaceEntry);
-};
-
 class MANAGED SynthesizedProxyClass : public Class {
  public:
   ObjectArray<Class>* GetInterfaces() {
diff --git a/src/object_utils.h b/src/object_utils.h
index 1bbb7bc..c6e71c3 100644
--- a/src/object_utils.h
+++ b/src/object_utils.h
@@ -169,7 +169,7 @@
         return GetClassLinker()->FindSystemClass("Ljava/io/Serializable;");
       }
     } else if (klass_->IsProxyClass()) {
-      return klass_->GetIfTable()->Get(idx)->GetInterface();
+      return klass_->GetIfTable()->GetInterface(idx);
     } else {
       uint16_t type_idx = GetDirectInterfaceTypeIdx(idx);
       Class* interface = GetDexCache()->GetResolvedType(type_idx);