Fix ClassLinker::LinkInterfaceMethods bug

Also:
- Expanded class_linker_test with additional vtable and iftable coverage
- Added -fkeep-inline-functions where it works on host for debugging
- Added disabled test for running command line Fibonacci with oatexec

Change-Id: Ie295551e42493c7cca05684e71e56bf55bd362a4
diff --git a/Android.mk b/Android.mk
index ae17953..ef8eb75 100644
--- a/Android.mk
+++ b/Android.mk
@@ -76,19 +76,39 @@
 
 # "mm test-art-device" to build and run all target tests
 .PHONY: test-art-target
-test-art-target: $(ART_TARGET_TEST_DEPENDENCIES)
+test-art-target: test-art-target-gtest test-art-target-oat
+
+.PHONY: test-art-target-sync
+test-art-target-sync: $(ART_TARGET_TEST_DEPENDENCIES)
 	adb remount
 	adb sync
-	adb shell touch /sdcard/test-art-target
-	adb shell rm /sdcard/test-art-target
-        # gtest unit tests
-	adb shell sh -c "$(foreach file,$(sort $(ART_TARGET_TEST_EXECUTABLES)), /system/bin/$(notdir $(file)) &&) touch /sdcard/test-art-target"
-	adb pull /sdcard/test-art-target /tmp/
-	rm /tmp/test-art-target # this will cause the make on test failure (since the file will not exist)
-        # oatexec test
-	adb shell sh -c "oatexecd -Xbootclasspath:/system/framework/core.jar -Xbootimage:/system/framework/boot.oat -classpath /system/framework/art-test-dex-HelloWorld.jar -Ximage:/system/framework/art-test-dex-HelloWorld.oat HelloWorld && touch /sdcard/test-art-target"
-	adb pull /sdcard/test-art-target /tmp/
-	rm /tmp/test-art-target # this will cause the make on test failure (since the file will not exist)
+
+.PHONY: test-art-target-gtest
+test-art-target-gtest: test-art-target-sync
+	adb shell touch /sdcard/test-art-target-gtest
+	adb shell rm /sdcard/test-art-target-gtest
+	adb shell sh -c "$(foreach file,$(sort $(ART_TARGET_TEST_EXECUTABLES)), /system/bin/$(notdir $(file)) &&) touch /sdcard/test-art-target-gtest"
+	(adb pull /sdcard/test-art-target-gtest /tmp/ && echo test-art-target-gtest PASSED) || echo test-art-target-gtest FAILED
+	$(hide) rm /tmp/test-art-target-gtest
+
+.PHONY: test-art-target-oat
+test-art-target-oat: test-art-target-oat-HelloWorld # test-art-target-oat-Fibonacci
+
+.PHONY: test-art-target-oat-HelloWorld
+test-art-target-oat-HelloWorld: test-art-target-sync
+	adb shell touch /sdcard/test-art-target-oat-HelloWorld
+	adb shell rm /sdcard/test-art-target-oat-HelloWorld
+	adb shell sh -c "oatexecd -Xbootclasspath:/system/framework/core.jar -Xbootimage:/system/framework/boot.oat -classpath /system/framework/art-test-dex-HelloWorld.jar -Ximage:/system/framework/art-test-dex-HelloWorld.oat HelloWorld && touch /sdcard/test-art-target-oat-HelloWorld"
+	(adb pull /sdcard/test-art-target-oat-HelloWorld /tmp/ && echo test-art-target-oat-HelloWorld PASSED) || (echo test-art-target-oat-HelloWorld FAILED && exit 1)
+	$(hide) rm /tmp/test-art-target-oat-HelloWorld
+
+.PHONY: test-art-target-oat-Fibonacci
+test-art-target-oat-Fibonacci: test-art-target-sync
+	adb shell touch /sdcard/test-art-target-oat-Fibonacci
+	adb shell rm /sdcard/test-art-target-oat-Fibonacci
+	adb shell sh -c "oatexecd -Xbootclasspath:/system/framework/core.jar -Xbootimage:/system/framework/boot.oat -classpath /system/framework/art-test-dex-Fibonacci.jar -Ximage:/system/framework/art-test-dex-Fibonacci.oat Fibonacci 10 && touch /sdcard/test-art-target-oat-Fibonacci"
+	(adb pull /sdcard/test-art-target-oat-Fibonacci /tmp/ && echo test-art-target-oat-Fibonacci PASSED) || (echo test-art-target-oat-Fibonacci FAILED && exit 1)
+	$(hide) rm /tmp/test-art-target-oat-Fibonacci
 
 # "mm cpplint-art" to style check art source files
 .PHONY: cpplint-art
