Handle interface methods in JNI invocation

Change-Id: I7c9d25177fc6fdf9512beb2a882969a9aaf835ba
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 2f1a5d7..7a93d48 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -201,8 +201,8 @@
   // supers as well.  These interfaces don't have any methods, so we
   // don't have to worry about the ifviPool either.
   array_iftable_ = new InterfaceEntry[2];
-  array_iftable_[0].SetClass(array_interfaces_->Get(0));
-  array_iftable_[1].SetClass(array_interfaces_->Get(1));
+  array_iftable_[0].SetInterface(array_interfaces_->Get(0));
+  array_iftable_[1].SetInterface(array_interfaces_->Get(1));
   // now FindClass can be used for non-primitive array classes
 
   // run Object[] through FindClass to complete initialization
@@ -1153,7 +1153,7 @@
   }
   for (size_t i = 0; i < klass->iftable_count_; ++i) {
     const InterfaceEntry* iftable = &klass->iftable_[i];
-    Class* interface = iftable->GetClass();
+    Class* interface = iftable->GetInterface();
     if (klass->GetClassLoader() != interface->GetClassLoader()) {
       for (size_t j = 0; j < interface->NumVirtualMethods(); ++j) {
         uint32_t vtable_index = iftable->method_index_array_[j];
@@ -1517,9 +1517,9 @@
       LG << "Class implements non-interface class";  // TODO: IncompatibleClassChangeError
       return false;
     }
-    klass->iftable_[idx++].SetClass(interf);
+    klass->iftable_[idx++].SetInterface(interf);
     for (size_t j = 0; j < interf->iftable_count_; j++) {
-      klass->iftable_[idx++].SetClass(interf->iftable_[j].GetClass());
+      klass->iftable_[idx++].SetInterface(interf->iftable_[j].GetInterface());
     }
   }
   CHECK_EQ(idx, ifcount);
@@ -1528,7 +1528,7 @@
     return true;
   }
   for (size_t i = super_ifcount; i < ifcount; i++) {
-    pool_size += klass->iftable_[i].GetClass()->NumVirtualMethods();
+    pool_size += klass->iftable_[i].GetInterface()->NumVirtualMethods();
   }
   if (pool_size == 0) {
     return true;
@@ -1538,7 +1538,7 @@
   std::vector<Method*> miranda_list;
   for (size_t i = super_ifcount; i < ifcount; ++i) {
     klass->iftable_[i].method_index_array_ = klass->ifvi_pool_ + pool_offset;
-    Class* interface = klass->iftable_[i].GetClass();
+    Class* interface = klass->iftable_[i].GetInterface();
     pool_offset += interface->NumVirtualMethods();    // end here
     for (size_t j = 0; j < interface->NumVirtualMethods(); ++j) {
       Method* interface_method = interface->GetVirtualMethod(j);
diff --git a/src/class_linker_test.cc b/src/class_linker_test.cc
index b5c03fb..9e96439 100644
--- a/src/class_linker_test.cc
+++ b/src/class_linker_test.cc
@@ -516,4 +516,37 @@
   EXPECT_TRUE(s8->GetObject(NULL)->AsString()->Equals("robot"));
 }
 
+TEST_F(ClassLinkerTest, Interfaces) {
+  scoped_ptr<DexFile> dex(OpenDexFileBase64(kInterfacesDex, "kInterfacesDex"));
+  PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
+  Class* I = class_linker_->FindClass("LInterfaces$I;", class_loader);
+  Class* J = class_linker_->FindClass("LInterfaces$J;", class_loader);
+  Class* A = class_linker_->FindClass("LInterfaces$A;", class_loader);
+  EXPECT_TRUE(I->IsAssignableFrom(A));
+  EXPECT_TRUE(J->IsAssignableFrom(A));
+
+  Method* Ii = I->FindVirtualMethod("i", "()V");
+  Method* Jj1 = J->FindVirtualMethod("j1", "()V");
+  Method* Jj2 = J->FindVirtualMethod("j2", "()V");
+  Method* Ai = A->FindVirtualMethod("i", "()V");
+  Method* Aj1 = A->FindVirtualMethod("j1", "()V");
+  Method* Aj2 = A->FindVirtualMethod("j2", "()V");
+  ASSERT_TRUE(Ii != NULL);
+  ASSERT_TRUE(Jj1 != NULL);
+  ASSERT_TRUE(Jj2 != NULL);
+  ASSERT_TRUE(Ai != NULL);
+  ASSERT_TRUE(Aj1 != NULL);
+  ASSERT_TRUE(Aj2 != NULL);
+  ASSERT_TRUE(Ii != NULL);
+  EXPECT_NE(Ii, Ai);
+  EXPECT_NE(Jj1, Aj1);
+  EXPECT_NE(Jj2, Aj2);
+  EXPECT_EQ(Ai, A->FindVirtualMethodForInterface(Ii));
+  EXPECT_EQ(Aj1, A->FindVirtualMethodForInterface(Jj1));
+  EXPECT_EQ(Aj2, A->FindVirtualMethodForInterface(Jj2));
+  EXPECT_EQ(Ai, A->FindVirtualMethodForVirtualOrInterface(Ii));
+  EXPECT_EQ(Aj1, A->FindVirtualMethodForVirtualOrInterface(Jj1));
+  EXPECT_EQ(Aj2, A->FindVirtualMethodForVirtualOrInterface(Jj2));
+}
+
 }  // namespace art
diff --git a/src/common_test.h b/src/common_test.h
index 1b0404e..e56a3a0 100644
--- a/src/common_test.h
+++ b/src/common_test.h
@@ -349,30 +349,69 @@
 //    }
 //}
 static const char kFibonacciDex[] =
-"ZGV4CjAzNQBaslnMUQxaXYgC3gD9FGHjVb8cHZ60G8ckBQAAcAAAAHhWNBIAAAAAAAAAAIQEAAAa"
-"AAAAcAAAAAsAAADYAAAABgAAAAQBAAABAAAATAEAAAcAAABUAQAAAgAAAIwBAABYAwAAzAEAAPoC"
-"AAACAwAAEgMAABUDAAAZAwAAHQMAACoDAAAuAwAAMwMAAEoDAABfAwAAggMAAJYDAACqAwAAvgMA"
-"AMsDAADOAwAA0gMAAOcDAAD8AwAABwQAABoEAAAgBAAAJQQAAC8EAAA3BAAAAgAAAAUAAAAIAAAA"
-"CQAAAAoAAAALAAAADAAAAA0AAAAPAAAAEQAAABIAAAADAAAAAAAAANwCAAAEAAAAAAAAAOQCAAAH"
-"AAAAAgAAAOwCAAAGAAAAAwAAANwCAAAPAAAACAAAAAAAAAAQAAAACAAAAPQCAAAHAAIAFgAAAAEA"
-"BAAAAAAAAQAAABMAAAABAAUAFQAAAAIAAgAYAAAAAwABABcAAAADAAMAGQAAAAUABAAAAAAABQAA"
-"AAEAAAD/////AAAAAA4AAAAAAAAAaAQAAAAAAAABAAAAAAAAAAUAAAAAAAAAAQAAAAAAAAByBAAA"
-"AAAAAAEAAQAAAAAAQAQAAAEAAAAOAAAAAQABAAEAAABFBAAABAAAAHAQBgAAAA4ABQABAAAAAABK"
-"BAAAEwAAABIROQQEABIADwASMAESARMBAQEwNkH6/7AC2AEBAQEjAQIBMCj4AAAIAAEAAwABAFcE"
-"AABIAAAAEhEhcDMQQwASAEYABwBxEAQAAAAKAHEQAQAAAAoBYgIAABoDFAASJCNECQASBXEQBQAA"
-"AAwGTQYEBRIVcRAFAAEADAFNAQQFbjADADIE2AEAAXEQAQABAAoBYgIAABoDFAASJCNECQASBXEQ"
-"BQAAAAwATQAEBRIQcRAFAAEADAFNAQQAbjADADIEDgANACj+AQAAAEQAAQABAQRGAQAAAAAAAAAB"
-"AAAABgAAAAIAAAAGAAkAAQAAAAoABjxpbml0PgAORmlib25hY2NpLmphdmEAAUkAAklJAAJJTAAL"
-"TEZpYm9uYWNjaTsAAkxJAANMTEwAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwATTGphdmEvbGFuZy9J"
-"bnRlZ2VyOwAhTGphdmEvbGFuZy9OdW1iZXJGb3JtYXRFeGNlcHRpb247ABJMamF2YS9sYW5nL09i"
-"amVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEvbGFuZy9TeXN0ZW07AAtPYmplY3QuamF2"
-"YQABVgACVkwAE1tMamF2YS9sYW5nL09iamVjdDsAE1tMamF2YS9sYW5nL1N0cmluZzsACWZpYm9u"
-"YWNjaQARZmlib25hY2NpKCVkKT0lZAoABG1haW4AA291dAAIcGFyc2VJbnQABnByaW50ZgAHdmFs"
-"dWVPZgADAAcOAAEABw4ADwEABx0tJgJ7HXgcAB4BAAcdPHhLARgPaQEYERwAAAABAAaBgATMAwAA"
-"AwAAgIAE4AMBCPgDAQmwBA0AAAAAAAAAAQAAAAAAAAABAAAAGgAAAHAAAAACAAAACwAAANgAAAAD"
-"AAAABgAAAAQBAAAEAAAAAQAAAEwBAAAFAAAABwAAAFQBAAAGAAAAAgAAAIwBAAABIAAABAAAAMwB"
-"AAABEAAABAAAANwCAAACIAAAGgAAAPoCAAADIAAABAAAAEAEAAAAIAAAAgAAAGgEAAAAEAAAAQAA"
-"AIQEAAA=";
+  "ZGV4CjAzNQBaslnMUQxaXYgC3gD9FGHjVb8cHZ60G8ckBQAAcAAAAHhWNBIAAAAAAAAAAIQEAAAa"
+  "AAAAcAAAAAsAAADYAAAABgAAAAQBAAABAAAATAEAAAcAAABUAQAAAgAAAIwBAABYAwAAzAEAAPoC"
+  "AAACAwAAEgMAABUDAAAZAwAAHQMAACoDAAAuAwAAMwMAAEoDAABfAwAAggMAAJYDAACqAwAAvgMA"
+  "AMsDAADOAwAA0gMAAOcDAAD8AwAABwQAABoEAAAgBAAAJQQAAC8EAAA3BAAAAgAAAAUAAAAIAAAA"
+  "CQAAAAoAAAALAAAADAAAAA0AAAAPAAAAEQAAABIAAAADAAAAAAAAANwCAAAEAAAAAAAAAOQCAAAH"
+  "AAAAAgAAAOwCAAAGAAAAAwAAANwCAAAPAAAACAAAAAAAAAAQAAAACAAAAPQCAAAHAAIAFgAAAAEA"
+  "BAAAAAAAAQAAABMAAAABAAUAFQAAAAIAAgAYAAAAAwABABcAAAADAAMAGQAAAAUABAAAAAAABQAA"
+  "AAEAAAD/////AAAAAA4AAAAAAAAAaAQAAAAAAAABAAAAAAAAAAUAAAAAAAAAAQAAAAAAAAByBAAA"
+  "AAAAAAEAAQAAAAAAQAQAAAEAAAAOAAAAAQABAAEAAABFBAAABAAAAHAQBgAAAA4ABQABAAAAAABK"
+  "BAAAEwAAABIROQQEABIADwASMAESARMBAQEwNkH6/7AC2AEBAQEjAQIBMCj4AAAIAAEAAwABAFcE"
+  "AABIAAAAEhEhcDMQQwASAEYABwBxEAQAAAAKAHEQAQAAAAoBYgIAABoDFAASJCNECQASBXEQBQAA"
+  "AAwGTQYEBRIVcRAFAAEADAFNAQQFbjADADIE2AEAAXEQAQABAAoBYgIAABoDFAASJCNECQASBXEQ"
+  "BQAAAAwATQAEBRIQcRAFAAEADAFNAQQAbjADADIEDgANACj+AQAAAEQAAQABAQRGAQAAAAAAAAAB"
+  "AAAABgAAAAIAAAAGAAkAAQAAAAoABjxpbml0PgAORmlib25hY2NpLmphdmEAAUkAAklJAAJJTAAL"
+  "TEZpYm9uYWNjaTsAAkxJAANMTEwAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwATTGphdmEvbGFuZy9J"
+  "bnRlZ2VyOwAhTGphdmEvbGFuZy9OdW1iZXJGb3JtYXRFeGNlcHRpb247ABJMamF2YS9sYW5nL09i"
+  "amVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEvbGFuZy9TeXN0ZW07AAtPYmplY3QuamF2"
+  "YQABVgACVkwAE1tMamF2YS9sYW5nL09iamVjdDsAE1tMamF2YS9sYW5nL1N0cmluZzsACWZpYm9u"
+  "YWNjaQARZmlib25hY2NpKCVkKT0lZAoABG1haW4AA291dAAIcGFyc2VJbnQABnByaW50ZgAHdmFs"
+  "dWVPZgADAAcOAAEABw4ADwEABx0tJgJ7HXgcAB4BAAcdPHhLARgPaQEYERwAAAABAAaBgATMAwAA"
+  "AwAAgIAE4AMBCPgDAQmwBA0AAAAAAAAAAQAAAAAAAAABAAAAGgAAAHAAAAACAAAACwAAANgAAAAD"
+  "AAAABgAAAAQBAAAEAAAAAQAAAEwBAAAFAAAABwAAAFQBAAAGAAAAAgAAAIwBAAABIAAABAAAAMwB"
+  "AAABEAAABAAAANwCAAACIAAAGgAAAPoCAAADIAAABAAAAEAEAAAAIAAAAgAAAGgEAAAAEAAAAQAA"
+  "AIQEAAA=";
+
+// class Interfaces {
+//   interface I {
+//     public void i();
+//   }
+//   interface J {
+//     public void j1();
+//     public void j2();
+//   }
+//   class A implements I, J {
+//     public void i() {};
+//     public void j1() {};
+//     public void j2() {};
+//   }
+// }
+static const char kInterfacesDex[] =
+  "ZGV4CjAzNQCRmX4RyqEIAGU0Pzgm7w3FvyUvYlel/coUBQAAcAAAAHhWNBIAAAAAAAAAAFAEAAAW"
+  "AAAAcAAAAAkAAADIAAAAAgAAAOwAAAABAAAABAEAAAkAAAAMAQAABAAAAFQBAABAAwAA1AEAAL4C"
+  "AADGAgAAyQIAAMwCAADdAgAA4AIAAPACAAAAAwAAEAMAAB4DAABCAwAAYgMAAIUDAACZAwAAnAMA"
+  "AKADAACtAwAAsAMAALQDAAC4AwAAvgMAAMYDAAAFAAAABgAAAAcAAAAIAAAACQAAAAoAAAALAAAA"
+  "DAAAAA0AAAANAAAACAAAAAAAAAAOAAAACAAAALgCAAAAAAMAFAAAAAAAAQAAAAAAAAAAABAAAAAA"
+  "AAAAEQAAAAAAAAASAAAAAQAAABAAAAACAAAAEQAAAAIAAAASAAAAAwAAAAAAAAAHAAAAAAAAAAEA"
+  "AAAABgAABwAAAAAAAAADAAAAcAIAABcEAAAAAAAAAgAAAAAGAAAHAAAAAAAAAAMAAACAAgAAHwQA"
+  "AAAAAAAAAAAAAAAAAAcAAACwAgAAAwAAAJACAAArBAAAAAAAAAMAAAAAAAAABwAAAAAAAAADAAAA"
+  "oAIAAEQEAAAAAAAAAgAAAOgDAADuAwAAAgAAAOgDAAD4AwAAAgAAAOgDAAACBAAAAQAAAAsEAAAC"
+  "AAIAAQAAAM0DAAAGAAAAWwEAAHAQCAAAAA4AAQABAAAAAADTAwAAAQAAAA4AAAABAAEAAAAAANgD"
+  "AAABAAAADgAAAAEAAQAAAAAA3QMAAAEAAAAOAAAAAQABAAEAAADiAwAABAAAAHAQCAAAAA4A1AEA"
+  "AAAAAAAAAAAAAAAAAOABAAAAAAAAAAAAAAAAAADsAQAAAAAAAAAAAAAAAAAA+AEAAAAAAAAAAAAA"
+  "AAAAAAIAAAABAAIAAQAAAAMABjxpbml0PgABQQABSQAPSW50ZXJmYWNlcy5qYXZhAAFKAA5MSW50"
+  "ZXJmYWNlcyRBOwAOTEludGVyZmFjZXMkSTsADkxJbnRlcmZhY2VzJEo7AAxMSW50ZXJmYWNlczsA"
+  "IkxkYWx2aWsvYW5ub3RhdGlvbi9FbmNsb3NpbmdDbGFzczsAHkxkYWx2aWsvYW5ub3RhdGlvbi9J"
+  "bm5lckNsYXNzOwAhTGRhbHZpay9hbm5vdGF0aW9uL01lbWJlckNsYXNzZXM7ABJMamF2YS9sYW5n"
+  "L09iamVjdDsAAVYAAlZMAAthY2Nlc3NGbGFncwABaQACajEAAmoyAARuYW1lAAZ0aGlzJDAABXZh"
+  "bHVlAAoBAAcOAAsABw4ADAAHDgANAAcOAAIABw5DAAIEARUYAwIFAg8kCAYTFwICBQIPJAgGExcE"
+  "AgUCDwQAExcBAgYBFRwDGAAYAhgBAAAAAQSBCAAAAAACBYEIAAGBCAAAAQEDAJAgAICABIAEAQGc"
+  "BAEBsAQBAcQEAAABAAeAgATYBAAAEAAAAAAAAAABAAAAAAAAAAEAAAAWAAAAcAAAAAIAAAAJAAAA"
+  "yAAAAAMAAAACAAAA7AAAAAQAAAABAAAABAEAAAUAAAAJAAAADAEAAAYAAAAEAAAAVAEAAAMQAAAE"
+  "AAAA1AEAAAEgAAAFAAAAAAIAAAYgAAAEAAAAcAIAAAEQAAACAAAAsAIAAAIgAAAWAAAAvgIAAAMg"
+  "AAAFAAAAzQMAAAQgAAAFAAAA6AMAAAAgAAAEAAAAFwQAAAAQAAABAAAAUAQAAA==";
 
 static inline DexFile* OpenDexFileBase64(const char* base64,
                                          const std::string& location) {
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index 89519c4..0d7b256 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -293,17 +293,17 @@
 }
 
 Method* FindVirtualMethod(Object* receiver, Method* method) {
-  return receiver->GetClass()->GetMethodByVtableIndex(method->GetVtableIndex());
+  return receiver->GetClass()->FindVirtualMethodForVirtualOrInterface(method);
 }
 
-JValue InvokeVirtualWithJValues(ScopedJniThreadState& ts, jobject obj, jmethodID mid, jvalue* args) {
+JValue InvokeVirtualOrInterfaceWithJValues(ScopedJniThreadState& ts, jobject obj, jmethodID mid, jvalue* args) {
   Object* receiver = Decode<Object*>(ts, obj);
   Method* method = FindVirtualMethod(receiver, DecodeMethod(ts, mid));
   scoped_array<byte> arg_array(CreateArgArray(ts, method, args));
   return InvokeWithArgArray(ts, receiver, method, arg_array.get());
 }
 
-JValue InvokeVirtualWithVarArgs(ScopedJniThreadState& ts, jobject obj, jmethodID mid, va_list args) {
+JValue InvokeVirtualOrInterfaceWithVarArgs(ScopedJniThreadState& ts, jobject obj, jmethodID mid, va_list args) {
   Object* receiver = Decode<Object*>(ts, obj);
   Method* method = FindVirtualMethod(receiver, DecodeMethod(ts, mid));
   scoped_array<byte> arg_array(CreateArgArray(ts, method, args));
@@ -1001,20 +1001,20 @@
     ScopedJniThreadState ts(env);
     va_list ap;
     va_start(ap, mid);
-    JValue result = InvokeVirtualWithVarArgs(ts, obj, mid, ap);
+    JValue result = InvokeVirtualOrInterfaceWithVarArgs(ts, obj, mid, ap);
     va_end(ap);
     return AddLocalReference<jobject>(ts, result.l);
   }
 
   static jobject CallObjectMethodV(JNIEnv* env, jobject obj, jmethodID mid, va_list args) {
     ScopedJniThreadState ts(env);
-    JValue result = InvokeVirtualWithVarArgs(ts, obj, mid, args);
+    JValue result = InvokeVirtualOrInterfaceWithVarArgs(ts, obj, mid, args);
     return AddLocalReference<jobject>(ts, result.l);
   }
 
   static jobject CallObjectMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
     ScopedJniThreadState ts(env);
-    JValue result = InvokeVirtualWithJValues(ts, obj, mid, args);
+    JValue result = InvokeVirtualOrInterfaceWithJValues(ts, obj, mid, args);
     return AddLocalReference<jobject>(ts, result.l);
   }
 
@@ -1022,170 +1022,170 @@
     ScopedJniThreadState ts(env);
     va_list ap;
     va_start(ap, mid);
-    JValue result = InvokeVirtualWithVarArgs(ts, obj, mid, ap);
+    JValue result = InvokeVirtualOrInterfaceWithVarArgs(ts, obj, mid, ap);
     va_end(ap);
     return result.z;
   }
 
   static jboolean CallBooleanMethodV(JNIEnv* env, jobject obj, jmethodID mid, va_list args) {
     ScopedJniThreadState ts(env);
-    return InvokeVirtualWithVarArgs(ts, obj, mid, args).z;
+    return InvokeVirtualOrInterfaceWithVarArgs(ts, obj, mid, args).z;
   }
 
   static jboolean CallBooleanMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
     ScopedJniThreadState ts(env);
-    return InvokeVirtualWithJValues(ts, obj, mid, args).z;
+    return InvokeVirtualOrInterfaceWithJValues(ts, obj, mid, args).z;
   }
 
   static jbyte CallByteMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
     ScopedJniThreadState ts(env);
     va_list ap;
     va_start(ap, mid);
