Avoid compile time rewriting of dex code by verifier.

Compile time rewriting of dex code leads to dead code that is causing
issues with the LLVM compiler. Make instantiation and incompatible class
change errors be detected in slow path field and invoke logic so its
safe for the compile time verification just to softly fail the effected
classes.

This change places incompatible class change logic into the class
linkers ResolveMethod and consequently changes a number of APIs.

Change-Id: Ifb25f09accea348d15180f6ff041e38dfe0d536e
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 7576c66..cd89448 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -88,26 +88,12 @@
   va_end(args);
 }
 
-static void ThrowNoSuchMethodError(bool is_direct, Class* c, const StringPiece& name,
-                                   const StringPiece& signature)
-    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
-  ClassHelper kh(c);
-  std::ostringstream msg;
-  msg << "no " << (is_direct ? "direct" : "virtual") << " method " << name << signature
-      << " in class " << kh.GetDescriptor() << " or its superclasses";
-  std::string location(kh.GetLocation());
-  if (!location.empty()) {
-    msg << " (defined in " << location << ")";
-  }
-  Thread::Current()->ThrowNewException("Ljava/lang/NoSuchMethodError;", msg.str().c_str());
-}
-
 static void ThrowNoSuchFieldError(const StringPiece& scope, Class* c, const StringPiece& type,
                                   const StringPiece& name)
     SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   ClassHelper kh(c);
   std::ostringstream msg;
-  msg << "no " << scope << "field " << name << " of type " << type
+  msg << "No " << scope << "field " << name << " of type " << type
       << " in class " << kh.GetDescriptor() << " or its superclasses";
   std::string location(kh.GetLocation());
   if (!location.empty()) {
@@ -1458,7 +1444,8 @@
       }
     } else if (method->GetCode() == trampoline) {
       const void* code = oat_class->GetOatMethod(method_index).GetCode();
-      CHECK(code != NULL);
+      CHECK(code != NULL)
+          << "Resolving a static trampoline but found no code for: " << PrettyMethod(method);
       method->SetCode(code);
     }
     method_index++;
@@ -3417,50 +3404,140 @@
                                    uint32_t method_idx,
                                    DexCache* dex_cache,
                                    ClassLoader* class_loader,
-                                   bool is_direct) {
+                                   InvokeType type) {
   DCHECK(dex_cache != NULL);
+  // Check for hit in the dex cache.
   Method* resolved = dex_cache->GetResolvedMethod(method_idx);
   if (resolved != NULL) {
     return resolved;
   }
+  // Fail, get the declaring class.
   const DexFile::MethodId& method_id = dex_file.GetMethodId(method_idx);
   Class* klass = ResolveType(dex_file, method_id.class_idx_, dex_cache, class_loader);
   if (klass == NULL) {
     DCHECK(Thread::Current()->IsExceptionPending());
     return NULL;
   }
-
-  if (is_direct) {
-    resolved = klass->FindDirectMethod(dex_cache, method_idx);
-  } else if (klass->IsInterface()) {
-    resolved = klass->FindInterfaceMethod(dex_cache, method_idx);
-  } else {
-    resolved = klass->FindVirtualMethod(dex_cache, method_idx);
+  // Scan using method_idx, this saves string compares but will only hit for matching dex
+  // caches/files.
+  switch (type) {
+    case kDirect:  // Fall-through.
+    case kStatic:
+      resolved = klass->FindDirectMethod(dex_cache, method_idx);
+      break;
+    case kInterface:
+      resolved = klass->FindInterfaceMethod(dex_cache, method_idx);
+      break;
+    case kSuper:  // Fall-through.
+    case kVirtual:
+      resolved = klass->FindVirtualMethod(dex_cache, method_idx);
+      break;
+    default:
+      LOG(FATAL) << "Unreachable - invocation type: " << type;
   }
-
   if (resolved == NULL) {
+    // Search by name, which works across dex files.
     const char* name = dex_file.StringDataByIdx(method_id.name_idx_);
     std::string signature(dex_file.CreateMethodSignature(method_id.proto_idx_, NULL));
-    if (is_direct) {
-      resolved = klass->FindDirectMethod(name, signature);
-    } else if (klass->IsInterface()) {
-      resolved = klass->FindInterfaceMethod(name, signature);
-    } else {
-      resolved = klass->FindVirtualMethod(name, signature);
-      // If a virtual method isn't found, search the direct methods. This can
-      // happen when trying to access private methods directly, and allows the
-      // proper exception to be thrown in the caller.
-      if (resolved == NULL) {
+    switch (type) {
+      case kDirect:  // Fall-through.
+      case kStatic:
         resolved = klass->FindDirectMethod(name, signature);
-      }
-    }
-    if (resolved == NULL) {
-      ThrowNoSuchMethodError(is_direct, klass, name, signature);
-      return NULL;
+        break;
+      case kInterface:
+        resolved = klass->FindInterfaceMethod(name, signature);
+        break;
+      case kSuper:  // Fall-through.
+      case kVirtual:
+        resolved = klass->FindVirtualMethod(name, signature);
+        break;
     }
   }
-  dex_cache->SetResolvedMethod(method_idx, resolved);
-  return resolved;
+  if (resolved != NULL) {
+    // We found a method, check for incompatible class changes.
+    switch (type) {
+      case kDirect:
+        if (resolved->IsStatic()) {
+          resolved = NULL;  // Incompatible class change.
+        }
+        break;
+      case kStatic:
+        if (!resolved->IsStatic()) {
+          resolved = NULL;  // Incompatible class change.
+        }
+        break;
+      case kInterface:
+        if (resolved->IsConstructor() || !resolved->GetDeclaringClass()->IsInterface()) {
+          resolved = NULL;  // Incompatible class change.
+        }
+        break;
+      case kSuper:
+        // TODO: appropriate checks for call to super class.
+        break;
+      case kVirtual:
+        if (resolved->IsConstructor() || resolved->GetDeclaringClass()->IsInterface()) {
+          resolved = NULL;  // Incompatible class change.
+        }
+        break;
+    }
+  }
+  if (resolved != NULL) {
+    // Be a good citizen and update the dex cache to speed subsequent calls.
+    dex_cache->SetResolvedMethod(method_idx, resolved);
+    return resolved;
+  } else {
+    // We failed to find the method which means either an incompatible class change or no such
+    // method.
+    const char* name = dex_file.StringDataByIdx(method_id.name_idx_);
+    std::string signature(dex_file.CreateMethodSignature(method_id.proto_idx_, NULL));
+    switch (type) {
+      case kDirect:
+      case kStatic:
+        resolved = klass->FindVirtualMethod(name, signature);
+        if (resolved != NULL) {
+          ThrowIncompatibleClassChangeError(type, kVirtual, resolved);
+        } else {
+          resolved = klass->FindInterfaceMethod(name, signature);
+          if (resolved != NULL) {
+            ThrowIncompatibleClassChangeError(type, kInterface, resolved);
+          } else {
+            ThrowNoSuchMethodError(type, klass, name, signature);
+          }
+        }
+        break;
+      case kInterface:
+        resolved = klass->FindDirectMethod(name, signature);
+        if (resolved != NULL) {
+          ThrowIncompatibleClassChangeError(type, kDirect, resolved);
+        } else {
+          resolved = klass->FindVirtualMethod(name, signature);
+          if (resolved != NULL) {
+            ThrowIncompatibleClassChangeError(type, kVirtual, resolved);
+          } else {
+            ThrowNoSuchMethodError(type, klass, name, signature);
+          }
+        }
+        break;
+      case kSuper:
+        ThrowNoSuchMethodError(type, klass, name, signature);
+        break;
+      case kVirtual:
+        resolved = klass->FindDirectMethod(name, signature);
+        if (resolved != NULL) {
+          ThrowIncompatibleClassChangeError(type, kDirect, resolved);
+        } else {
+          resolved = klass->FindInterfaceMethod(name, signature);
+          if (resolved != NULL) {
+            ThrowIncompatibleClassChangeError(type, kInterface, resolved);
+          } else {
+            ThrowNoSuchMethodError(type, klass, name, signature);
+          }
+        }
+        break;
+    }
+    DCHECK(Thread::Current()->IsExceptionPending());
+    return NULL;
+  }
 }
 
 Field* ClassLinker::ResolveField(const DexFile& dex_file,
diff --git a/src/class_linker.h b/src/class_linker.h
index c69c442..8a6aaec 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -174,10 +174,10 @@
                         uint32_t method_idx,
                         DexCache* dex_cache,
                         ClassLoader* class_loader,
-                        bool is_direct)
+                        InvokeType type)
       SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_);
 
-  Method* ResolveMethod(uint32_t method_idx, const Method* referrer, bool is_direct)
+  Method* ResolveMethod(uint32_t method_idx, const Method* referrer, InvokeType type)
       SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
     Method* resolved_method = referrer->GetDexCacheResolvedMethods()->Get(method_idx);
     if (UNLIKELY(resolved_method == NULL || resolved_method->IsRuntimeMethod())) {
@@ -185,7 +185,7 @@
       DexCache* dex_cache = declaring_class->GetDexCache();
       ClassLoader* class_loader = declaring_class->GetClassLoader();
       const DexFile& dex_file = FindDexFile(dex_cache);
-      resolved_method = ResolveMethod(dex_file, method_idx, dex_cache, class_loader, is_direct);
+      resolved_method = ResolveMethod(dex_file, method_idx, dex_cache, class_loader, type);
     }
     return resolved_method;
   }
diff --git a/src/compiler.cc b/src/compiler.cc
index 466e2df..4dd3a09 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -506,7 +506,8 @@
 
   uint32_t method_idx = method->GetDexMethodIndex();
   const DexFile::CodeItem* code_item = dex_file->GetCodeItem(method->GetCodeItemOffset());
-  CompileMethod(code_item, method->GetAccessFlags(), method_idx, class_loader, *dex_file);
+  CompileMethod(code_item, method->GetAccessFlags(), method->GetInvokeType(),
+                method_idx, class_loader, *dex_file);
 
   PostCompile(class_loader, dex_files);
 
@@ -644,8 +645,8 @@
   return result;
 }
 
-static Class* ComputeReferrerClass(ScopedObjectAccess& soa,
-                                   OatCompilationUnit* mUnit)
+static Class* ComputeCompilingMethodsClass(ScopedObjectAccess& soa,
+                                           OatCompilationUnit* mUnit)
     SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   DexCache* dex_cache = mUnit->class_linker_->FindDexCache(*mUnit->dex_file_);
   ClassLoader* class_loader = soa.Decode<ClassLoader*>(mUnit->class_loader_);
@@ -654,8 +655,9 @@
                                            dex_cache, class_loader);
 }
 
-static Field* ComputeReferrerField(ScopedObjectAccess& soa,
-                                   OatCompilationUnit* mUnit, uint32_t field_idx)
+static Field* ComputeFieldReferencedFromCompilingMethod(ScopedObjectAccess& soa,
+                                                        OatCompilationUnit* mUnit,
+                                                        uint32_t field_idx)
     SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   DexCache* dex_cache = mUnit->class_linker_->FindDexCache(*mUnit->dex_file_);
   ClassLoader* class_loader = soa.Decode<ClassLoader*>(mUnit->class_loader_);
@@ -663,25 +665,27 @@
                                             class_loader, false);
 }
 