diff --git a/build/Android.common.mk b/build/Android.common.mk
index 9481df2..c62b038 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -45,6 +45,10 @@
   ART_TARGET_CFLAGS += -DANDROID_SMP=0
 endif
 
+art_debug_cflags := -UNDEBUG
+# TODO: move -fkeep-inline-functions to art_debug_cflags when target gcc > 4.4
+ART_HOST_DEBUG_CFLAGS := $(art_debug_cflags) -fkeep-inline-functions
+ART_TARGET_DEBUG_CFLAGS := $(art_debug_cflags)
 
 DEX2OAT_SRC_FILES := \
 	src/dex2oat.cc
diff --git a/build/Android.executable.mk b/build/Android.executable.mk
index 1b2f41d..60d37ee 100644
--- a/build/Android.executable.mk
+++ b/build/Android.executable.mk
@@ -40,7 +40,12 @@
     LOCAL_CFLAGS := $(ART_HOST_CFLAGS)
   endif
   ifeq ($(4),debug)
-    LOCAL_CFLAGS += -UNDEBUG
+    ifeq ($(3),target)
+      LOCAL_CFLAGS += $(ART_TARGET_DEBUG_CFLAGS)
+    else
+      LOCAL_CFLAGS += $(ART_HOST_DEBUG_CFLAGS)
+      LOCAL_STATIC_LIBRARIES := libgtest_host
+    endif
   endif
   LOCAL_C_INCLUDES += $(ART_C_INCLUDES)
   LOCAL_SHARED_LIBRARIES := libnativehelper
diff --git a/build/Android.libart.mk b/build/Android.libart.mk
index 96202eb..48ac809 100644
--- a/build/Android.libart.mk
+++ b/build/Android.libart.mk
@@ -38,8 +38,12 @@
   else
     LOCAL_CFLAGS := $(ART_HOST_CFLAGS)
   endif
-  ifeq ($(2),debug)
-    LOCAL_CFLAGS += -UNDEBUG
+  ifeq ($(4),debug)
+    ifeq ($(3),target)
+      LOCAL_CFLAGS += $(ART_TARGET_DEBUG_CFLAGS)
+    else
+      LOCAL_CFLAGS += $(ART_HOST_DEBUG_CFLAGS)
+    endif
   endif
   LOCAL_C_INCLUDES += $(ART_C_INCLUDES)
   LOCAL_SHARED_LIBRARIES := liblog libnativehelper
diff --git a/build/Android.libarttest.mk b/build/Android.libarttest.mk
index baf37d9..6e1619d 100644
--- a/build/Android.libarttest.mk
+++ b/build/Android.libarttest.mk
@@ -25,10 +25,10 @@
   LOCAL_MODULE_TAGS := tests
   LOCAL_SRC_FILES := $(LIBARTTEST_COMMON_SRC_FILES)
   ifeq ($(1),target)
-    LOCAL_CFLAGS := $(ART_TARGET_CFLAGS) -UNDEBUG
+    LOCAL_CFLAGS := $(ART_TARGET_CFLAGS) $(ART_TARGET_DEBUG_CFLAGS)
     LOCAL_SHARED_LIBRARIES := libdl libstlport
   else
-    LOCAL_CFLAGS := $(ART_HOST_CFLAGS) -UNDEBUG
+    LOCAL_CFLAGS := $(ART_HOST_CFLAGS) $(ART_HOST_DEBUG_CFLAGS)
     LOCAL_LDLIBS := -ldl -lrt
   endif
   ifeq ($(1),target)
diff --git a/build/Android.test.mk b/build/Android.test.mk
index 798a69f..6e82b26 100644
--- a/build/Android.test.mk
+++ b/build/Android.test.mk
@@ -31,11 +31,11 @@
   LOCAL_C_INCLUDES += $(ART_C_INCLUDES)
   LOCAL_SHARED_LIBRARIES := libarttest libartd
   ifeq ($(1),target)