-    JValue result = InvokeVirtualWithVarArgs(ts, obj, mid, ap);
+    JValue result = InvokeVirtualOrInterfaceWithVarArgs(ts, obj, mid, ap);
     va_end(ap);
     return result.b;
   }
 
   static jbyte CallByteMethodV(JNIEnv* env, jobject obj, jmethodID mid, va_list args) {
     ScopedJniThreadState ts(env);
-    return InvokeVirtualWithVarArgs(ts, obj, mid, args).b;
+    return InvokeVirtualOrInterfaceWithVarArgs(ts, obj, mid, args).b;
   }
 
   static jbyte CallByteMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
     ScopedJniThreadState ts(env);
-    return InvokeVirtualWithJValues(ts, obj, mid, args).b;
+    return InvokeVirtualOrInterfaceWithJValues(ts, obj, mid, args).b;
   }
 
   static jchar CallCharMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
     ScopedJniThreadState ts(env);
     va_list ap;
     va_start(ap, mid);
-    JValue result = InvokeVirtualWithVarArgs(ts, obj, mid, ap);
+    JValue result = InvokeVirtualOrInterfaceWithVarArgs(ts, obj, mid, ap);
     va_end(ap);
     return result.c;
   }
 
   static jchar CallCharMethodV(JNIEnv* env, jobject obj, jmethodID mid, va_list args) {
     ScopedJniThreadState ts(env);
-    return InvokeVirtualWithVarArgs(ts, obj, mid, args).c;
+    return InvokeVirtualOrInterfaceWithVarArgs(ts, obj, mid, args).c;
   }
 
   static jchar CallCharMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
     ScopedJniThreadState ts(env);
