Fix VM test 077

Recognize incompatible class changes in resolution of direct methods.
Recognize incompatible changes to invokevirtual by rewriting in the
verifier.

Change-Id: Ie7d938bae39179d44ac3bedb575a3ccf73ac43b2
diff --git a/src/dex_verifier.cc b/src/dex_verifier.cc
index 6c415e6..9ba5d34 100644
--- a/src/dex_verifier.cc
+++ b/src/dex_verifier.cc
@@ -3085,8 +3085,8 @@
       (method_type == METHOD_STATIC && !res_method->IsStatic()) ||
       ((method_type == METHOD_VIRTUAL || method_type == METHOD_INTERFACE) && res_method->IsDirect())
       ) {
-    Fail(VERIFY_ERROR_GENERIC) << "invoke type does not match method type of "
-                               << PrettyMethod(res_method);
+    Fail(VERIFY_ERROR_CLASS_CHANGE) << "invoke type does not match method type of "
+                                    << PrettyMethod(res_method);
     return NULL;
   }
   // If we're using invoke-super(method), make sure that the executing method's class' superclass
diff --git a/src/runtime_support.cc b/src/runtime_support.cc
index 3a3eaf1..1222626 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -407,12 +407,19 @@
   // Resolve method filling in dex cache
   Method* called = linker->ResolveMethod(method_idx, *caller_sp, true);
   if (LIKELY(!thread->IsExceptionPending())) {
-    // Update CodeAndDirectMethod table
-    Method* caller = *caller_sp;
-    DexCache* dex_cache = caller->GetDeclaringClass()->GetDexCache();
-    dex_cache->GetCodeAndDirectMethods()->SetResolvedDirectMethod(method_idx, called);
-    // We got this far, ensure that the declaring class is initialized
-    linker->EnsureInitialized(called->GetDeclaringClass(), true);
+    if (LIKELY(called->IsDirect())) {
+      // Update CodeAndDirectMethod table
+      Method* caller = *caller_sp;
+      DexCache* dex_cache = caller->GetDeclaringClass()->GetDexCache();
+      dex_cache->GetCodeAndDirectMethods()->SetResolvedDirectMethod(method_idx, called);
+      // We got this far, ensure that the declaring class is initialized
+      linker->EnsureInitialized(called->GetDeclaringClass(), true);
+    } else {
+      // Direct method has been made virtual
+      thread->ThrowNewExceptionF("Ljava/lang/IncompatibleClassChangeError;",
+                                 "Expected direct method but found virtual: %s",
+                                 PrettyMethod(called, true).c_str());
+    }
   }
   void* code;
   if (UNLIKELY(thread->IsExceptionPending())) {