-    LOCAL_CFLAGS := $(ART_TARGET_CFLAGS) -UNDEBUG
+    LOCAL_CFLAGS := $(ART_TARGET_CFLAGS) $(ART_TARGET_DEBUG_CFLAGS)
     LOCAL_SHARED_LIBRARIES += libdl libicuuc libicui18n libnativehelper libstlport libz
     LOCAL_STATIC_LIBRARIES := libgtest libgtest_main
   else
-    LOCAL_CFLAGS := $(ART_HOST_CFLAGS) -UNDEBUG
+    LOCAL_CFLAGS := $(ART_HOST_CFLAGS) $(ART_HOST_DEBUG_CFLAGS)
     LOCAL_SHARED_LIBRARIES += libicuuc-host libicui18n-host libnativehelper libz-host
     LOCAL_WHOLE_STATIC_LIBRARIES := libgtest_host libgtest_main_host
   endif
diff --git a/src/class_linker.cc b/src/class_linker.cc
index f25bac0..dde29cf 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -1718,7 +1718,7 @@
   }
   klass->SetIfTable(iftable);
   CHECK_EQ(idx, ifcount);
-  if (klass->IsInterface() || super_ifcount == ifcount) {
+  if (klass->IsInterface()) {
     return true;
   }
   std::vector<Method*> miranda_list;
diff --git a/src/class_linker_test.cc b/src/class_linker_test.cc
index eab184e..4b48892 100644
--- a/src/class_linker_test.cc
+++ b/src/class_linker_test.cc
@@ -54,6 +54,9 @@
     EXPECT_EQ(0U, primitive->NumInstanceFields());
     EXPECT_EQ(0U, primitive->NumStaticFields());
     EXPECT_EQ(0U, primitive->NumInterfaces());
+    EXPECT_TRUE(primitive->GetVTable() == NULL);
+    EXPECT_EQ(0, primitive->GetIfTableCount());
+    EXPECT_TRUE(primitive->GetIfTable() == NULL);
   }
 
   void AssertArrayClass(const StringPiece& array_descriptor,
@@ -95,6 +98,12 @@
     EXPECT_EQ(0U, array->NumInstanceFields());
     EXPECT_EQ(0U, array->NumStaticFields());
     EXPECT_EQ(2U, array->NumInterfaces());
+    EXPECT_TRUE(array->GetVTable() != NULL);
+    EXPECT_EQ(2, array->GetIfTableCount());
+    ObjectArray<InterfaceEntry>* iftable = array->GetIfTable();
+    ASSERT_TRUE(iftable != NULL);
+    EXPECT_TRUE(iftable->Get(0)->GetInterface()->GetDescriptor()->Equals("Ljava/lang/Cloneable;"));
+    EXPECT_TRUE(iftable->Get(1)->GetInterface()->GetDescriptor()->Equals("Ljava/io/Serializable;"));
   }
 
   void AssertMethod(Class* klass, Method* method) {
@@ -159,6 +168,20 @@
         EXPECT_NE(0U, klass->NumDirectMethods());
       }
     }
+    EXPECT_EQ(klass->IsInterface(), klass->GetVTable() == NULL);
+    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();
+      ASSERT_TRUE(interface != NULL);
+      EXPECT_TRUE(interface_entry->GetInterface() != NULL);
+      if (klass->IsInterface()) {
+        EXPECT_EQ(0U, interface_entry->GetMethodArrayCount());
+      } else {
+        CHECK_EQ(interface->NumVirtualMethods(), interface_entry->GetMethodArrayCount());
+        EXPECT_EQ(interface->NumVirtualMethods(), interface_entry->GetMethodArrayCount());
+      }
+    }
     if (klass->IsAbstract()) {
       EXPECT_FALSE(klass->IsFinal());
     } else {
diff --git a/src/object.h b/src/object.h
index 2f9ea33..5e09f2e 100644
--- a/src/object.h
+++ b/src/object.h
@@ -2683,6 +2683,14 @@
     Set(kInterface, interface);
   }
 
+  size_t GetMethodArrayCount() const {
+    ObjectArray<Method>* method_array = down_cast<ObjectArray<Method>*>(Get(kMethodArray));
+    if (method_array == 0) {
+      return 0;
+    }
+    return method_array->GetLength();
+  }
+
   ObjectArray<Method>* GetMethodArray() const {
     ObjectArray<Method>* method_array = down_cast<ObjectArray<Method>*>(Get(kMethodArray));
     DCHECK(method_array != NULL);