-    return InvokeVirtualWithJValues(ts, obj, mid, args).c;
+    return InvokeVirtualOrInterfaceWithJValues(ts, obj, mid, args).c;
   }
 
   static jdouble CallDoubleMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
     ScopedJniThreadState ts(env);
     va_list ap;
     va_start(ap, mid);
-    JValue result = InvokeVirtualWithVarArgs(ts, obj, mid, ap);
+    JValue result = InvokeVirtualOrInterfaceWithVarArgs(ts, obj, mid, ap);
     va_end(ap);
     return result.d;
   }
 
   static jdouble CallDoubleMethodV(JNIEnv* env, jobject obj, jmethodID mid, va_list args) {
     ScopedJniThreadState ts(env);
-    return InvokeVirtualWithVarArgs(ts, obj, mid, args).d;
+    return InvokeVirtualOrInterfaceWithVarArgs(ts, obj, mid, args).d;
   }
 
   static jdouble CallDoubleMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
     ScopedJniThreadState ts(env);
-    return InvokeVirtualWithJValues(ts, obj, mid, args).d;
+    return InvokeVirtualOrInterfaceWithJValues(ts, obj, mid, args).d;
   }
 
   static jfloat CallFloatMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
     ScopedJniThreadState ts(env);
     va_list ap;
     va_start(ap, mid);