-static Method* ComputeReferrerMethod(ScopedObjectAccess& soa,
-                                     OatCompilationUnit* mUnit, uint32_t method_idx)
+static Method* ComputeMethodReferencedFromCompilingMethod(ScopedObjectAccess& soa,
+                                                          OatCompilationUnit* mUnit,
+                                                          uint32_t method_idx,
+                                                          InvokeType type)
     SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   DexCache* dex_cache = mUnit->class_linker_->FindDexCache(*mUnit->dex_file_);
   ClassLoader* class_loader = soa.Decode<ClassLoader*>(mUnit->class_loader_);
   return mUnit->class_linker_->ResolveMethod(*mUnit->dex_file_, method_idx, dex_cache,
-                                             class_loader, true);
+                                             class_loader, type);
 }
 
 bool Compiler::ComputeInstanceFieldInfo(uint32_t field_idx, OatCompilationUnit* mUnit,
                                         int& field_offset, bool& is_volatile, bool is_put) {
   ScopedObjectAccess soa(Thread::Current());
-  // Conservative defaults
+  // Conservative defaults.
   field_offset = -1;
   is_volatile = true;
-  // Try to resolve field
-  Field* resolved_field = ComputeReferrerField(soa, mUnit, field_idx);
-  if (resolved_field != NULL) {
-    Class* referrer_class = ComputeReferrerClass(soa, mUnit);
+  // Try to resolve field and ignore if an Incompatible Class Change Error (ie is static).
+  Field* resolved_field = ComputeFieldReferencedFromCompilingMethod(soa, mUnit, field_idx);
+  if (resolved_field != NULL && !resolved_field->IsStatic()) {
+    Class* referrer_class = ComputeCompilingMethodsClass(soa, mUnit);
     if (referrer_class != NULL) {
       Class* fields_class = resolved_field->GetDeclaringClass();
       bool access_ok = referrer_class->CanAccess(fields_class) &&
@@ -721,16 +725,15 @@
                                       int& field_offset, int& ssb_index,
                                       bool& is_referrers_class, bool& is_volatile, bool is_put) {
   ScopedObjectAccess soa(Thread::Current());
-  // Conservative defaults
+  // Conservative defaults.
   field_offset = -1;
   ssb_index = -1;
   is_referrers_class = false;
   is_volatile = true;
-  // Try to resolve field
-  Field* resolved_field = ComputeReferrerField(soa, mUnit, field_idx);
-  if (resolved_field != NULL) {
-    DCHECK(resolved_field->IsStatic());
-    Class* referrer_class = ComputeReferrerClass(soa, mUnit);
+  // Try to resolve field and ignore if an Incompatible Class Change Error (ie isn't static).
+  Field* resolved_field = ComputeFieldReferencedFromCompilingMethod(soa, mUnit, field_idx);
+  if (resolved_field != NULL && resolved_field->IsStatic()) {
+    Class* referrer_class = ComputeCompilingMethodsClass(soa, mUnit);
     if (referrer_class != NULL) {
       Class* fields_class = resolved_field->GetDeclaringClass();
       if (fields_class == referrer_class) {
@@ -846,17 +849,22 @@
   vtable_idx = -1;
   direct_code = 0;
   direct_method = 0;
-  Method* resolved_method = ComputeReferrerMethod(soa, mUnit, method_idx);
+  Method* resolved_method =
+      ComputeMethodReferencedFromCompilingMethod(soa, mUnit, method_idx, type);
   if (resolved_method != NULL) {
-    Class* referrer_class = ComputeReferrerClass(soa, mUnit);
-    if (referrer_class != NULL) {
+    // Don't try to fast-path if we don't understand the caller's class or this appears to be an
+    // Incompatible Class Change Error.
+    Class* referrer_class = ComputeCompilingMethodsClass(soa, mUnit);
+    bool icce = resolved_method->CheckIncompatibleClassChange(type);
+    if (referrer_class != NULL && !icce) {
       Class* methods_class = resolved_method->GetDeclaringClass();
       if (!referrer_class->CanAccess(methods_class) ||
           !referrer_class->CanAccessMember(methods_class,
                                            resolved_method->GetAccessFlags())) {
         // The referring class can't access the resolved method, this may occur as a result of a
         // protected method being made public by implementing an interface that re-declares the
-        // method public. Resort to the dex file to determine the correct class for the access check
+        // method public. Resort to the dex file to determine the correct class for the access
+        // check.
         const DexFile& dex_file = mUnit->class_linker_->FindDexFile(referrer_class->GetDexCache());
         methods_class =
             mUnit->class_linker_->ResolveType(dex_file,
@@ -870,24 +878,24 @@
         const bool kEnableSharpening = true;
         // Sharpen a virtual call into a direct call when the target is known.
         bool can_sharpen = type == kVirtual && (resolved_method->IsFinal() ||
-                                                methods_class->IsFinal());
-        // ensure the vtable index will be correct to dispatch in the vtable of the super class
+            methods_class->IsFinal());
+        // Ensure the vtable index will be correct to dispatch in the vtable of the super class.
         can_sharpen = can_sharpen || (type == kSuper && referrer_class != methods_class &&
-                                      referrer_class->IsSubClass(methods_class) &&
-                                      vtable_idx < methods_class->GetVTable()->GetLength() &&
-                                      methods_class->GetVTable()->Get(vtable_idx) == resolved_method);
+            referrer_class->IsSubClass(methods_class) &&
+            vtable_idx < methods_class->GetVTable()->GetLength() &&
+            methods_class->GetVTable()->Get(vtable_idx) == resolved_method);
         if (kEnableSharpening && can_sharpen) {
           stats_->ResolvedMethod(type);
           // Sharpen a virtual call into a direct call. The method_idx is into referrer's
           // dex cache, check that this resolved method is where we expect it.
           CHECK(referrer_class->GetDexCache()->GetResolvedMethod(method_idx) == resolved_method)
-            << PrettyMethod(resolved_method);
+              << PrettyMethod(resolved_method);
           stats_->VirtualMadeDirect(type);
           GetCodeAndMethodForDirectCall(type, kDirect, resolved_method, direct_code, direct_method);
           type = kDirect;
           return true;
         } else if (type == kSuper) {
-          // Unsharpened super calls are suspicious so go slowpath.
+          // Unsharpened super calls are suspicious so go slow-path.
         } else {
           stats_->ResolvedMethod(type);
           GetCodeAndMethodForDirectCall(type, type, resolved_method, direct_code, direct_method);
@@ -906,30 +914,30 @@
 
 void Compiler::AddCodePatch(const DexFile* dex_file,
                             uint32_t referrer_method_idx,
-                            uint32_t referrer_access_flags,
+                            InvokeType referrer_invoke_type,
                             uint32_t target_method_idx,
-                            bool target_is_direct,
+                            InvokeType target_invoke_type,
                             size_t literal_offset) {
   MutexLock mu(compiled_methods_lock_);
   code_to_patch_.push_back(new PatchInformation(dex_file,
                                                 referrer_method_idx,
-                                                referrer_access_flags,
+                                                referrer_invoke_type,
                                                 target_method_idx,
-                                                target_is_direct,
+                                                target_invoke_type,
                                                 literal_offset));
 }
 void Compiler::AddMethodPatch(const DexFile* dex_file,
                               uint32_t referrer_method_idx,
-                              uint32_t referrer_access_flags,
+                              InvokeType referrer_invoke_type,
                               uint32_t target_method_idx,
-                              bool target_is_direct,
+                              InvokeType target_invoke_type,
                               size_t literal_offset) {
   MutexLock mu(compiled_methods_lock_);
   methods_to_patch_.push_back(new PatchInformation(dex_file,
                                                    referrer_method_idx,
-                                                   referrer_access_flags,
+                                                   referrer_invoke_type,
                                                    target_method_idx,
-                                                   target_is_direct,
+                                                   target_invoke_type,
                                                    literal_offset));
 }
 
@@ -1132,7 +1140,7 @@
   }
   while (it.HasNextDirectMethod()) {
     Method* method = class_linker->ResolveMethod(dex_file, it.GetMemberIndex(), dex_cache,
-                                                 class_loader, true);
+                                                 class_loader, it.GetMethodInvokeType(class_def));
     if (method == NULL) {
       CHECK(self->IsExceptionPending());
       self->ClearException();
@@ -1141,7 +1149,7 @@
   }
   while (it.HasNextVirtualMethod()) {
     Method* method = class_linker->ResolveMethod(dex_file, it.GetMemberIndex(), dex_cache,
-                                                 class_loader, false);
+                                                 class_loader, it.GetMethodInvokeType(class_def));
     if (method == NULL) {
       CHECK(self->IsExceptionPending());
       self->ClearException();
@@ -1507,7 +1515,8 @@
     }
     previous_direct_method_idx = method_idx;
     context->GetCompiler()->CompileMethod(it.GetMethodCodeItem(), it.GetMemberAccessFlags(),
-                                          method_idx, class_loader, dex_file);
+                                          it.GetMethodInvokeType(class_def), method_idx,
+                                          class_loader, dex_file);
     it.Next();
   }
   // Compile virtual methods
@@ -1522,7 +1531,8 @@
     }
     previous_virtual_method_idx = method_idx;
     context->GetCompiler()->CompileMethod(it.GetMethodCodeItem(), it.GetMemberAccessFlags(),
-                                          method_idx, class_loader, dex_file);
+                                          it.GetMethodInvokeType(class_def), method_idx,
+                                          class_loader, dex_file);
     it.Next();
   }
   DCHECK(!it.HasNext());
@@ -1542,7 +1552,7 @@
 }
 
 void Compiler::CompileMethod(const DexFile::CodeItem* code_item, uint32_t access_flags,
-                             uint32_t method_idx, jobject class_loader,
+                             InvokeType invoke_type, uint32_t method_idx, jobject class_loader,
                              const DexFile& dex_file) {
   CompiledMethod* compiled_method = NULL;
   uint64_t start_ns = NanoTime();
@@ -1552,8 +1562,8 @@
     CHECK(compiled_method != NULL);
   } else if ((access_flags & kAccAbstract) != 0) {
   } else {
-    compiled_method = (*compiler_)(*this, code_item, access_flags, method_idx, class_loader,
-                                   dex_file);
+    compiled_method = (*compiler_)(*this, code_item, access_flags, invoke_type, method_idx,
+                                   class_loader, dex_file);
     CHECK(compiled_method != NULL) << PrettyMethod(method_idx, dex_file);
   }
   uint64_t duration_ns = NanoTime() - start_ns;
@@ -1709,13 +1719,13 @@
     }
     while (it.HasNextDirectMethod()) {
       Method* method = class_linker->ResolveMethod(dex_file, it.GetMemberIndex(), dex_cache,
-                                                   class_loader, true);
+                                                   class_loader, it.GetMethodInvokeType(class_def));
       SetGcMapsMethod(dex_file, method);
       it.Next();
     }
     while (it.HasNextVirtualMethod()) {
       Method* method = class_linker->ResolveMethod(dex_file, it.GetMemberIndex(), dex_cache,
-                                                   class_loader, false);
+                                                   class_loader, it.GetMethodInvokeType(class_def));
       SetGcMapsMethod(dex_file, method);
       it.Next();
     }
diff --git a/src/compiler.h b/src/compiler.h
index 01ef037..4a7fc2a 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -143,16 +143,16 @@
   // Record patch information for later fix up.
   void AddCodePatch(const DexFile* dex_file,
                     uint32_t referrer_method_idx,
-                    uint32_t referrer_access_flags,
+                    InvokeType referrer_invoke_type,
                     uint32_t target_method_idx,
-                    bool target_is_direct,
+                    InvokeType target_invoke_type,
                     size_t literal_offset)
       LOCKS_EXCLUDED(compiled_methods_lock_);
   void AddMethodPatch(const DexFile* dex_file,
                       uint32_t referrer_method_idx,
-                      uint32_t referrer_access_flags,
+                      InvokeType referrer_invoke_type,
                       uint32_t target_method_idx,
-                      bool target_is_direct,
+                      InvokeType target_invoke_type,
                       size_t literal_offset)
       LOCKS_EXCLUDED(compiled_methods_lock_);
 
@@ -180,14 +180,14 @@
     uint32_t GetReferrerMethodIdx() const {
       return referrer_method_idx_;
     }
-    bool GetReferrerIsDirect() const {
-      return referrer_is_direct_;
+    InvokeType GetReferrerInvokeType() const {
+      return referrer_invoke_type_;
     }
     uint32_t GetTargetMethodIdx() const {
       return target_method_idx_;
     }
-    bool GetTargetIsDirect() const {
-      return target_is_direct_;
+    InvokeType GetTargetInvokeType() const {
+      return target_invoke_type_;
     }
     size_t GetLiteralOffset() const {;
       return literal_offset_;
@@ -196,24 +196,24 @@
    private:
     PatchInformation(const DexFile* dex_file,
                      uint32_t referrer_method_idx,
-                     uint32_t referrer_access_flags,
+                     InvokeType referrer_invoke_type,
                      uint32_t target_method_idx,
-                     uint32_t target_is_direct,
+                     InvokeType target_invoke_type,
                      size_t literal_offset)
       : dex_file_(dex_file),
         referrer_method_idx_(referrer_method_idx),
-        referrer_is_direct_(Method::IsDirect(referrer_access_flags)),
+        referrer_invoke_type_(referrer_invoke_type),
         target_method_idx_(target_method_idx),
-        target_is_direct_(target_is_direct),
+        target_invoke_type_(target_invoke_type),
         literal_offset_(literal_offset) {
       CHECK(dex_file_ != NULL);
     }
 
     const DexFile* dex_file_;
     uint32_t referrer_method_idx_;
-    bool referrer_is_direct_;
+    InvokeType referrer_invoke_type_;
     uint32_t target_method_idx_;
-    bool target_is_direct_;
+    InvokeType target_invoke_type_;
     size_t literal_offset_;
 
     friend class Compiler;
@@ -263,7 +263,8 @@
   void Compile(jobject class_loader, const std::vector<const DexFile*>& dex_files);
   void CompileDexFile(jobject class_loader, const DexFile& dex_file)
       LOCKS_EXCLUDED(GlobalSynchronization::mutator_lock_);
-  void CompileMethod(const DexFile::CodeItem* code_item, uint32_t access_flags, uint32_t method_idx,
+  void CompileMethod(const DexFile::CodeItem* code_item, uint32_t access_flags,
+                     InvokeType invoke_type, uint32_t method_idx,
                      jobject class_loader, const DexFile& dex_file)
       LOCKS_EXCLUDED(compiled_methods_lock_);
 
@@ -332,8 +333,8 @@
 
   typedef CompiledMethod* (*CompilerFn)(Compiler& compiler,
                                         const DexFile::CodeItem* code_item,
-                                        uint32_t access_flags, uint32_t method_idx,
-                                        jobject class_loader,
+                                        uint32_t access_flags, InvokeType invoke_type,
+                                        uint32_t method_idx, jobject class_loader,
                                         const DexFile& dex_file);
   CompilerFn compiler_;
 
diff --git a/src/compiler/Compiler.h b/src/compiler/Compiler.h
index 214f603..659b5a6 100644
--- a/src/compiler/Compiler.h
+++ b/src/compiler/Compiler.h
@@ -204,7 +204,9 @@
 
 extern "C" art::CompiledMethod* ArtCompileMethod(art::Compiler& compiler,
                                                  const art::DexFile::CodeItem* code_item,
-                                                 uint32_t access_flags, uint32_t method_idx,
+                                                 uint32_t access_flags,
+                                                 art::InvokeType invoke_type,
+                                                 uint32_t method_idx,
                                                  jobject class_loader,
                                                  const art::DexFile& dex_file);
 
diff --git a/src/compiler/CompilerIR.h b/src/compiler/CompilerIR.h
index a606287..914d2ab 100644
--- a/src/compiler/CompilerIR.h
+++ b/src/compiler/CompilerIR.h
@@ -331,6 +331,7 @@
       method_idx(0),
       code_item(NULL),
       access_flags(0),
+      invoke_type(kDirect),
       shorty(NULL),
       firstLIRInsn(NULL),
       lastLIRInsn(NULL),
@@ -440,6 +441,7 @@
   uint32_t method_idx;                // compiling method's index into method_ids of DexFile
   const DexFile::CodeItem* code_item;  // compiling method's DexFile code_item
   uint32_t access_flags;              // compiling method's access flags
+  InvokeType invoke_type;             // compiling method's invocation type
   const char* shorty;                 // compiling method's shorty
   LIR* firstLIRInsn;
   LIR* lastLIRInsn;
diff --git a/src/compiler/Frontend.cc b/src/compiler/Frontend.cc
index 78c0f94..3c579c4 100644
--- a/src/compiler/Frontend.cc
+++ b/src/compiler/Frontend.cc
@@ -742,7 +742,8 @@
 
 CompiledMethod* oatCompileMethod(Compiler& compiler,
                                  const DexFile::CodeItem* code_item,
-                                 uint32_t access_flags, uint32_t method_idx,
+                                 uint32_t access_flags, InvokeType invoke_type,
+                                 uint32_t method_idx,
                                  jobject class_loader,
                                  const DexFile& dex_file)
 {
@@ -764,6 +765,7 @@
   cUnit->method_idx = method_idx;
   cUnit->code_item = code_item;
   cUnit->access_flags = access_flags;
+  cUnit->invoke_type = invoke_type;
   cUnit->shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(method_idx));
   cUnit->instructionSet = compiler.GetInstructionSet();
   cUnit->insns = code_item->insns_;
@@ -1182,11 +1184,11 @@
 extern "C" art::CompiledMethod*
     ArtCompileMethod(art::Compiler& compiler,
                      const art::DexFile::CodeItem* code_item,
-                     uint32_t access_flags, uint32_t method_idx,
-                     jobject class_loader,
+                     uint32_t access_flags, art::InvokeType invoke_type,
+                     uint32_t method_idx, jobject class_loader,
                      const art::DexFile& dex_file)
 {
   CHECK_EQ(compiler.GetInstructionSet(), art::oatInstructionSet());
-  return art::oatCompileMethod(compiler, code_item, access_flags, method_idx,
-                 class_loader, dex_file);
+  return art::oatCompileMethod(compiler, code_item, access_flags, invoke_type,
+                               method_idx, class_loader, dex_file);
 }
diff --git a/src/compiler/codegen/CodegenUtil.cc b/src/compiler/codegen/CodegenUtil.cc
index dd7daba..3aea76a 100644
--- a/src/compiler/codegen/CodegenUtil.cc
+++ b/src/compiler/codegen/CodegenUtil.cc
@@ -646,9 +646,9 @@
       uint32_t target = dataLIR->operands[0];
       cUnit->compiler->AddCodePatch(cUnit->dex_file,
                                     cUnit->method_idx,
-                                    cUnit->access_flags,
+                                    cUnit->invoke_type,
                                     target,
-                                    IsDirect(dataLIR->operands[1]),
+                                    static_cast<InvokeType>(dataLIR->operands[1]),
                                     cUnit->codeBuffer.size());
       const DexFile::MethodId& id = cUnit->dex_file->GetMethodId(target);
       // unique based on target to ensure code deduplication works
@@ -661,9 +661,9 @@
       uint32_t target = dataLIR->operands[0];
       cUnit->compiler->AddMethodPatch(cUnit->dex_file,
                                       cUnit->method_idx,
-                                      cUnit->access_flags,
+                                      cUnit->invoke_type,
                                       target,
-                                      IsDirect(dataLIR->operands[1]),
+                                      static_cast<InvokeType>(dataLIR->operands[1]),
                                       cUnit->codeBuffer.size());
       const DexFile::MethodId& id = cUnit->dex_file->GetMethodId(target);
       // unique based on target to ensure code deduplication works
diff --git a/src/compiler_llvm/compiler_llvm.cc b/src/compiler_llvm/compiler_llvm.cc
index e52478b..b30486c 100644
--- a/src/compiler_llvm/compiler_llvm.cc
+++ b/src/compiler_llvm/compiler_llvm.cc
@@ -188,13 +188,13 @@
   delete ContextOf(compiler);
   compiler.SetCompilerContext(NULL);
 }
-
 extern "C" art::CompiledMethod* ArtCompileMethod(art::Compiler& compiler,
                                                  const art::DexFile::CodeItem* code_item,
-                                                 uint32_t access_flags, uint32_t method_idx,
+                                                 uint32_t access_flags,
+                                                 art::InvokeType invoke_type,
+                                                 uint32_t method_idx,
                                                  jobject class_loader,
-                                                 const art::DexFile& dex_file)
-{
+                                                 const art::DexFile& dex_file) {
   art::ClassLinker *class_linker = art::Runtime::Current()->GetClassLinker();
 
   art::OatCompilationUnit oat_compilation_unit(
diff --git a/src/compiler_llvm/runtime_support_llvm.cc b/src/compiler_llvm/runtime_support_llvm.cc
index ccc0e14..3854b4c 100644
--- a/src/compiler_llvm/runtime_support_llvm.cc
+++ b/src/compiler_llvm/runtime_support_llvm.cc
@@ -365,13 +365,13 @@
 
 int32_t art_set32_static_from_code(uint32_t field_idx, Method* referrer, int32_t new_value)
     SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
-  Field* field = FindFieldFast(field_idx, referrer, true, true, sizeof(uint32_t));
+  Field* field = FindFieldFast(field_idx, referrer, StaticPrimitiveWrite, sizeof(uint32_t));
   if (LIKELY(field != NULL)) {
     field->Set32(NULL, new_value);
     return 0;
   }
   field = FindFieldFromCode(field_idx, referrer, art_get_current_thread_from_code(),
-                            true, true, true, sizeof(uint32_t));
+                            StaticPrimitiveWrite, sizeof(uint32_t));
   if (LIKELY(field != NULL)) {
     field->Set32(NULL, new_value);
     return 0;
@@ -381,13 +381,13 @@
 
 int32_t art_set64_static_from_code(uint32_t field_idx, Method* referrer, int64_t new_value)
     SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
-  Field* field = FindFieldFast(field_idx, referrer, true, true, sizeof(uint64_t));
+  Field* field = FindFieldFast(field_idx, referrer, StaticPrimitiveWrite, sizeof(uint64_t));
   if (LIKELY(field != NULL)) {
     field->Set64(NULL, new_value);
     return 0;
   }
   field = FindFieldFromCode(field_idx, referrer, art_get_current_thread_from_code(),
-                            true, true, true, sizeof(uint64_t));
+                            StaticPrimitiveWrite, sizeof(uint64_t));
   if (LIKELY(field != NULL)) {
     field->Set64(NULL, new_value);
     return 0;
@@ -397,13 +397,13 @@
 
 int32_t art_set_obj_static_from_code(uint32_t field_idx, Method* referrer, Object* new_value)
     SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
-  Field* field = FindFieldFast(field_idx, referrer, false, true, sizeof(Object*));
+  Field* field = FindFieldFast(field_idx, referrer, StaticObjectWrite, sizeof(Object*));
   if (LIKELY(field != NULL)) {
     field->SetObj(NULL, new_value);
     return 0;
   }
   field = FindFieldFromCode(field_idx, referrer, art_get_current_thread_from_code(),
-                            true, false, true, sizeof(Object*));
+                            StaticObjectWrite, sizeof(Object*));
   if (LIKELY(field != NULL)) {
     field->SetObj(NULL, new_value);
     return 0;
@@ -413,12 +413,12 @@
 
 int32_t art_get32_static_from_code(uint32_t field_idx, Method* referrer)
     SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
-  Field* field = FindFieldFast(field_idx, referrer, true, false, sizeof(uint32_t));
+  Field* field = FindFieldFast(field_idx, referrer, StaticPrimitiveRead, sizeof(uint32_t));
   if (LIKELY(field != NULL)) {
     return field->Get32(NULL);
   }
   field = FindFieldFromCode(field_idx, referrer, art_get_current_thread_from_code(),
-                            true, true, false, sizeof(uint32_t));
+                            StaticPrimitiveRead, sizeof(uint32_t));
   if (LIKELY(field != NULL)) {
     return field->Get32(NULL);
   }
@@ -427,12 +427,12 @@
 
 int64_t art_get64_static_from_code(uint32_t field_idx, Method* referrer)
     SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
-  Field* field = FindFieldFast(field_idx, referrer, true, false, sizeof(uint64_t));
+  Field* field = FindFieldFast(field_idx, referrer, StaticPrimitiveRead, sizeof(uint64_t));
   if (LIKELY(field != NULL)) {
     return field->Get64(NULL);
   }
   field = FindFieldFromCode(field_idx, referrer, art_get_current_thread_from_code(),
-                            true, true, false, sizeof(uint64_t));
+                            StaticPrimitiveRead, sizeof(uint64_t));
   if (LIKELY(field != NULL)) {
     return field->Get64(NULL);
   }
@@ -441,12 +441,12 @@
 
 Object* art_get_obj_static_from_code(uint32_t field_idx, Method* referrer)
     SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
-  Field* field = FindFieldFast(field_idx, referrer, false, false, sizeof(Object*));
+  Field* field = FindFieldFast(field_idx, referrer, StaticObjectRead, sizeof(Object*));
   if (LIKELY(field != NULL)) {
     return field->GetObj(NULL);
   }
   field = FindFieldFromCode(field_idx, referrer, art_get_current_thread_from_code(),
-                            true, false, false, sizeof(Object*));
+                            StaticObjectRead, sizeof(Object*));
   if (LIKELY(field != NULL)) {
     return field->GetObj(NULL);
   }
@@ -456,13 +456,13 @@
 int32_t art_set32_instance_from_code(uint32_t field_idx, Method* referrer,
                                      Object* obj, uint32_t new_value)
     SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
-  Field* field = FindFieldFast(field_idx, referrer, true, true, sizeof(uint32_t));
+  Field* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite, sizeof(uint32_t));
   if (LIKELY(field != NULL)) {
     field->Set32(obj, new_value);
     return 0;
   }
   field = FindFieldFromCode(field_idx, referrer, art_get_current_thread_from_code(),
-                            false, true, true, sizeof(uint32_t));
+                            InstancePrimitiveWrite, sizeof(uint32_t));
   if (LIKELY(field != NULL)) {
     field->Set32(obj, new_value);
     return 0;
@@ -473,13 +473,13 @@
 int32_t art_set64_instance_from_code(uint32_t field_idx, Method* referrer,
                                      Object* obj, int64_t new_value)
     SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
-  Field* field = FindFieldFast(field_idx, referrer, true, true, sizeof(uint64_t));
+  Field* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite, sizeof(uint64_t));
   if (LIKELY(field != NULL)) {
     field->Set64(obj, new_value);
     return 0;
   }
   field = FindFieldFromCode(field_idx, referrer, art_get_current_thread_from_code(),
-                            false, true, true, sizeof(uint64_t));
+                            InstancePrimitiveWrite, sizeof(uint64_t));
   if (LIKELY(field != NULL)) {
     field->Set64(obj, new_value);
     return 0;
@@ -490,13 +490,13 @@
 int32_t art_set_obj_instance_from_code(uint32_t field_idx, Method* referrer,
                                        Object* obj, Object* new_value)
     SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
-  Field* field = FindFieldFast(field_idx, referrer, false, true, sizeof(Object*));
+  Field* field = FindFieldFast(field_idx, referrer, InstanceObjectWrite, sizeof(Object*));
   if (LIKELY(field != NULL)) {
     field->SetObj(obj, new_value);
     return 0;
   }
   field = FindFieldFromCode(field_idx, referrer, art_get_current_thread_from_code(),
-                            false, false, true, sizeof(Object*));
+                            InstanceObjectWrite, sizeof(Object*));
   if (LIKELY(field != NULL)) {
     field->SetObj(obj, new_value);
     return 0;
@@ -506,12 +506,12 @@
 
 int32_t art_get32_instance_from_code(uint32_t field_idx, Method* referrer, Object* obj)
     SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
-  Field* field = FindFieldFast(field_idx, referrer, true, false, sizeof(uint32_t));
+  Field* field = FindFieldFast(field_idx, referrer, InstancePrimitiveRead, sizeof(uint32_t));
   if (LIKELY(field != NULL)) {
     return field->Get32(obj);
   }
   field = FindFieldFromCode(field_idx, referrer, art_get_current_thread_from_code(),
-                            false, true, false, sizeof(uint32_t));
+                            InstancePrimitiveRead, sizeof(uint32_t));
   if (LIKELY(field != NULL)) {
     return field->Get32(obj);
   }
@@ -520,12 +520,12 @@
 
 int64_t art_get64_instance_from_code(uint32_t field_idx, Method* referrer, Object* obj)
     SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
-  Field* field = FindFieldFast(field_idx, referrer, true, false, sizeof(uint64_t));
+  Field* field = FindFieldFast(field_idx, referrer, InstancePrimitiveRead, sizeof(uint64_t));
   if (LIKELY(field != NULL)) {
     return field->Get64(obj);
   }
   field = FindFieldFromCode(field_idx, referrer, art_get_current_thread_from_code(),
-                            false, true, false, sizeof(uint64_t));
+                            InstancePrimitiveRead, sizeof(uint64_t));
   if (LIKELY(field != NULL)) {
     return field->Get64(obj);
   }