-    JValue result = InvokeVirtualWithVarArgs(ts, obj, mid, ap);
+    JValue result = InvokeVirtualOrInterfaceWithVarArgs(ts, obj, mid, ap);
     va_end(ap);
     return result.f;
   }
 
   static jfloat CallFloatMethodV(JNIEnv* env, jobject obj, jmethodID mid, va_list args) {
     ScopedJniThreadState ts(env);
-    return InvokeVirtualWithVarArgs(ts, obj, mid, args).f;
+    return InvokeVirtualOrInterfaceWithVarArgs(ts, obj, mid, args).f;
   }
 
   static jfloat CallFloatMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
     ScopedJniThreadState ts(env);
-    return InvokeVirtualWithJValues(ts, obj, mid, args).f;
+    return InvokeVirtualOrInterfaceWithJValues(ts, obj, mid, args).f;
   }
 
   static jint CallIntMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
     ScopedJniThreadState ts(env);
     va_list ap;
     va_start(ap, mid);
-    JValue result = InvokeVirtualWithVarArgs(ts, obj, mid, ap);
+    JValue result = InvokeVirtualOrInterfaceWithVarArgs(ts, obj, mid, ap);
     va_end(ap);
     return result.i;
   }
 
   static jint CallIntMethodV(JNIEnv* env, jobject obj, jmethodID mid, va_list args) {
     ScopedJniThreadState ts(env);
-    return InvokeVirtualWithVarArgs(ts, obj, mid, args).i;
+    return InvokeVirtualOrInterfaceWithVarArgs(ts, obj, mid, args).i;
   }
 
   static jint CallIntMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
     ScopedJniThreadState ts(env);
-    return InvokeVirtualWithJValues(ts, obj, mid, args).i;
+    return InvokeVirtualOrInterfaceWithJValues(ts, obj, mid, args).i;
   }
 
   static jlong CallLongMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
     ScopedJniThreadState ts(env);
     va_list ap;
     va_start(ap, mid);
-    JValue result = InvokeVirtualWithVarArgs(ts, obj, mid, ap);
+    JValue result = InvokeVirtualOrInterfaceWithVarArgs(ts, obj, mid, ap);
     va_end(ap);
     return result.j;
   }
 
   static jlong CallLongMethodV(JNIEnv* env, jobject obj, jmethodID mid, va_list args) {
     ScopedJniThreadState ts(env);
-    return InvokeVirtualWithVarArgs(ts, obj, mid, args).j;
+    return InvokeVirtualOrInterfaceWithVarArgs(ts, obj, mid, args).j;
   }
 
   static jlong CallLongMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
     ScopedJniThreadState ts(env);
-    return InvokeVirtualWithJValues(ts, obj, mid, args).j;
+    return InvokeVirtualOrInterfaceWithJValues(ts, obj, mid, args).j;
   }
 
   static jshort CallShortMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
     ScopedJniThreadState ts(env);
     va_list ap;
     va_start(ap, mid);
-    JValue result = InvokeVirtualWithVarArgs(ts, obj, mid, ap);
+    JValue result = InvokeVirtualOrInterfaceWithVarArgs(ts, obj, mid, ap);
     va_end(ap);
     return result.s;
   }
 
   static jshort CallShortMethodV(JNIEnv* env, jobject obj, jmethodID mid, va_list args) {
     ScopedJniThreadState ts(env);
-    return InvokeVirtualWithVarArgs(ts, obj, mid, args).s;
+    return InvokeVirtualOrInterfaceWithVarArgs(ts, obj, mid, args).s;
   }
 
   static jshort CallShortMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
     ScopedJniThreadState ts(env);
-    return InvokeVirtualWithJValues(ts, obj, mid, args).s;
+    return InvokeVirtualOrInterfaceWithJValues(ts, obj, mid, args).s;
   }
 
   static void CallVoidMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
     ScopedJniThreadState ts(env);
     va_list ap;
     va_start(ap, mid);
-    JValue result = InvokeVirtualWithVarArgs(ts, obj, mid, ap);
+    JValue result = InvokeVirtualOrInterfaceWithVarArgs(ts, obj, mid, ap);
     va_end(ap);
   }
 
   static void CallVoidMethodV(JNIEnv* env, jobject obj, jmethodID mid, va_list args) {
     ScopedJniThreadState ts(env);
-    InvokeVirtualWithVarArgs(ts, obj, mid, args);
+    InvokeVirtualOrInterfaceWithVarArgs(ts, obj, mid, args);
   }
 
   static void CallVoidMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
     ScopedJniThreadState ts(env);
-    InvokeVirtualWithJValues(ts, obj, mid, args);
+    InvokeVirtualOrInterfaceWithJValues(ts, obj, mid, args);
   }
 
   static jobject CallNonvirtualObjectMethod(JNIEnv* env,
diff --git a/src/object.cc b/src/object.cc
index d06c3e3..5d64466 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -25,7 +25,7 @@
   // recursively all super-interfaces of those interfaces, are listed
   // in iftable_, so we can just do a linear scan through that.
   for (size_t i = 0; i < iftable_count_; i++) {
-    if (iftable_[i].GetClass() == klass) {
+    if (iftable_[i].GetInterface() == klass) {
       return true;
     }
   }
@@ -434,6 +434,20 @@
           this->GetSignature()->Equals(that->GetSignature()));
 }
 
+Method* Class::FindVirtualMethodForInterface(Method* method) {
+  Class* declaring_class = method->GetDeclaringClass();
+  DCHECK(declaring_class->IsInterface());
+  // TODO cache to improve lookup speed
+  for (size_t i = 0; i < iftable_count_; i++) {
+    InterfaceEntry& interface_entry = iftable_[i];
+    if (interface_entry.GetInterface() == declaring_class) {
+      return vtable_->Get(interface_entry.method_index_array_[method->method_index_]);
+    }
+  }
+  UNIMPLEMENTED(FATAL) << "Need to throw an error of some kind";
+  return NULL;
+}
+
 Method* Class::FindDeclaredDirectMethod(const StringPiece& name,
                                         const StringPiece& signature) {
   for (size_t i = 0; i < NumDirectMethods(); ++i) {
diff --git a/src/object.h b/src/object.h
index 2657872..6c8fd6b 100644
--- a/src/object.h
+++ b/src/object.h
@@ -498,10 +498,6 @@
     return pc;
   }
 
-  size_t GetVtableIndex() const {
-    return method_index_;
-  }
-
  public:  // TODO: private
   // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
   // the class we are a part of
@@ -670,10 +666,10 @@
   uint32_t access_flags_;
 
   // For concrete virtual methods, this is the offset of the method
-  // in "vtable".
+  // in Class::vtable_.
   //
   // For abstract methods in an interface class, this is the offset
-  // of the method in "iftable[n]->methodIndexArray".
+  // of the method in "iftable_[n]->method_index_array_".
   uint16_t method_index_;
 
   // Method bounds; not needed for an abstract method.
@@ -1117,8 +1113,26 @@
     virtual_methods_->Set(i, f);
   }
 