@@ -534,12 +534,12 @@
 
 Object* art_get_obj_instance_from_code(uint32_t field_idx, Method* referrer, Object* obj)
     SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
-  Field* field = FindFieldFast(field_idx, referrer, false, false, sizeof(Object*));
+  Field* field = FindFieldFast(field_idx, referrer, InstanceObjectRead, sizeof(Object*));
   if (LIKELY(field != NULL)) {
     return field->GetObj(obj);
   }
   field = FindFieldFromCode(field_idx, referrer, art_get_current_thread_from_code(),
-                            false, false, false, sizeof(Object*));
+                            InstanceObjectRead, sizeof(Object*));
   if (LIKELY(field != NULL)) {
     return field->GetObj(obj);
   }
diff --git a/src/dex_file.h b/src/dex_file.h
index 5f33ef8..99a748d 100644
--- a/src/dex_file.h
+++ b/src/dex_file.h
@@ -21,9 +21,11 @@
 #include <vector>
 
 #include "globals.h"
+#include "invoke_type.h"
 #include "jni.h"
 #include "logging.h"
 #include "mem_map.h"
+#include "modifiers.h"
 #include "mutex.h"
 #include "safe_map.h"
 #include "stringpiece.h"
@@ -1024,6 +1026,24 @@
       return method_.access_flags_;
     }
   }