-  Method* GetMethodByVtableIndex(size_t vtable_index) {
-    return vtable_->Get(vtable_index);
+  // Given a method implemented by this class but potentially from a
+  // super class, return the specific implementation
+  // method for this class.
+  Method* FindVirtualMethodForVirtual(Method* method) {
+    DCHECK(!method->GetDeclaringClass()->IsInterface());
+    // The argument method may from a super class.
+    // Use the index to a potentially overriden one for this instance's class.
+    return vtable_->Get(method->method_index_);
+  }
+
+  // Given a method implemented by this class, but potentially from a
+  // super class or interface, return the specific implementation
+  // method for this class.
+  Method* FindVirtualMethodForInterface(Method* method);
+
+  Method* FindVirtualMethodForVirtualOrInterface(Method* method) {
+    if (method->GetDeclaringClass()->IsInterface()) {
+      return FindVirtualMethodForInterface(method);
+    }
+    return FindVirtualMethodForVirtual(method);
   }
 
   Method* FindDeclaredVirtualMethod(const StringPiece& name,
@@ -1289,7 +1303,7 @@
   // our class either replace those from the super or are appended.
   ObjectArray<Method>* vtable_;
 
-  // Interface table (iftable), one entry per interface supported by
+  // 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
@@ -1303,12 +1317,14 @@
   // For every interface a concrete class implements, we create a list
   // of virtualMethod indices for the methods in the interface.
   size_t iftable_count_;
+  // TODO convert to ObjectArray<?>
   InterfaceEntry* iftable_;
 
   // The interface vtable indices for iftable get stored here.  By
   // placing them all in a single pool for each class that implements
   // interfaces, we decrease the number of allocations.
   size_t ifvi_pool_count_;
+  // TODO convert to IntArray
   uint32_t* ifvi_pool_;
 
   // instance fields
@@ -1694,24 +1710,26 @@
 
 class InterfaceEntry {
  public:
-  InterfaceEntry() : klass_(NULL), method_index_array_(NULL) {
+  InterfaceEntry() : interface_(NULL), method_index_array_(NULL) {
   }
 
-  Class* GetClass() const {
-    return klass_;
+  Class* GetInterface() const {
+    DCHECK(interface_ != NULL);
+    return interface_;
   }
 
-  void SetClass(Class* klass) {
-    klass_ = klass;
+  void SetInterface(Class* interface) {
+    DCHECK(interface->IsInterface());
+    interface_ = interface;
   }
 
  private:
   // Points to the interface class.
-  Class* klass_;
+  Class* interface_;
 
  public:  // TODO: private
   // Index into array of vtable offsets.  This points into the
-  // ifviPool, which holds the vtables for all interfaces declared by
+  // ifvi_pool_, which holds the vtables for all interfaces declared by
   // this class.
   uint32_t* method_index_array_;