+  InvokeType GetMethodInvokeType(const DexFile::ClassDef& class_def) const {
+    if (HasNextDirectMethod()) {
+      if ((GetMemberAccessFlags() & kAccStatic) != 0 ) {
+        return kStatic;
+      } else {
+        return kDirect;
+      }
+    } else {
+      CHECK_EQ(GetMemberAccessFlags() & kAccStatic, 0U);
+      if ((class_def.access_flags_ & kAccInterface) != 0) {
+        return kInterface;
+      } else if ((GetMemberAccessFlags() & kAccConstructor) != 0) {
+        return kSuper;
+      } else {
+        return kVirtual;
+      }
+    }
+  }
   const DexFile::CodeItem* GetMethodCodeItem() const {
     return dex_file_.GetCodeItem(method_.code_off_);
   }
diff --git a/src/image_writer.cc b/src/image_writer.cc
index bc22af6..e8220fc 100644
--- a/src/image_writer.cc
+++ b/src/image_writer.cc
@@ -612,7 +612,7 @@
                                                patch->GetReferrerMethodIdx(),
                                                dex_cache,
                                                NULL,
-                                               patch->GetReferrerIsDirect());
+                                               patch->GetReferrerInvokeType());
   CHECK(method != NULL)
     << patch->GetDexFile().GetLocation() << " " << patch->GetReferrerMethodIdx();
   CHECK(!method->IsRuntimeMethod())
@@ -632,7 +632,7 @@
                                                patch->GetTargetMethodIdx(),
                                                dex_cache,
                                                NULL,
-                                               patch->GetTargetIsDirect());
+                                               patch->GetTargetInvokeType());
   CHECK(method != NULL)
     << patch->GetDexFile().GetLocation() << " " << patch->GetTargetMethodIdx();
   CHECK(!method->IsRuntimeMethod())
diff --git a/src/modifiers.h b/src/modifiers.h
new file mode 100644
index 0000000..070130f
--- /dev/null
+++ b/src/modifiers.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_MODIFIERS_H_
+#define ART_SRC_MODIFIERS_H_
+
+static const uint32_t kAccPublic = 0x0001;  // class, field, method, ic
+static const uint32_t kAccPrivate = 0x0002;  // field, method, ic
+static const uint32_t kAccProtected = 0x0004;  // field, method, ic
+static const uint32_t kAccStatic = 0x0008;  // field, method, ic
+static const uint32_t kAccFinal = 0x0010;  // class, field, method, ic
+static const uint32_t kAccSynchronized = 0x0020;  // method (only allowed on natives)
+static const uint32_t kAccSuper = 0x0020;  // class (not used in dex)
+static const uint32_t kAccVolatile = 0x0040;  // field
+static const uint32_t kAccBridge = 0x0040;  // method (1.5)
+static const uint32_t kAccTransient = 0x0080;  // field
+static const uint32_t kAccVarargs = 0x0080;  // method (1.5)
+static const uint32_t kAccNative = 0x0100;  // method
+static const uint32_t kAccInterface = 0x0200;  // class, ic
+static const uint32_t kAccAbstract = 0x0400;  // class, method, ic
+static const uint32_t kAccStrict = 0x0800;  // method
+static const uint32_t kAccSynthetic = 0x1000;  // field, method, ic
+static const uint32_t kAccAnnotation = 0x2000;  // class, ic (1.5)
+static const uint32_t kAccEnum = 0x4000;  // class, field, ic (1.5)
+
+static const uint32_t kAccMiranda = 0x8000;  // method
+
+static const uint32_t kAccJavaFlagsMask = 0xffff;  // bits set from Java sources (low 16)
+
+static const uint32_t kAccConstructor = 0x00010000;  // method (dex only)
+static const uint32_t kAccDeclaredSynchronized = 0x00020000;  // method (dex only)
+static const uint32_t kAccClassIsProxy = 0x00040000;  // class (dex only)
+
+// Special runtime-only flags.
+// Note: if only kAccClassIsReference is set, we have a soft reference.
+static const uint32_t kAccClassIsFinalizable        = 0x80000000;  // class/ancestor overrides finalize()
+static const uint32_t kAccClassIsReference          = 0x08000000;  // class is a soft/weak/phantom ref
+static const uint32_t kAccClassIsWeakReference      = 0x04000000;  // class is a weak reference
+static const uint32_t kAccClassIsFinalizerReference = 0x02000000;  // class is a finalizer reference
+static const uint32_t kAccClassIsPhantomReference   = 0x01000000;  // class is a phantom reference
+
+static const uint32_t kAccReferenceFlagsMask = (kAccClassIsReference
+                                                | kAccClassIsWeakReference
+                                                | kAccClassIsFinalizerReference
+                                                | kAccClassIsPhantomReference);
+
+#endif  // ART_SRC_MODIFIERS_H_
+
diff --git a/src/oat/runtime/support_field.cc b/src/oat/runtime/support_field.cc
index 99e3a94..289553e 100644
--- a/src/oat/runtime/support_field.cc
+++ b/src/oat/runtime/support_field.cc
@@ -24,12 +24,12 @@
 extern "C" uint32_t artGet32StaticFromCode(uint32_t field_idx, const Method* referrer,
                                            Thread* self, Method** sp)
     SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
-  Field* field = FindFieldFast(field_idx, referrer, true, false, sizeof(int32_t));
+  Field* field = FindFieldFast(field_idx, referrer, StaticPrimitiveRead, sizeof(int32_t));
   if (LIKELY(field != NULL)) {
     return field->Get32(NULL);
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
-  field = FindFieldFromCode(field_idx, referrer, self, true, true, false, sizeof(int32_t));
+  field = FindFieldFromCode(field_idx, referrer, self, StaticPrimitiveRead, sizeof(int32_t));
   if (LIKELY(field != NULL)) {
     return field->Get32(NULL);
   }
@@ -39,12 +39,12 @@
 extern "C" uint64_t artGet64StaticFromCode(uint32_t field_idx, const Method* referrer,
                                            Thread* self, Method** sp)
     SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
-  Field* field = FindFieldFast(field_idx, referrer, true, false, sizeof(int64_t));
+  Field* field = FindFieldFast(field_idx, referrer, StaticPrimitiveRead, sizeof(int64_t));
   if (LIKELY(field != NULL)) {
     return field->Get64(NULL);
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
-  field = FindFieldFromCode(field_idx, referrer, self, true, true, false, sizeof(int64_t));
+  field = FindFieldFromCode(field_idx, referrer, self, StaticPrimitiveRead, sizeof(int64_t));
   if (LIKELY(field != NULL)) {
     return field->Get64(NULL);
   }
@@ -54,12 +54,12 @@
 extern "C" Object* artGetObjStaticFromCode(uint32_t field_idx, const Method* referrer,
                                            Thread* self, Method** sp)
     SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
-  Field* field = FindFieldFast(field_idx, referrer, false, false, sizeof(Object*));
+  Field* field = FindFieldFast(field_idx, referrer, StaticObjectRead, sizeof(Object*));
   if (LIKELY(field != NULL)) {
     return field->GetObj(NULL);
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
-  field = FindFieldFromCode(field_idx, referrer, self, true, false, false, sizeof(Object*));
+  field = FindFieldFromCode(field_idx, referrer, self, StaticObjectRead, sizeof(Object*));
   if (LIKELY(field != NULL)) {
     return field->GetObj(NULL);
   }
@@ -69,12 +69,12 @@
 extern "C" uint32_t artGet32InstanceFromCode(uint32_t field_idx, Object* obj,
                                              const Method* referrer, Thread* self, Method** sp)
     SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
-  Field* field = FindFieldFast(field_idx, referrer, true, false, sizeof(int32_t));
+  Field* field = FindFieldFast(field_idx, referrer, InstancePrimitiveRead, sizeof(int32_t));
   if (LIKELY(field != NULL && obj != NULL)) {
     return field->Get32(obj);
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
-  field = FindFieldFromCode(field_idx, referrer, self, false, true, false, sizeof(int32_t));
+  field = FindFieldFromCode(field_idx, referrer, self, InstancePrimitiveRead, sizeof(int32_t));
   if (LIKELY(field != NULL)) {
     if (UNLIKELY(obj == NULL)) {
       ThrowNullPointerExceptionForFieldAccess(self, field, true);
@@ -88,12 +88,12 @@
 extern "C" uint64_t artGet64InstanceFromCode(uint32_t field_idx, Object* obj,
                                              const Method* referrer, Thread* self, Method** sp)
     SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
-  Field* field = FindFieldFast(field_idx, referrer, true, false, sizeof(int64_t));
+  Field* field = FindFieldFast(field_idx, referrer, InstancePrimitiveRead, sizeof(int64_t));
   if (LIKELY(field != NULL && obj != NULL)) {
     return field->Get64(obj);
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
-  field = FindFieldFromCode(field_idx, referrer, self, false, true, false, sizeof(int64_t));
+  field = FindFieldFromCode(field_idx, referrer, self, InstancePrimitiveRead, sizeof(int64_t));
   if (LIKELY(field != NULL)) {
     if (UNLIKELY(obj == NULL)) {
       ThrowNullPointerExceptionForFieldAccess(self, field, true);
@@ -107,12 +107,12 @@
 extern "C" Object* artGetObjInstanceFromCode(uint32_t field_idx, Object* obj,
                                               const Method* referrer, Thread* self, Method** sp)
     SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
-  Field* field = FindFieldFast(field_idx, referrer, false, false, sizeof(Object*));
+  Field* field = FindFieldFast(field_idx, referrer, InstanceObjectRead, sizeof(Object*));
   if (LIKELY(field != NULL && obj != NULL)) {
     return field->GetObj(obj);
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
-  field = FindFieldFromCode(field_idx, referrer, self, false, false, false, sizeof(Object*));
+  field = FindFieldFromCode(field_idx, referrer, self, InstanceObjectRead, sizeof(Object*));
   if (LIKELY(field != NULL)) {
     if (UNLIKELY(obj == NULL)) {
       ThrowNullPointerExceptionForFieldAccess(self, field, true);
@@ -126,13 +126,13 @@
 extern "C" int artSet32StaticFromCode(uint32_t field_idx, uint32_t new_value,
                                       const Method* referrer, Thread* self, Method** sp)
     SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
-  Field* field = FindFieldFast(field_idx, referrer, true, true, sizeof(int32_t));
+  Field* field = FindFieldFast(field_idx, referrer, StaticPrimitiveWrite, sizeof(int32_t));
   if (LIKELY(field != NULL)) {
     field->Set32(NULL, new_value);
     return 0;  // success
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
-  field = FindFieldFromCode(field_idx, referrer, self, true, true, true, sizeof(int32_t));
+  field = FindFieldFromCode(field_idx, referrer, self, StaticPrimitiveWrite, sizeof(int32_t));
   if (LIKELY(field != NULL)) {
     field->Set32(NULL, new_value);
     return 0;  // success
@@ -143,13 +143,13 @@
 extern "C" int artSet64StaticFromCode(uint32_t field_idx, const Method* referrer,
                                       uint64_t new_value, Thread* self, Method** sp)
     SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
-  Field* field = FindFieldFast(field_idx, referrer, true, true, sizeof(int64_t));
+  Field* field = FindFieldFast(field_idx, referrer, StaticPrimitiveWrite, sizeof(int64_t));
   if (LIKELY(field != NULL)) {
     field->Set64(NULL, new_value);
     return 0;  // success
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
-  field = FindFieldFromCode(field_idx, referrer, self, true, true, true, sizeof(int64_t));
+  field = FindFieldFromCode(field_idx, referrer, self, StaticPrimitiveWrite, sizeof(int64_t));
   if (LIKELY(field != NULL)) {
     field->Set64(NULL, new_value);
     return 0;  // success
@@ -160,7 +160,7 @@
 extern "C" int artSetObjStaticFromCode(uint32_t field_idx, Object* new_value,
                                        const Method* referrer, Thread* self, Method** sp)
     SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
-  Field* field = FindFieldFast(field_idx, referrer, false, true, sizeof(Object*));
+  Field* field = FindFieldFast(field_idx, referrer, StaticObjectWrite, sizeof(Object*));
   if (LIKELY(field != NULL)) {
     if (LIKELY(!FieldHelper(field).IsPrimitiveType())) {
       field->SetObj(NULL, new_value);
@@ -168,7 +168,7 @@
     }
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
-  field = FindFieldFromCode(field_idx, referrer, self, true, false, true, sizeof(Object*));
+  field = FindFieldFromCode(field_idx, referrer, self, StaticObjectWrite, sizeof(Object*));
   if (LIKELY(field != NULL)) {
     field->SetObj(NULL, new_value);
     return 0;  // success
@@ -179,13 +179,13 @@
 extern "C" int artSet32InstanceFromCode(uint32_t field_idx, Object* obj, uint32_t new_value,
                                         const Method* referrer, Thread* self, Method** sp)
     SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
-  Field* field = FindFieldFast(field_idx, referrer, true, true, sizeof(int32_t));
+  Field* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite, sizeof(int32_t));
   if (LIKELY(field != NULL && obj != NULL)) {
     field->Set32(obj, new_value);
     return 0;  // success
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
-  field = FindFieldFromCode(field_idx, referrer, self, false, true, true, sizeof(int32_t));
+  field = FindFieldFromCode(field_idx, referrer, self, InstancePrimitiveWrite, sizeof(int32_t));
   if (LIKELY(field != NULL)) {
     if (UNLIKELY(obj == NULL)) {
       ThrowNullPointerExceptionForFieldAccess(self, field, false);
@@ -202,14 +202,14 @@
     SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   Method* callee_save = Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsOnly);
   Method* referrer = sp[callee_save->GetFrameSizeInBytes() / sizeof(Method*)];
-  Field* field = FindFieldFast(field_idx, referrer, true, true, sizeof(int64_t));
+  Field* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite, sizeof(int64_t));
   if (LIKELY(field != NULL  && obj != NULL)) {
     field->Set64(obj, new_value);
     return 0;  // success
   }
   *sp = callee_save;
   self->SetTopOfStack(sp, 0);
-  field = FindFieldFromCode(field_idx, referrer, self, false, true, true, sizeof(int64_t));
+  field = FindFieldFromCode(field_idx, referrer, self, InstancePrimitiveWrite, sizeof(int64_t));
   if (LIKELY(field != NULL)) {
     if (UNLIKELY(obj == NULL)) {
       ThrowNullPointerExceptionForFieldAccess(self, field, false);
@@ -224,13 +224,13 @@
 extern "C" int artSetObjInstanceFromCode(uint32_t field_idx, Object* obj, Object* new_value,
                                          const Method* referrer, Thread* self, Method** sp)
     SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
-  Field* field = FindFieldFast(field_idx, referrer, false, true, sizeof(Object*));
+  Field* field = FindFieldFast(field_idx, referrer, InstanceObjectWrite, sizeof(Object*));
   if (LIKELY(field != NULL && obj != NULL)) {
     field->SetObj(obj, new_value);
     return 0;  // success
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
-  field = FindFieldFromCode(field_idx, referrer, self, false, false, true, sizeof(Object*));
+  field = FindFieldFromCode(field_idx, referrer, self, InstanceObjectWrite, sizeof(Object*));
   if (LIKELY(field != NULL)) {
     if (UNLIKELY(obj == NULL)) {
       ThrowNullPointerExceptionForFieldAccess(self, field, false);
diff --git a/src/oat/runtime/support_stubs.cc b/src/oat/runtime/support_stubs.cc
index 8b12973..510df3b 100644
--- a/src/oat/runtime/support_stubs.cc
+++ b/src/oat/runtime/support_stubs.cc
@@ -89,8 +89,7 @@
   // Compute details about the called method (avoid GCs)
   ClassLinker* linker = Runtime::Current()->GetClassLinker();
   Method* caller = *caller_sp;
-  bool is_static;
-  bool is_virtual;
+  InvokeType invoke_type;
   uint32_t dex_method_idx;
 #if !defined(__i386__)
   const char* shorty;
@@ -104,14 +103,27 @@
     CHECK_LT(dex_pc, code->insns_size_in_code_units_);
     const Instruction* instr = Instruction::At(&code->insns_[dex_pc]);
     Instruction::Code instr_code = instr->Opcode();
-    is_static = (instr_code == Instruction::INVOKE_STATIC) ||
-                (instr_code == Instruction::INVOKE_STATIC_RANGE);
-    is_virtual = (instr_code == Instruction::INVOKE_VIRTUAL) ||
-                 (instr_code == Instruction::INVOKE_VIRTUAL_RANGE) ||
-                 (instr_code == Instruction::INVOKE_SUPER) ||
-                 (instr_code == Instruction::INVOKE_SUPER_RANGE);
-    DCHECK(is_static || is_virtual || (instr_code == Instruction::INVOKE_DIRECT) ||
-           (instr_code == Instruction::INVOKE_DIRECT_RANGE));
+    switch (instr_code) {
+      case Instruction::INVOKE_DIRECT:  // Fall-through.
+      case Instruction::INVOKE_DIRECT_RANGE:
+        invoke_type = kDirect;
+        break;
+      case Instruction::INVOKE_STATIC:  // Fall-through.
+      case Instruction::INVOKE_STATIC_RANGE:
+        invoke_type = kStatic;
+        break;
+      case Instruction::INVOKE_SUPER:  // Fall-through.
+      case Instruction::INVOKE_SUPER_RANGE:
+        invoke_type = kSuper;
+        break;
+      case Instruction::INVOKE_VIRTUAL:  // Fall-through.
+      case Instruction::INVOKE_VIRTUAL_RANGE:
+        invoke_type = kVirtual;
+        break;
+      default:
+        LOG(FATAL) << "Unexpected call into trampoline: " << instr->DumpString(NULL);
+        invoke_type = kDirect;  // Avoid used uninitialized warnings.
+    }
     DecodedInstruction dec_insn(instr);
     dex_method_idx = dec_insn.vB;
 #if !defined(__i386__)
@@ -119,8 +131,7 @@
 #endif
   } else {
     DCHECK(!called->IsRuntimeMethod());
-    is_static = type == Runtime::kStaticMethod;
-    is_virtual = false;
+    invoke_type = (type == Runtime::kStaticMethod) ? kStatic : kDirect;
     dex_method_idx = called->GetDexMethodIndex();
 #if !defined(__i386__)
     MethodHelper mh(called);
@@ -141,7 +152,7 @@
   }
   // Place into local references incoming arguments from the caller's register arguments
   size_t cur_arg = 1;   // skip method_idx in R0, first arg is in R1
-  if (!is_static) {
+  if (invoke_type != kStatic) {
     Object* obj = reinterpret_cast<Object*>(regs[cur_arg]);
     cur_arg++;
     if (args_in_regs < 3) {
@@ -176,33 +187,28 @@
 #endif
   // Resolve method filling in dex cache
   if (type == Runtime::kUnknownMethod) {
-    called = linker->ResolveMethod(dex_method_idx, caller, !is_virtual);
+    called = linker->ResolveMethod(dex_method_idx, caller, invoke_type);
   }
   const void* code = NULL;
   if (LIKELY(!thread->IsExceptionPending())) {
-    if (LIKELY(called->IsDirect() == !is_virtual)) {
-      // Ensure that the called method's class is initialized.
-      Class* called_class = called->GetDeclaringClass();
-      linker->EnsureInitialized(called_class, true, true);
-      if (LIKELY(called_class->IsInitialized())) {
-        code = called->GetCode();
-      } else if (called_class->IsInitializing()) {
-        if (is_static) {
-          // Class is still initializing, go to oat and grab code (trampoline must be left in place
-          // until class is initialized to stop races between threads).
-          code = linker->GetOatCodeFor(called);
-        } else {
-          // No trampoline for non-static methods.
-          code = called->GetCode();
-        }
+    // Incompatible class change should have been handled in resolve method.
+    CHECK(!called->CheckIncompatibleClassChange(invoke_type));
+    // Ensure that the called method's class is initialized.
+    Class* called_class = called->GetDeclaringClass();
+    linker->EnsureInitialized(called_class, true, true);
+    if (LIKELY(called_class->IsInitialized())) {
+      code = called->GetCode();
+    } else if (called_class->IsInitializing()) {
+      if (invoke_type == kStatic) {
+        // Class is still initializing, go to oat and grab code (trampoline must be left in place
+        // until class is initialized to stop races between threads).
+        code = linker->GetOatCodeFor(called);
       } else {
-        DCHECK(called_class->IsErroneous());
+        // No trampoline for non-static methods.
+        code = called->GetCode();
       }
     } else {
-      // Direct method has been made virtual
-      thread->ThrowNewExceptionF("Ljava/lang/IncompatibleClassChangeError;",
-                                 "Expected direct method but found virtual: %s",
-                                 PrettyMethod(called, true).c_str());
+      DCHECK(called_class->IsErroneous());
     }
   }
   if (UNLIKELY(code == NULL)) {
@@ -229,8 +235,7 @@
   Method* caller = thread->GetCurrentMethod(&dex_pc);
 
   ClassLinker* linker = Runtime::Current()->GetClassLinker();
-  bool is_static;
-  bool is_virtual;
+  InvokeType invoke_type;
   uint32_t dex_method_idx;
   if (type == Runtime::kUnknownMethod) {
     DCHECK(called->IsRuntimeMethod());
@@ -238,32 +243,59 @@
     CHECK_LT(dex_pc, code->insns_size_in_code_units_);
     const Instruction* instr = Instruction::At(&code->insns_[dex_pc]);
     Instruction::Code instr_code = instr->Opcode();
-    is_static = (instr_code == Instruction::INVOKE_STATIC) ||
-                (instr_code == Instruction::INVOKE_STATIC_RANGE);
-    is_virtual = (instr_code == Instruction::INVOKE_VIRTUAL) ||
-                 (instr_code == Instruction::INVOKE_VIRTUAL_RANGE) ||
-                 (instr_code == Instruction::INVOKE_SUPER) ||
-                 (instr_code == Instruction::INVOKE_SUPER_RANGE);
-    DCHECK(is_static || is_virtual || (instr_code == Instruction::INVOKE_DIRECT) ||
-           (instr_code == Instruction::INVOKE_DIRECT_RANGE));
+    switch (instr_code) {
+      case Instruction::INVOKE_DIRECT:  // Fall-through.
+      case Instruction::INVOKE_DIRECT_RANGE:
+        invoke_type = kDirect;
+        break;
+      case Instruction::INVOKE_STATIC:  // Fall-through.
+      case Instruction::INVOKE_STATIC_RANGE:
+        invoke_type = kStatic;
+        break;
+      case Instruction::INVOKE_SUPER:  // Fall-through.
+      case Instruction::INVOKE_SUPER_RANGE:
+        invoke_type = kSuper;
+        break;
+      case Instruction::INVOKE_VIRTUAL:  // Fall-through.
+      case Instruction::INVOKE_VIRTUAL_RANGE:
+        invoke_type = kVirtual;
+        break;
+      default:
+        LOG(FATAL) << "Unexpected call into trampoline: " << instr->DumpString(NULL);
+        invoke_type = kDirect;  // Avoid used uninitialized warnings.
+    }
     DecodedInstruction dec_insn(instr);
     dex_method_idx = dec_insn.vB;
   } else {
     DCHECK(!called->IsRuntimeMethod());
-    is_static = type == Runtime::kStaticMethod;
-    is_virtual = false;
+    invoke_type = (type == Runtime::kStaticMethod) ? kStatic : kDirect;
     dex_method_idx = called->GetDexMethodIndex();
   }
   if (type == Runtime::kUnknownMethod) {
-    called = linker->ResolveMethod(dex_method_idx, caller, !is_virtual);
+    called = linker->ResolveMethod(dex_method_idx, caller, invoke_type);
   }
   const void* code = NULL;
   if (LIKELY(!thread->IsExceptionPending())) {
-    if (LIKELY(called->IsDirect() == !is_virtual)) {
-      // Ensure that the called method's class is initialized.
-      Class* called_class = called->GetDeclaringClass();
-      linker->EnsureInitialized(called_class, true, true);
-      if (LIKELY(called_class->IsInitialized())) {
+    // Incompatible class change should have been handled in resolve method.
+    CHECK(!called->CheckIncompatibleClassChange(invoke_type));
+    // Ensure that the called method's class is initialized.
+    Class* called_class = called->GetDeclaringClass();
+    linker->EnsureInitialized(called_class, true, true);
+    if (LIKELY(called_class->IsInitialized())) {
+      code = called->GetCode();
+      // TODO: remove this after we solve the link issue.
+      { // for lazy link.
+        if (code == NULL) {
+          code = linker->GetOatCodeFor(called);
+        }
+      }
+    } else if (called_class->IsInitializing()) {
+      if (invoke_type == kStatic) {
+        // Class is still initializing, go to oat and grab code (trampoline must be left in place
+        // until class is initialized to stop races between threads).
+        code = linker->GetOatCodeFor(called);
+      } else {
+        // No trampoline for non-static methods.
         code = called->GetCode();
         // TODO: remove this after we solve the link issue.
         { // for lazy link.
@@ -271,29 +303,9 @@
             code = linker->GetOatCodeFor(called);
           }
         }
-      } else if (called_class->IsInitializing()) {
-        if (is_static) {
-          // Class is still initializing, go to oat and grab code (trampoline must be left in place
-          // until class is initialized to stop races between threads).
-          code = linker->GetOatCodeFor(called);
-        } else {
-          // No trampoline for non-static methods.
-          code = called->GetCode();
-          // TODO: remove this after we solve the link issue.
-          { // for lazy link.
-            if (code == NULL) {
-              code = linker->GetOatCodeFor(called);
-            }
-          }
-        }
-      } else {
-        DCHECK(called_class->IsErroneous());
       }
     } else {
-      // Direct method has been made virtual
-      thread->ThrowNewExceptionF("Ljava/lang/IncompatibleClassChangeError;",
-                                 "Expected direct method but found virtual: %s",
-                                 PrettyMethod(called, true).c_str());
+      DCHECK(called_class->IsErroneous());
     }
   }
   if (LIKELY(code != NULL)) {
diff --git a/src/oat_writer.cc b/src/oat_writer.cc
index 0546f2b..4aa948c 100644
--- a/src/oat_writer.cc
+++ b/src/oat_writer.cc
@@ -198,18 +198,18 @@
   // Process methods
   size_t class_def_method_index = 0;
   while (it.HasNextDirectMethod()) {
-    bool is_static = (it.GetMemberAccessFlags() & kAccStatic) != 0;
     bool is_native = (it.GetMemberAccessFlags() & kAccNative) != 0;
-    offset = InitOatCodeMethod(offset, oat_class_index, class_def_index, class_def_method_index, is_native,
-                               is_static, true, it.GetMemberIndex(), &dex_file);
+    offset = InitOatCodeMethod(offset, oat_class_index, class_def_index, class_def_method_index,
+                               is_native, it.GetMethodInvokeType(class_def), it.GetMemberIndex(),
+                               &dex_file);
     class_def_method_index++;
     it.Next();
   }
   while (it.HasNextVirtualMethod()) {
-    CHECK_EQ(it.GetMemberAccessFlags() & kAccStatic, 0U);
     bool is_native = (it.GetMemberAccessFlags() & kAccNative) != 0;
-    offset = InitOatCodeMethod(offset, oat_class_index, class_def_index, class_def_method_index, is_native,
-                               false, false, it.GetMemberIndex(), &dex_file);
+    offset = InitOatCodeMethod(offset, oat_class_index, class_def_index, class_def_method_index,
+                               is_native, it.GetMethodInvokeType(class_def), it.GetMemberIndex(),
+                               &dex_file);
     class_def_method_index++;
     it.Next();
   }
@@ -221,7 +221,7 @@
                                     size_t __attribute__((unused)) class_def_index,
                                     size_t class_def_method_index,
                                     bool __attribute__((unused)) is_native,
-                                    bool is_static, bool is_direct,
+                                    InvokeType type,
                                     uint32_t method_idx, const DexFile* dex_file) {
   // derived from CompiledMethod if available
   uint32_t code_offset = 0;
@@ -316,7 +316,8 @@
   }
 
   const char* shorty = dex_file->GetMethodShorty(dex_file->GetMethodId(method_idx));
-  const CompiledInvokeStub* compiled_invoke_stub = compiler_->FindInvokeStub(is_static, shorty);
+  const CompiledInvokeStub* compiled_invoke_stub = compiler_->FindInvokeStub(type == kStatic,
+                                                                             shorty);
   if (compiled_invoke_stub != NULL) {
     offset = CompiledMethod::AlignCode(offset, compiler_->GetInstructionSet());
     DCHECK_ALIGNED(offset, kArmAlignment);
@@ -339,7 +340,7 @@
   }
 
 #if defined(ART_USE_LLVM_COMPILER)
-  if (!is_static) {
+  if (type == kStatic) {
     const CompiledInvokeStub* compiled_proxy_stub = compiler_->FindProxyStub(shorty);
     if (compiled_proxy_stub != NULL) {
       offset = CompiledMethod::AlignCode(offset, compiler_->GetInstructionSet());
@@ -384,7 +385,7 @@
     // Unchecked as we hold mutator_lock_ on entry.
     ScopedObjectAccessUnchecked soa(Thread::Current());
     Method* method = linker->ResolveMethod(*dex_file, method_idx, dex_cache,
-                                           soa.Decode<ClassLoader*>(class_loader_), is_direct);
+                                           soa.Decode<ClassLoader*>(class_loader_), type);
     CHECK(method != NULL);
     method->SetFrameSizeInBytes(frame_size_in_bytes);
     method->SetCoreSpillMask(core_spill_mask);
@@ -719,7 +720,7 @@
   }
 
 #if defined(ART_USE_LLVM_COMPILER)
-  if (!is_static) {
+  if (is_static) {
     const CompiledInvokeStub* compiled_proxy_stub = compiler_->FindProxyStub(shorty);
     if (compiled_proxy_stub != NULL) {
       uint32_t aligned_code_offset = CompiledMethod::AlignCode(code_offset,
diff --git a/src/oat_writer.h b/src/oat_writer.h
index 60a79a2..200d695 100644
--- a/src/oat_writer.h
+++ b/src/oat_writer.h
@@ -96,8 +96,8 @@
                              const DexFile::ClassDef& class_def)
       SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_);
   size_t InitOatCodeMethod(size_t offset, size_t oat_class_index, size_t class_def_index,
-                           size_t class_def_method_index, bool is_native, bool is_static,
-                           bool is_direct, uint32_t method_idx, const DexFile*)
+                           size_t class_def_method_index, bool is_native, InvokeType type,
+                           uint32_t method_idx, const DexFile*)
       SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_);
 
   bool Write(File* file);
diff --git a/src/object.cc b/src/object.cc
index c8da0fa..83994ff 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -304,6 +304,19 @@
 Class* Method::java_lang_reflect_Constructor_ = NULL;
 Class* Method::java_lang_reflect_Method_ = NULL;
 
+InvokeType Method::GetInvokeType() const {
+  // TODO: kSuper?
+  if (GetDeclaringClass()->IsInterface()) {
+    return kInterface;
+  } else if (IsStatic()) {
+    return kStatic;
+  } else if (IsDirect()) {
+    return kDirect;
+  } else {
+    return kVirtual;
+  }
+}
+
 void Method::SetClasses(Class* java_lang_reflect_Constructor, Class* java_lang_reflect_Method) {
   CHECK(java_lang_reflect_Constructor_ == NULL);
   CHECK(java_lang_reflect_Constructor != NULL);
diff --git a/src/object.h b/src/object.h
index dfb34e0..85b1721 100644
--- a/src/object.h
+++ b/src/object.h
@@ -25,8 +25,10 @@
 #include "casts.h"
 #include "globals.h"
 #include "heap.h"
+#include "invoke_type.h"
 #include "logging.h"
 #include "macros.h"
+#include "modifiers.h"
 #include "offsets.h"
 #include "primitive.h"
 #include "runtime.h"
@@ -112,46 +114,6 @@
 } // namespace compiler_llvm
 #endif
 
-static const uint32_t kAccPublic = 0x0001;  // class, field, method, ic
-static const uint32_t kAccPrivate = 0x0002;  // field, method, ic
-static const uint32_t kAccProtected = 0x0004;  // field, method, ic
-static const uint32_t kAccStatic = 0x0008;  // field, method, ic
-static const uint32_t kAccFinal = 0x0010;  // class, field, method, ic
-static const uint32_t kAccSynchronized = 0x0020;  // method (only allowed on natives)
-static const uint32_t kAccSuper = 0x0020;  // class (not used in dex)
-static const uint32_t kAccVolatile = 0x0040;  // field
-static const uint32_t kAccBridge = 0x0040;  // method (1.5)
-static const uint32_t kAccTransient = 0x0080;  // field
-static const uint32_t kAccVarargs = 0x0080;  // method (1.5)
-static const uint32_t kAccNative = 0x0100;  // method
-static const uint32_t kAccInterface = 0x0200;  // class, ic
-static const uint32_t kAccAbstract = 0x0400;  // class, method, ic
-static const uint32_t kAccStrict = 0x0800;  // method
-static const uint32_t kAccSynthetic = 0x1000;  // field, method, ic
-static const uint32_t kAccAnnotation = 0x2000;  // class, ic (1.5)
-static const uint32_t kAccEnum = 0x4000;  // class, field, ic (1.5)
-
-static const uint32_t kAccMiranda = 0x8000;  // method
-
-static const uint32_t kAccJavaFlagsMask = 0xffff;  // bits set from Java sources (low 16)
-
-static const uint32_t kAccConstructor = 0x00010000;  // method (dex only)
-static const uint32_t kAccDeclaredSynchronized = 0x00020000;  // method (dex only)
-static const uint32_t kAccClassIsProxy = 0x00040000;  // class (dex only)
-
-// Special runtime-only flags.
-// Note: if only kAccClassIsReference is set, we have a soft reference.
-static const uint32_t kAccClassIsFinalizable        = 0x80000000;  // class/ancestor overrides finalize()
-static const uint32_t kAccClassIsReference          = 0x08000000;  // class is a soft/weak/phantom ref
-static const uint32_t kAccClassIsWeakReference      = 0x04000000;  // class is a weak reference
-static const uint32_t kAccClassIsFinalizerReference = 0x02000000;  // class is a finalizer reference
-static const uint32_t kAccClassIsPhantomReference   = 0x01000000;  // class is a phantom reference
-
-static const uint32_t kAccReferenceFlagsMask = (kAccClassIsReference
-                                                | kAccClassIsWeakReference
-                                                | kAccClassIsFinalizerReference
-                                                | kAccClassIsPhantomReference);
-
 /*
  * Definitions for packing refOffsets in Class.
  */
@@ -567,6 +529,9 @@
     SetField32(OFFSET_OF_OBJECT_MEMBER(Method, access_flags_), new_access_flags, false);
   }
 
+  // Approximate what kind of method call would be used for this method.
+  InvokeType GetInvokeType() const;
+
   // Returns true if the method is declared public.
   bool IsPublic() const {
     return (GetAccessFlags() & kAccPublic) != 0;
@@ -624,6 +589,8 @@
 
   bool IsProxyMethod() const;
 
+  bool CheckIncompatibleClassChange(InvokeType type);
+
   uint16_t GetMethodIndex() const;
 
   size_t GetVtableIndex() const {
@@ -2484,6 +2451,30 @@
   return GetField32(OFFSET_OF_OBJECT_MEMBER(Method, method_dex_index_), false);
 }
 
+inline bool Method::CheckIncompatibleClassChange(InvokeType type) {
+  bool icce = true;
+  switch (type) {
+    case kStatic:
+      icce = !IsStatic();
+      break;
+    case kDirect:
+      icce = !IsDirect();
+      break;
+    case kVirtual:
+      icce = IsDirect();
+      break;
+    case kSuper:
+      icce = false;
+      break;
+    case kInterface: {
+      Class* methods_class = GetDeclaringClass();
+      icce = IsDirect() || !(methods_class->IsInterface() || methods_class->IsObjectClass());
+      break;
+    }
+  }
+  return icce;
+}
+
 inline void Method::AssertPcIsWithinCode(uintptr_t pc) const {
   if (!kIsDebugBuild) {
     return;
diff --git a/src/object_test.cc b/src/object_test.cc
index bbb96c6..e44cf64 100644
--- a/src/object_test.cc
+++ b/src/object_test.cc
@@ -234,8 +234,8 @@
   ASSERT_TRUE(field_id != NULL);
   uint32_t field_idx = dex_file->GetIndexForFieldId(*field_id);
 
-  Field* field = FindFieldFromCode(field_idx, clinit, Thread::Current(), true,
-                                   false, false, sizeof(Object*));
+  Field* field = FindFieldFromCode(field_idx, clinit, Thread::Current(), StaticObjectRead,
+                                   sizeof(Object*));
   Object* s0 = field->GetObj(NULL);
   EXPECT_EQ(NULL, s0);
 
diff --git a/src/runtime_support.cc b/src/runtime_support.cc
index 0caccf6..91710e7 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -93,7 +93,7 @@
                                      Class* referrer,
                                      Class* accessed) {
   self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
-                           "illegal class access: '%s' -> '%s'",
+                           "Illegal class access: '%s' -> '%s'",
                            PrettyDescriptor(referrer).c_str(),
                            PrettyDescriptor(accessed).c_str());
 }
@@ -105,7 +105,7 @@
                                                       const Method* called,
                                                       InvokeType type) {
   self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
-                           "illegal class access ('%s' -> '%s')"
+                           "Illegal class access ('%s' -> '%s')"
                            "in attempt to invoke %s method '%s' from '%s'",
                            PrettyDescriptor(referrer).c_str(),
                            PrettyDescriptor(accessed).c_str(),
@@ -114,15 +114,60 @@
                            PrettyMethod(caller).c_str());
 }
 
-void ThrowNewIncompatibleClassChangeErrorClassForInterfaceDispatch(Thread* self,
-                                                                   const Method* referrer,
-                                                                   const Method* interface_method,
-                                                                   Object* this_object) {
+static void ThrowNewIncompatibleClassChangeErrorClassForInterfaceDispatch(Thread* self,
+                                                                          const Method* interface_method,
+                                                                          Object* this_object)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
+  std::string interface_method_name(PrettyMethod(interface_method));
+  if (this_object != NULL) {
+    std::string this_class_descriptor(PrettyDescriptor(this_object->GetClass()));
+    std::string interface_class_descriptor(PrettyDescriptor(interface_method->GetDeclaringClass()));
+    self->ThrowNewExceptionF("Ljava/lang/IncompatibleClassChangeError;",
+                             "Class '%s' does not implement interface '%s' in call to '%s'",
+                             this_class_descriptor.c_str(),
+                             interface_class_descriptor.c_str(),
+                             interface_method_name.c_str());
+  } else {
+    self->ThrowNewExceptionF("Ljava/lang/IncompatibleClassChangeError;",
+                             "Expected '%s' to be an interface method",
+                             interface_method_name.c_str());
+  }
+}
+
+static void ThrowNewIncompatibleClassChangeErrorField(Thread* self, const Field* resolved_field,
+                                               bool is_static)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   self->ThrowNewExceptionF("Ljava/lang/IncompatibleClassChangeError;",
-                           "class '%s' does not implement interface '%s' in call to '%s' from '%s'",
-                           PrettyDescriptor(this_object->GetClass()).c_str(),
-                           PrettyDescriptor(interface_method->GetDeclaringClass()).c_str(),
-                           PrettyMethod(interface_method).c_str(), PrettyMethod(referrer).c_str());
+                           "Expected '%s' to be a %s field",
+                           PrettyField(resolved_field).c_str(),
+                           is_static ? "static" : "instance");
+}
+
+void ThrowIncompatibleClassChangeError(InvokeType expected_type, InvokeType found_type,
+                                       Method* method) {
+  std::ostringstream msg;
+  msg << "The method '" << PrettyMethod(method) << "' was expected to be of type"
+      << expected_type << " but instead was found to be of type " << found_type;
+  ClassHelper kh(method->GetDeclaringClass());
+  std::string location(kh.GetLocation());
+  if (!location.empty()) {
+    msg << " (accessed from " << location << ")";
+  }
+  Thread::Current()->ThrowNewException("Ljava/lang/IncompatibleClassChangeError;",
+                                       msg.str().c_str());
+}
+
+void ThrowNoSuchMethodError(InvokeType type, Class* c, const StringPiece& name,
+                            const StringPiece& signature) {
+  ClassHelper kh(c);
+  std::ostringstream msg;
+  msg << "No " << type << " method " << name << signature
+      << " in class " << kh.GetDescriptor() << " or its superclasses";
+  std::string location(kh.GetLocation());
+  if (!location.empty()) {
+    msg << " (accessed from " << location << ")";
+  }
+  Thread::Current()->ThrowNewException("Ljava/lang/NoSuchMethodError;", msg.str().c_str());
 }
 
 void ThrowNewIllegalAccessErrorField(Thread* self,
@@ -413,15 +458,32 @@
   }
 }
 
-// Slow path field resolution and declaring class initialization
 Field* FindFieldFromCode(uint32_t field_idx, const Method* referrer, Thread* self,
-                         bool is_static, bool is_primitive, bool is_set, size_t expected_size) {
+                         FindFieldType type, size_t expected_size) {
+  bool is_primitive;
+  bool is_set;
+  bool is_static;
+  switch (type) {
+    case InstanceObjectRead:     is_primitive = false; is_set = false; is_static = false; break;
+    case InstanceObjectWrite:    is_primitive = false; is_set = true;  is_static = false; break;
+    case InstancePrimitiveRead:  is_primitive = true;  is_set = false; is_static = false; break;
+    case InstancePrimitiveWrite: is_primitive = true;  is_set = true;  is_static = false; break;
+    case StaticObjectRead:       is_primitive = false; is_set = false; is_static = true;  break;
+    case StaticObjectWrite:      is_primitive = false; is_set = true;  is_static = true;  break;
+    case StaticPrimitiveRead:    is_primitive = true;  is_set = false; is_static = true;  break;
+    case StaticPrimitiveWrite:   // Keep GCC happy by having a default handler, fall-through.
+    default:                     is_primitive = true;  is_set = true;  is_static = true;  break;
+  }
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   Field* resolved_field = class_linker->ResolveField(field_idx, referrer, is_static);
   if (UNLIKELY(resolved_field == NULL)) {
-    DCHECK(self->IsExceptionPending());  // Throw exception and unwind
-    return NULL;  // failure
+    DCHECK(self->IsExceptionPending());  // Throw exception and unwind.
+    return NULL;  // Failure.
   } else {
+    if (resolved_field->IsStatic() != is_static) {
+      ThrowNewIncompatibleClassChangeErrorField(self, resolved_field, is_static);
+      return NULL;
+    }
     Class* fields_class = resolved_field->GetDeclaringClass();
     Class* referring_class = referrer->GetDeclaringClass();
     if (UNLIKELY(!referring_class->CanAccess(fields_class) ||
@@ -480,10 +542,10 @@
                            Thread* self, bool access_check, InvokeType type) {
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   bool is_direct = type == kStatic || type == kDirect;
-  Method* resolved_method = class_linker->ResolveMethod(method_idx, referrer, is_direct);
+  Method* resolved_method = class_linker->ResolveMethod(method_idx, referrer, type);
   if (UNLIKELY(resolved_method == NULL)) {
-    DCHECK(self->IsExceptionPending());  // Throw exception and unwind
-    return NULL;  // failure
+    DCHECK(self->IsExceptionPending());  // Throw exception and unwind.
+    return NULL;  // Failure.
   } else {
     if (!access_check) {
       if (is_direct) {
@@ -492,10 +554,10 @@
         Method* interface_method =
             this_object->GetClass()->FindVirtualMethodForInterface(resolved_method);
         if (UNLIKELY(interface_method == NULL)) {
-          ThrowNewIncompatibleClassChangeErrorClassForInterfaceDispatch(self, referrer,
+          ThrowNewIncompatibleClassChangeErrorClassForInterfaceDispatch(self,
                                                                         resolved_method,
                                                                         this_object);
-          return NULL;  // failure
+          return NULL;  // Failure.
         } else {
           return interface_method;
         }
@@ -511,6 +573,11 @@
         return vtable->Get(vtable_index);
       }
     } else {
+      // Incompatible class change should have been handled in resolve method.
+      if (UNLIKELY(resolved_method->CheckIncompatibleClassChange(type))) {
+        ThrowIncompatibleClassChangeError(type, resolved_method->GetInvokeType(), resolved_method);
+        return NULL;  // Failure.
+      }
       Class* methods_class = resolved_method->GetDeclaringClass();
       Class* referring_class = referrer->GetDeclaringClass();
       if (UNLIKELY(!referring_class->CanAccess(methods_class) ||
@@ -526,11 +593,11 @@
         if (UNLIKELY(!referring_class->CanAccess(methods_class))) {
           ThrowNewIllegalAccessErrorClassForMethodDispatch(self, referring_class, methods_class,
                                                            referrer, resolved_method, type);
-          return NULL;  // failure
+          return NULL;  // Failure.
         } else if (UNLIKELY(!referring_class->CanAccessMember(methods_class,
                                                               resolved_method->GetAccessFlags()))) {
           ThrowNewIllegalAccessErrorMethod(self, referring_class, resolved_method);
-          return NULL;  // failure
+          return NULL;  // Failure.
         }
       }
       if (is_direct) {
@@ -539,10 +606,10 @@
         Method* interface_method =
             this_object->GetClass()->FindVirtualMethodForInterface(resolved_method);
         if (UNLIKELY(interface_method == NULL)) {
-          ThrowNewIncompatibleClassChangeErrorClassForInterfaceDispatch(self, referrer,
+          ThrowNewIncompatibleClassChangeErrorClassForInterfaceDispatch(self,
                                                                         resolved_method,
                                                                         this_object);
-          return NULL;  // failure
+          return NULL;  // Failure.
         } else {
           return interface_method;
         }
@@ -563,14 +630,11 @@
                    vtable_index < static_cast<uint32_t>(vtable->GetLength()))) {
           return vtable->GetWithoutChecks(vtable_index);
         } else {
-          // Behavior to agree with that of the verifier
-          self->ThrowNewExceptionF("Ljava/lang/NoSuchMethodError;",
-                                   "attempt to invoke %s method '%s' from '%s'"
-                                   " using incorrect form of method dispatch",
-                                   (type == kSuper ? "super class" : "virtual"),
-                                   PrettyMethod(resolved_method).c_str(),
-                                   PrettyMethod(referrer).c_str());
-          return NULL;  // failure
+          // Behavior to agree with that of the verifier.
+          MethodHelper mh(resolved_method);
+          ThrowNoSuchMethodError(type, resolved_method->GetDeclaringClass(), mh.GetName(),
+                                 mh.GetSignature());
+          return NULL;  // Failure.
         }
       }
     }
diff --git a/src/runtime_support.h b/src/runtime_support.h
index 2ea7f99..260202b 100644
--- a/src/runtime_support.h
+++ b/src/runtime_support.h
@@ -57,11 +57,16 @@
                                                                    const Method* interface_method,
                                                                    Object* this_object)
     SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_);
+void ThrowIncompatibleClassChangeError(InvokeType expected_type, InvokeType found_type,
+                                       Method* method)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_);
+void ThrowNoSuchMethodError(InvokeType type, Class* c, const StringPiece& name,
+                            const StringPiece& signature)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_);
 void ThrowNewIllegalAccessErrorField(Thread* self, Class* referrer, Field* accessed)
     SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_);
 void ThrowNewIllegalAccessErrorFinalField(Thread* self, const Method* referrer, Field* accessed)
     SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_);
-
 void ThrowNewIllegalAccessErrorMethod(Thread* self, Class* referrer, Method* accessed)
     SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_);
 void ThrowNullPointerExceptionForFieldAccess(Thread* self, Field* field, bool is_read)
@@ -151,30 +156,62 @@
                                          Thread* self, bool access_check)
     SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_);
 
+// Type of find field operation for fast and slow case.
+enum FindFieldType {
+  InstanceObjectRead,
+  InstanceObjectWrite,
+  InstancePrimitiveRead,
+  InstancePrimitiveWrite,
+  StaticObjectRead,
+  StaticObjectWrite,
+  StaticPrimitiveRead,
+  StaticPrimitiveWrite,
+};
+
+// Slow field find that can initialize classes and may throw exceptions.
 extern Field* FindFieldFromCode(uint32_t field_idx, const Method* referrer, Thread* self,
-                                bool is_static, bool is_primitive, bool is_set,
-                                size_t expected_size)
+                                FindFieldType type, size_t expected_size)
     SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_);
 
-// Fast path field resolution that can't throw exceptions
-static inline Field* FindFieldFast(uint32_t field_idx, const Method* referrer, bool is_primitive,
-                                   size_t expected_size, bool is_set)
+// Fast path field resolution that can't initialize classes or throw exceptions.
+static inline Field* FindFieldFast(uint32_t field_idx, const Method* referrer,
+                                   FindFieldType type, size_t expected_size)
     SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   Field* resolved_field = referrer->GetDeclaringClass()->GetDexCache()->GetResolvedField(field_idx);
   if (UNLIKELY(resolved_field == NULL)) {
     return NULL;
   }
   Class* fields_class = resolved_field->GetDeclaringClass();
-  // Check class is initiliazed or initializing
+  // Check class is initiliazed or initializing.
   if (UNLIKELY(!fields_class->IsInitializing())) {
     return NULL;
   }
+  // Check for incompatible class change.
+  bool is_primitive;
+  bool is_set;
+  bool is_static;
+  switch (type) {
+    case InstanceObjectRead:     is_primitive = false; is_set = false; is_static = false; break;
+    case InstanceObjectWrite:    is_primitive = false; is_set = true;  is_static = false; break;
+    case InstancePrimitiveRead:  is_primitive = true;  is_set = false; is_static = false; break;
+    case InstancePrimitiveWrite: is_primitive = true;  is_set = true;  is_static = false; break;
+    case StaticObjectRead:       is_primitive = false; is_set = false; is_static = true;  break;
+    case StaticObjectWrite:      is_primitive = false; is_set = true;  is_static = true;  break;
+    case StaticPrimitiveRead:    is_primitive = true;  is_set = false; is_static = true;  break;
+    case StaticPrimitiveWrite:   is_primitive = true;  is_set = true;  is_static = true;  break;
+    default: LOG(FATAL) << "UNREACHABLE";  // Assignment below to avoid GCC warnings.
+             is_primitive = true;  is_set = true;  is_static = true;  break;
+  }
+  if (UNLIKELY(resolved_field->IsStatic() != is_static)) {
+    // Incompatible class change.
+    return NULL;
+  }
   Class* referring_class = referrer->GetDeclaringClass();
   if (UNLIKELY(!referring_class->CanAccess(fields_class) ||
                !referring_class->CanAccessMember(fields_class,
                                                  resolved_field->GetAccessFlags()) ||
                (is_set && resolved_field->IsFinal() && (fields_class != referring_class)))) {
-    // illegal access
+    // Illegal access.
     return NULL;
   }
   FieldHelper fh(resolved_field);
@@ -185,9 +222,9 @@
   return resolved_field;
 }
 
-// Fast path method resolution that can't throw exceptions
-static inline Method* FindMethodFast(uint32_t method_idx, Object* this_object, const Method* referrer,
-                                     bool access_check, InvokeType type)
+// Fast path method resolution that can't throw exceptions.
+static inline Method* FindMethodFast(uint32_t method_idx, Object* this_object,
+                                     const Method* referrer, bool access_check, InvokeType type)
     SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   bool is_direct = type == kStatic || type == kDirect;
   if (UNLIKELY(this_object == NULL && !is_direct)) {
@@ -199,12 +236,17 @@
     return NULL;
   }
   if (access_check) {
+    // Check for incompatible class change errors and access.
+    bool icce = resolved_method->CheckIncompatibleClassChange(type);
+    if (UNLIKELY(icce)) {
+      return NULL;
+    }
     Class* methods_class = resolved_method->GetDeclaringClass();
     Class* referring_class = referrer->GetDeclaringClass();
     if (UNLIKELY(!referring_class->CanAccess(methods_class) ||
                  !referring_class->CanAccessMember(methods_class,
                                                    resolved_method->GetAccessFlags()))) {
-      // potential illegal access
+      // Potential illegal access, may need to refine the method's class.
       return NULL;
     }
   }
diff --git a/src/safe_map.h b/src/safe_map.h
index 6df05e2..62a0415 100644
--- a/src/safe_map.h
+++ b/src/safe_map.h
@@ -49,7 +49,7 @@
   bool empty() const { return map_.empty(); }
   size_type size() const { return map_.size(); }
 
-  void clear() { return map_.clear(); }
+  void clear() { map_.clear(); }
   void erase(iterator it) { map_.erase(it); }
   size_type erase(const K& k) { return map_.erase(k); }
 
diff --git a/src/verifier/method_verifier.cc b/src/verifier/method_verifier.cc
index c6c61b9..220741d 100644
--- a/src/verifier/method_verifier.cc
+++ b/src/verifier/method_verifier.cc
@@ -221,7 +221,8 @@
   ClassLinker* linker = Runtime::Current()->GetClassLinker();
   while (it.HasNextDirectMethod()) {
     uint32_t method_idx = it.GetMemberIndex();
-    Method* method = linker->ResolveMethod(*dex_file, method_idx, dex_cache, class_loader, true);
+    InvokeType type = it.GetMethodInvokeType(class_def);
+    Method* method = linker->ResolveMethod(*dex_file, method_idx, dex_cache, class_loader, type);
     if (method == NULL) {
       DCHECK(Thread::Current()->IsExceptionPending());
       // We couldn't resolve the method, but continue regardless.
@@ -246,7 +247,8 @@
   }
   while (it.HasNextVirtualMethod()) {
     uint32_t method_idx = it.GetMemberIndex();
-    Method* method = linker->ResolveMethod(*dex_file, method_idx, dex_cache, class_loader, false);
+    InvokeType type = it.GetMethodInvokeType(class_def);
+    Method* method = linker->ResolveMethod(*dex_file, method_idx, dex_cache, class_loader, type);
     if (method == NULL) {
       DCHECK(Thread::Current()->IsExceptionPending());
       // We couldn't resolve the method, but continue regardless.
@@ -393,21 +395,22 @@
     case VERIFY_ERROR_ACCESS_CLASS:
     case VERIFY_ERROR_ACCESS_FIELD:
     case VERIFY_ERROR_ACCESS_METHOD:
+    case VERIFY_ERROR_INSTANTIATION:
+    case VERIFY_ERROR_CLASS_CHANGE:
       if (Runtime::Current()->IsCompiler()) {
-        // If we're optimistically running verification at compile time, turn NO_xxx and ACCESS_xxx
-        // errors into soft verification errors so that we re-verify at runtime. We may fail to find
-        // or to agree on access because of not yet available class loaders, or class loaders that
-        // will differ at runtime.
+        // If we're optimistically running verification at compile time, turn NO_xxx, ACCESS_xxx,
+        // class change and instantiation errors into soft verification errors so that we re-verify
+        // at runtime. We may fail to find or to agree on access because of not yet available class
+        // loaders, or class loaders that will differ at runtime. In some cases we will rewrite bad
+        // code at runtime but don't want to allow it at compile time due its effect on the
+        // soundness of the code being compiled. These cases, in the generated code, need to run as
+        // "slow paths" that dynamically perform the verification and cause the behavior to be that
+        // akin to an interpreter.
         error = VERIFY_ERROR_BAD_CLASS_SOFT;
       } else {
         have_pending_rewrite_failure_ = true;
       }
       break;
-      // Errors that are bad at both compile and runtime, but don't cause rejection of the class.
-    case VERIFY_ERROR_CLASS_CHANGE:
-    case VERIFY_ERROR_INSTANTIATION:
-      have_pending_rewrite_failure_ = true;
-      break;
       // Indication that verification should be retried at runtime.
     case VERIFY_ERROR_BAD_CLASS_SOFT:
       if (!Runtime::Current()->IsCompiler()) {
@@ -1597,14 +1600,14 @@
       if (!res_type.IsInstantiableTypes()) {
         Fail(VERIFY_ERROR_INSTANTIATION)
             << "new-instance on primitive, interface or abstract class" << res_type;
-      } else {
-        const RegType& uninit_type = reg_types_.Uninitialized(res_type, work_insn_idx_);
-        // Any registers holding previous allocations from this address that have not yet been
-        // initialized must be marked invalid.
-        work_line_->MarkUninitRefsAsInvalid(uninit_type);
-        // add the new uninitialized reference to the register state
-        work_line_->SetRegisterType(dec_insn.vA, uninit_type);
+        // Soft failure so carry on to set register type.
       }
+      const RegType& uninit_type = reg_types_.Uninitialized(res_type, work_insn_idx_);
+      // Any registers holding previous allocations from this address that have not yet been
+      // initialized must be marked invalid.
+      work_line_->MarkUninitRefsAsInvalid(uninit_type);
+      // add the new uninitialized reference to the register state
+      work_line_->SetRegisterType(dec_insn.vA, uninit_type);
       break;
     }
     case Instruction::NEW_ARRAY: