Numerous fixes to compiler and verifier for cts vm-tests.

ClassNotFoundExceptions in ResolveType are converted to
NoClassDefFoundErrors.

Compiler checks for puts into final fields.

Method resolution searches direct methods if an appropriate virtual
method can't be found.

Invocations of <clinit> are rejected by the verifier.

Invoke-super and invoke-virtual can't be used on private methods.

Using invoke-interface on non-interface methods and not using
invoke-interface on interface methods leads do an error.

Change-Id: Ia589f1ffccf91b62812ee34c8c5fae1aaf3798c6
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 449bb53..f48a25c 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -188,6 +188,7 @@
   "Ldalvik/system/BaseDexClassLoader;",
   "Ldalvik/system/PathClassLoader;",
   "Ljava/lang/Throwable;",
+  "Ljava/lang/ClassNotFoundException;",
   "Ljava/lang/StackTraceElement;",
   "Z",
   "B",
@@ -458,9 +459,11 @@
   SetClassRoot(kDalvikSystemPathClassLoader, dalvik_system_PathClassLoader);
   PathClassLoader::SetClass(dalvik_system_PathClassLoader);
 
-  // Set up java.lang.Throwable and java.lang.StackTraceElement as a convenience
+  // Set up java.lang.Throwable, java.lang.ClassNotFoundException, and
+  // java.lang.StackTraceElement as a convenience
   SetClassRoot(kJavaLangThrowable, FindSystemClass("Ljava/lang/Throwable;"));
   Throwable::SetClass(GetClassRoot(kJavaLangThrowable));
+  SetClassRoot(kJavaLangClassNotFoundException, FindSystemClass("Ljava/lang/ClassNotFoundException;"));
   SetClassRoot(kJavaLangStackTraceElement, FindSystemClass("Ljava/lang/StackTraceElement;"));
   SetClassRoot(kJavaLangStackTraceElementArrayClass, FindSystemClass("[Ljava/lang/StackTraceElement;"));
   StackTraceElement::SetClass(GetClassRoot(kJavaLangStackTraceElement));
@@ -3180,6 +3183,11 @@
     } else {
       CHECK(Thread::Current()->IsExceptionPending())
           << "Expected pending exception for failed resolution of: " << descriptor;
+      // Convert a ClassNotFoundException to a NoClassDefFoundError
+      if (Thread::Current()->GetException()->InstanceOf(GetClassRoot(kJavaLangClassNotFoundException))) {
+        Thread::Current()->ClearException();
+        ThrowNoClassDefFoundError("Failed resolution of: %s", descriptor);
+      }
     }
   }
   return resolved;
@@ -3218,6 +3226,12 @@
       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) {
+        resolved = klass->FindDirectMethod(name, signature);
+      }
     }
     if (resolved == NULL) {
       ThrowNoSuchMethodError(is_direct, klass, name, signature);
diff --git a/src/class_linker.h b/src/class_linker.h
index d90ac1d..f9c190e 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -441,6 +441,7 @@
     kDalvikSystemBaseDexClassLoader,
     kDalvikSystemPathClassLoader,
     kJavaLangThrowable,
+    kJavaLangClassNotFoundException,
     kJavaLangStackTraceElement,
     kPrimitiveBoolean,
     kPrimitiveByte,
diff --git a/src/compiler.cc b/src/compiler.cc
index c917736..37a7414 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -456,7 +456,7 @@
 }
 
 bool Compiler::ComputeInstanceFieldInfo(uint32_t field_idx, CompilationUnit* cUnit,
-                                        int& field_offset, bool& is_volatile) {
+                                        int& field_offset, bool& is_volatile, bool is_put) {
   // Conservative defaults
   field_offset = -1;
   is_volatile = true;
@@ -466,10 +466,11 @@
     Class* referrer_class = ComputeReferrerClass(cUnit);
     // Try to resolve referring class then access check, failure to pass the
     Class* fields_class = resolved_field->GetDeclaringClass();
-    if (referrer_class != NULL &&
-        referrer_class->CanAccess(fields_class) &&
-        referrer_class->CanAccessMember(fields_class,
-                                        resolved_field->GetAccessFlags())) {
+    bool is_write_to_final_from_wrong_class = is_put && resolved_field->IsFinal() &&
+                                              fields_class != referrer_class;
+    if (referrer_class != NULL && referrer_class->CanAccess(fields_class) &&
+        referrer_class->CanAccessMember(fields_class, resolved_field->GetAccessFlags()) &&
+        !is_write_to_final_from_wrong_class) {
       field_offset = resolved_field->GetOffset().Int32Value();
       is_volatile = resolved_field->IsVolatile();
       stats_->ResolvedInstanceField();
@@ -487,7 +488,7 @@
 
 bool Compiler::ComputeStaticFieldInfo(uint32_t field_idx, CompilationUnit* cUnit,
                                       int& field_offset, int& ssb_index,
-                                      bool& is_referrers_class, bool& is_volatile) {
+                                      bool& is_referrers_class, bool& is_volatile, bool is_put) {
   // Conservative defaults
   field_offset = -1;
   ssb_index = -1;
@@ -499,17 +500,18 @@
     DCHECK(resolved_field->IsStatic());
     Class* referrer_class = ComputeReferrerClass(cUnit);
     if (referrer_class != NULL) {
-      if (resolved_field->GetDeclaringClass() == referrer_class) {
+      Class* fields_class = resolved_field->GetDeclaringClass();
+      if (fields_class == referrer_class) {
         is_referrers_class = true;  // implies no worrying about class initialization
         field_offset = resolved_field->GetOffset().Int32Value();
         is_volatile = resolved_field->IsVolatile();
         stats_->ResolvedLocalStaticField();
         return true;  // fast path
       } else {
-        Class* fields_class = resolved_field->GetDeclaringClass();
+        bool is_write_to_final_from_wrong_class = is_put && resolved_field->IsFinal();
         if (referrer_class->CanAccess(fields_class) &&
-            referrer_class->CanAccessMember(fields_class,
-                                            resolved_field->GetAccessFlags())) {
+            referrer_class->CanAccessMember(fields_class, resolved_field->GetAccessFlags()) &&
+            !is_write_to_final_from_wrong_class) {
           // We have the resolved field, we must make it into a ssbIndex for the referrer
           // in its static storage base (which may fail if it doesn't have a slot for it)
           // TODO: for images we can elide the static storage base null check
diff --git a/src/compiler.h b/src/compiler.h
index 0c6b2bf..ce2d3c2 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -107,13 +107,13 @@
 
   // Can we fast path instance field access? Computes field's offset and volatility
   bool ComputeInstanceFieldInfo(uint32_t field_idx, CompilationUnit* cUnit,
-                                int& field_offset, bool& is_volatile);
+                                int& field_offset, bool& is_volatile, bool is_put);
 
   // Can we fastpath static field access? Computes field's offset, volatility and whether the
   // field is within the referrer (which can avoid checking class initialization)
   bool ComputeStaticFieldInfo(uint32_t field_idx, CompilationUnit* cUnit,
                               int& field_offset, int& ssb_index,
-                              bool& is_referrers_class, bool& is_volatile);
+                              bool& is_referrers_class, bool& is_volatile, bool is_put);
 
   // Can we fastpath a interface, super class or virtual method call? Computes method's vtable index
   bool ComputeInvokeInfo(uint32_t method_idx, CompilationUnit* cUnit, InvokeType type,
diff --git a/src/compiler/codegen/arm/MethodCodegenDriver.cc b/src/compiler/codegen/arm/MethodCodegenDriver.cc
index a1793e0..3e844fd 100644
--- a/src/compiler/codegen/arm/MethodCodegenDriver.cc
+++ b/src/compiler/codegen/arm/MethodCodegenDriver.cc
@@ -177,7 +177,7 @@
     bool fastPath =
         cUnit->compiler->ComputeStaticFieldInfo(fieldIdx, cUnit,
                                                 fieldOffset, ssbIndex,
-                                                isReferrersClass, isVolatile);
+                                                isReferrersClass, isVolatile, true);
     if (fastPath && !SLOW_FIELD_PATH) {
         DCHECK_GE(fieldOffset, 0);
         int rBase;
@@ -271,7 +271,7 @@
     bool fastPath =
         cUnit->compiler->ComputeStaticFieldInfo(fieldIdx, cUnit,
                                                 fieldOffset, ssbIndex,
-                                                isReferrersClass, isVolatile);
+                                                isReferrersClass, isVolatile, false);
     if (fastPath && !SLOW_FIELD_PATH) {
         DCHECK_GE(fieldOffset, 0);
         int rBase;
diff --git a/src/compiler/codegen/arm/Thumb2/Gen.cc b/src/compiler/codegen/arm/Thumb2/Gen.cc
index db51fb8..dff05b7 100644
--- a/src/compiler/codegen/arm/Thumb2/Gen.cc
+++ b/src/compiler/codegen/arm/Thumb2/Gen.cc
@@ -415,7 +415,7 @@
     uint32_t fieldIdx = mir->dalvikInsn.vC;
     bool fastPath =
         cUnit->compiler->ComputeInstanceFieldInfo(fieldIdx, cUnit,
-                                                  fieldOffset, isVolatile);
+                                                  fieldOffset, isVolatile, false);
     if (fastPath && !SLOW_FIELD_PATH) {
         RegLocation rlResult;
         RegisterClass regClass = oatRegClassBySize(size);
@@ -470,7 +470,7 @@
     uint32_t fieldIdx = mir->dalvikInsn.vC;
     bool fastPath =
         cUnit->compiler->ComputeInstanceFieldInfo(fieldIdx, cUnit,
-                                                  fieldOffset, isVolatile);
+                                                  fieldOffset, isVolatile, true);
     if (fastPath && !SLOW_FIELD_PATH) {
         RegisterClass regClass = oatRegClassBySize(size);
         DCHECK_GE(fieldOffset, 0);
diff --git a/src/dex_verifier.cc b/src/dex_verifier.cc
index fb68470..65b0734 100644
--- a/src/dex_verifier.cc
+++ b/src/dex_verifier.cc
@@ -2168,6 +2168,10 @@
     }
     case Instruction::NEW_INSTANCE: {
       const RegType& res_type = ResolveClassAndCheckAccess(dec_insn.vB_);
+      if (res_type.IsUnknown()) {
+        CHECK_NE(failure_, VERIFY_ERROR_NONE);
+        break;  // couldn't resolve class
+      }
       // TODO: check Compiler::CanAccessTypeWithoutChecks returns false when res_type is unresolved
       // can't create an instance of an interface or abstract class */
       if (!res_type.IsInstantiableTypes()) {
@@ -3123,26 +3127,27 @@
   return *common_super;
 }
 
-Method* DexVerifier::ResolveMethodAndCheckAccess(uint32_t method_idx, bool is_direct) {
+Method* DexVerifier::ResolveMethodAndCheckAccess(uint32_t method_idx, MethodType method_type) {
   const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx);
   const RegType& klass_type = ResolveClassAndCheckAccess(method_id.class_idx_);
   if (failure_ != VERIFY_ERROR_NONE) {
     fail_messages_ << " in attempt to access method " << dex_file_->GetMethodName(method_id);
     return NULL;
   }
-  if(klass_type.IsUnresolvedTypes()) {
+  if (klass_type.IsUnresolvedTypes()) {
     return NULL;  // Can't resolve Class so no more to do here
   }
+  Class* klass = klass_type.GetClass();
   Class* referrer = method_->GetDeclaringClass();
   DexCache* dex_cache = referrer->GetDexCache();
   Method* res_method = dex_cache->GetResolvedMethod(method_idx);
   if (res_method == NULL) {
-    Class* klass = klass_type.GetClass();
     const char* name = dex_file_->GetMethodName(method_id);
     std::string signature(dex_file_->CreateMethodSignature(method_id.proto_idx_, NULL));
-    if (is_direct) {
+
+    if (method_type == METHOD_DIRECT || method_type == METHOD_STATIC) {
       res_method = klass->FindDirectMethod(name, signature);
-    } else if (klass->IsInterface()) {
+    } else if (method_type == METHOD_INTERFACE) {
       res_method = klass->FindInterfaceMethod(name, signature);
     } else {
       res_method = klass->FindVirtualMethod(name, signature);
@@ -3150,30 +3155,20 @@
     if (res_method != NULL) {
       dex_cache->SetResolvedMethod(method_idx, res_method);
     } else {
-      Fail(VERIFY_ERROR_NO_METHOD) << "couldn't find method "
-                                   << PrettyDescriptor(klass) << "." << name
-                                   << " " << signature;
-      return NULL;
+      // If a virtual or interface method wasn't found with the expected type, look in
+      // the direct methods. This can happen when the wrong invoke type is used or when
+      // a class has changed, and will be flagged as an error in later checks.
+      if (method_type == METHOD_INTERFACE || method_type == METHOD_VIRTUAL) {
+        res_method = klass->FindDirectMethod(name, signature);
+      }
+      if (res_method == NULL) {
+        Fail(VERIFY_ERROR_NO_METHOD) << "couldn't find method "
+                                     << PrettyDescriptor(klass) << "." << name
+                                     << " " << signature;
+        return NULL;
+      }
     }
   }
-  /* Check if access is allowed. */
-  if (!referrer->CanAccessMember(res_method->GetDeclaringClass(), res_method->GetAccessFlags())) {
-    Fail(VERIFY_ERROR_ACCESS_METHOD) << "illegal method access (call " << PrettyMethod(res_method)
-                                  << " from " << PrettyDescriptor(referrer) << ")";
-    return NULL;
-  }
-  return res_method;
-}
-
-Method* DexVerifier::VerifyInvocationArgs(const Instruction::DecodedInstruction& dec_insn,
-                                          MethodType method_type, bool is_range, bool is_super) {
-  // Resolve the method. This could be an abstract or concrete method depending on what sort of call
-  // we're making.
-  Method* res_method = ResolveMethodAndCheckAccess(dec_insn.vB_,
-                           (method_type == METHOD_DIRECT || method_type == METHOD_STATIC));
-  if (res_method == NULL) {  // error or class is unresolved
-    return NULL;
-  }
   // Make sure calls to constructors are "direct". There are additional restrictions but we don't
   // enforce them here.
   if (res_method->IsConstructor() && method_type != METHOD_DIRECT) {
@@ -3181,6 +3176,34 @@
                                << PrettyMethod(res_method);
     return NULL;
   }
+  // Disallow any calls to class initializers.
+  if (MethodHelper(res_method).IsClassInitializer()) {
+    Fail(VERIFY_ERROR_GENERIC) << "rejecting call to class initializer "
+                               << PrettyMethod(res_method);
+    return NULL;
+  }
+  // Check that invoke-virtual and invoke-super are not used on private methods.
+  if (res_method->IsPrivate() && method_type == METHOD_VIRTUAL) {
+    Fail(VERIFY_ERROR_GENERIC) << "invoke-super/virtual can't be used on private method "
+                               << PrettyMethod(res_method);
+    return NULL;
+  }
+  // Check if access is allowed.
+  if (!referrer->CanAccessMember(res_method->GetDeclaringClass(), res_method->GetAccessFlags())) {
+    Fail(VERIFY_ERROR_ACCESS_METHOD) << "illegal method access (call " << PrettyMethod(res_method)
+                                  << " from " << PrettyDescriptor(referrer) << ")";
+    return NULL;
+  }
+  // Check that interface methods match interface classes.
+  if (klass->IsInterface() && method_type != METHOD_INTERFACE) {
+    Fail(VERIFY_ERROR_CLASS_CHANGE) << "non-interface method " << PrettyMethod(res_method)
+                                    << " is in an interface class " << PrettyClass(klass);
+    return NULL;
+  } else if (!klass->IsInterface() && method_type == METHOD_INTERFACE) {
+    Fail(VERIFY_ERROR_CLASS_CHANGE) << "interface method " << PrettyMethod(res_method)
+                                    << " is in a non-interface class " << PrettyClass(klass);
+    return NULL;
+  }
   // See if the method type implied by the invoke instruction matches the access flags for the
   // target method.
   if ((method_type == METHOD_DIRECT && !res_method->IsDirect()) ||
@@ -3191,6 +3214,18 @@
                                     << PrettyMethod(res_method);
     return NULL;
   }
+  return res_method;
+}
+
+Method* DexVerifier::VerifyInvocationArgs(const Instruction::DecodedInstruction& dec_insn,
+                                          MethodType method_type, bool is_range, bool is_super) {
+  // Resolve the method. This could be an abstract or concrete method depending on what sort of call
+  // we're making.
+  Method* res_method = ResolveMethodAndCheckAccess(dec_insn.vB_, method_type);
+  if (res_method == NULL) {  // error or class is unresolved
+    return NULL;
+  }
+
   // If we're using invoke-super(method), make sure that the executing method's class' superclass
   // has a vtable entry for the target method.
   if (is_super) {
@@ -3449,7 +3484,7 @@
               << dex_file_->GetFieldDeclaringClassDescriptor(field_id);
     return NULL;
   }
-  if(klass_type.IsUnresolvedTypes()) {
+  if (klass_type.IsUnresolvedTypes()) {
     return NULL;  // Can't resolve Class so no more to do here
   }
   Field* field = Runtime::Current()->GetClassLinker()->ResolveFieldJLS(field_idx, method_);
@@ -3472,7 +3507,7 @@
   } else if (obj_type.IsZero()) {
     // Cannot infer and check type, however, access will cause null pointer exception
     return field;
-  } else if(obj_type.IsUninitializedReference() &&
+  } else if(obj_type.IsUninitializedTypes() &&
             (!method_->IsConstructor() || method_->GetDeclaringClass() != obj_type.GetClass() ||
              field->GetDeclaringClass() != method_->GetDeclaringClass())) {
     // Field accesses through uninitialized references are only allowable for constructors where
@@ -3637,7 +3672,7 @@
 
 void DexVerifier::ReplaceFailingInstruction() {
   if (Runtime::Current()->IsStarted()) {
-    LOG(ERROR) << "Verification attempting to replacing instructions in " << PrettyMethod(method_)
+    LOG(ERROR) << "Verification attempting to replace instructions in " << PrettyMethod(method_)
                << " " << fail_messages_.str();
     return;
   }
diff --git a/src/dex_verifier.h b/src/dex_verifier.h
index eb0508b..b898859 100644
--- a/src/dex_verifier.h
+++ b/src/dex_verifier.h
@@ -1174,7 +1174,7 @@
    * the referrer can access the resolved method.
    * Does not throw exceptions.
    */
-  Method* ResolveMethodAndCheckAccess(uint32_t method_idx,  bool is_direct);
+  Method* ResolveMethodAndCheckAccess(uint32_t method_idx, MethodType method_type);
 
   /*
    * Verify the arguments to a method. We're executing in "method", making
diff --git a/src/object_test.cc b/src/object_test.cc
index 31b255e..b431d0a 100644
--- a/src/object_test.cc
+++ b/src/object_test.cc
@@ -218,7 +218,7 @@
   uint32_t field_idx = dex_file->GetIndexForFieldId(*field_id);
 
   Field* field = FindFieldFromCode(field_idx, clinit, Thread::Current(), true,
-                                   false, sizeof(Object*));
+                                   false, false, sizeof(Object*));
   Object* s0 = field->GetObj(NULL);
   EXPECT_EQ(NULL, s0);
 
diff --git a/src/runtime_support.cc b/src/runtime_support.cc
index 38d2699..8dd7eed 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -76,6 +76,13 @@
                            PrettyDescriptor(referrer).c_str());
 }
 
+static void ThrowNewIllegalAccessErrorFinalField(Thread* self, const Method* referrer, Field* accessed) {
+  self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
+                           "Final field '%s' cannot be written to by method '%s'",
+                           PrettyField(accessed, false).c_str(),
+                           PrettyMethod(referrer).c_str());
+}
+
 static void ThrowNewIllegalAccessErrorMethod(Thread* self, Class* referrer, Method* accessed) {
   self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
                            "Method '%s' is inaccessible to class '%s'",
@@ -580,7 +587,7 @@
 
 // Fast path field resolution that can't throw exceptions
 static Field* FindFieldFast(uint32_t field_idx, const Method* referrer, bool is_primitive,
-                            size_t expected_size) {
+                            size_t expected_size, bool is_set) {
   Field* resolved_field = referrer->GetDeclaringClass()->GetDexCache()->GetResolvedField(field_idx);
   if (UNLIKELY(resolved_field == NULL)) {
     return NULL;
@@ -593,7 +600,8 @@
   Class* referring_class = referrer->GetDeclaringClass();
   if (UNLIKELY(!referring_class->CanAccess(fields_class) ||
                !referring_class->CanAccessMember(fields_class,
-                                                 resolved_field->GetAccessFlags()))) {
+                                                 resolved_field->GetAccessFlags()) ||
+               (is_set && resolved_field->IsFinal() && (fields_class != referring_class)))) {
     // illegal access
     return NULL;
   }
@@ -608,7 +616,7 @@
 
 // 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, size_t expected_size) {
+                         bool is_static, bool is_primitive, bool is_set, size_t expected_size) {
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   Field* resolved_field = class_linker->ResolveField(field_idx, referrer, is_static);
   if (UNLIKELY(resolved_field == NULL)) {
@@ -624,6 +632,9 @@
                                                           resolved_field->GetAccessFlags()))) {
       ThrowNewIllegalAccessErrorField(self, referring_class, resolved_field);
       return NULL;  // failure
+    } else if (UNLIKELY(is_set && resolved_field->IsFinal() && (fields_class != referring_class))) {
+      ThrowNewIllegalAccessErrorFinalField(self, referrer, resolved_field);
+      return NULL;  // failure
     } else {
       FieldHelper fh(resolved_field);
       if (UNLIKELY(fh.IsPrimitiveType() != is_primitive ||
@@ -655,12 +666,12 @@
 
 extern "C" uint32_t artGet32StaticFromCode(uint32_t field_idx, const Method* referrer,
                                            Thread* self, Method** sp) {
-  Field* field = FindFieldFast(field_idx, referrer, true, sizeof(int32_t));
+  Field* field = FindFieldFast(field_idx, referrer, true, false, sizeof(int32_t));
   if (LIKELY(field != NULL)) {
     return field->Get32(NULL);
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
-  field = FindFieldFromCode(field_idx, referrer, self, true, true, sizeof(int32_t));
+  field = FindFieldFromCode(field_idx, referrer, self, true, true, false, sizeof(int32_t));
   if (LIKELY(field != NULL)) {
     return field->Get32(NULL);
   }
@@ -669,12 +680,12 @@
 
 extern "C" uint64_t artGet64StaticFromCode(uint32_t field_idx, const Method* referrer,
                                            Thread* self, Method** sp) {
-  Field* field = FindFieldFast(field_idx, referrer, true, sizeof(int64_t));
+  Field* field = FindFieldFast(field_idx, referrer, true, false, sizeof(int64_t));
   if (LIKELY(field != NULL)) {
     return field->Get64(NULL);
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
-  field = FindFieldFromCode(field_idx, referrer, self, true, true, sizeof(int64_t));
+  field = FindFieldFromCode(field_idx, referrer, self, true, true, false, sizeof(int64_t));
   if (LIKELY(field != NULL)) {
     return field->Get64(NULL);
   }
@@ -683,12 +694,12 @@
 
 extern "C" Object* artGetObjStaticFromCode(uint32_t field_idx, const Method* referrer,
                                            Thread* self, Method** sp) {
-  Field* field = FindFieldFast(field_idx, referrer, false, sizeof(Object*));
+  Field* field = FindFieldFast(field_idx, referrer, false, false, sizeof(Object*));
   if (LIKELY(field != NULL)) {
     return field->GetObj(NULL);
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
-  field = FindFieldFromCode(field_idx, referrer, self, true, false, sizeof(Object*));
+  field = FindFieldFromCode(field_idx, referrer, self, true, false, false, sizeof(Object*));
   if (LIKELY(field != NULL)) {
     return field->GetObj(NULL);
   }
@@ -697,12 +708,12 @@
 
 extern "C" uint32_t artGet32InstanceFromCode(uint32_t field_idx, Object* obj,
                                              const Method* referrer, Thread* self, Method** sp) {
-  Field* field = FindFieldFast(field_idx, referrer, true, sizeof(int32_t));
+  Field* field = FindFieldFast(field_idx, referrer, true, false, 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, sizeof(int32_t));
+  field = FindFieldFromCode(field_idx, referrer, self, false, true, false, sizeof(int32_t));
   if (LIKELY(field != NULL)) {
     if (UNLIKELY(obj == NULL)) {
       ThrowNullPointerExceptionForFieldAccess(self, field, true);
@@ -715,12 +726,12 @@
 
 extern "C" uint64_t artGet64InstanceFromCode(uint32_t field_idx, Object* obj,
                                              const Method* referrer, Thread* self, Method** sp) {
-  Field* field = FindFieldFast(field_idx, referrer, true, sizeof(int64_t));
+  Field* field = FindFieldFast(field_idx, referrer, true, false, 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, sizeof(int64_t));
+  field = FindFieldFromCode(field_idx, referrer, self, false, true, false, sizeof(int64_t));
   if (LIKELY(field != NULL)) {
     if (UNLIKELY(obj == NULL)) {
       ThrowNullPointerExceptionForFieldAccess(self, field, true);
@@ -733,12 +744,12 @@
 
 extern "C" Object* artGetObjInstanceFromCode(uint32_t field_idx, Object* obj,
                                               const Method* referrer, Thread* self, Method** sp) {
-  Field* field = FindFieldFast(field_idx, referrer, false, sizeof(Object*));
+  Field* field = FindFieldFast(field_idx, referrer, false, false, 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, sizeof(Object*));
+  field = FindFieldFromCode(field_idx, referrer, self, false, false, false, sizeof(Object*));
   if (LIKELY(field != NULL)) {
     if (UNLIKELY(obj == NULL)) {
       ThrowNullPointerExceptionForFieldAccess(self, field, true);
@@ -751,13 +762,13 @@
 
 extern "C" int artSet32StaticFromCode(uint32_t field_idx, uint32_t new_value,
                                       const Method* referrer, Thread* self, Method** sp) {
-  Field* field = FindFieldFast(field_idx, referrer, true, sizeof(int32_t));
+  Field* field = FindFieldFast(field_idx, referrer, true, true, 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, sizeof(int32_t));
+  field = FindFieldFromCode(field_idx, referrer, self, true, true, true, sizeof(int32_t));
   if (LIKELY(field != NULL)) {
     field->Set32(NULL, new_value);
     return 0;  // success
@@ -767,13 +778,13 @@
 
 extern "C" int artSet64StaticFromCode(uint32_t field_idx, const Method* referrer,
                                       uint64_t new_value, Thread* self, Method** sp) {
-  Field* field = FindFieldFast(field_idx, referrer, true, sizeof(int64_t));
+  Field* field = FindFieldFast(field_idx, referrer, true, true, 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, sizeof(int64_t));
+  field = FindFieldFromCode(field_idx, referrer, self, true, true, true, sizeof(int64_t));
   if (LIKELY(field != NULL)) {
     field->Set64(NULL, new_value);
     return 0;  // success
@@ -783,7 +794,7 @@
 
 extern "C" int artSetObjStaticFromCode(uint32_t field_idx, Object* new_value,
                                        const Method* referrer, Thread* self, Method** sp) {
-  Field* field = FindFieldFast(field_idx, referrer, false, sizeof(Object*));
+  Field* field = FindFieldFast(field_idx, referrer, false, true, sizeof(Object*));
   if (LIKELY(field != NULL)) {
     if (LIKELY(!FieldHelper(field).IsPrimitiveType())) {
       field->SetObj(NULL, new_value);
@@ -791,7 +802,7 @@
     }
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
-  field = FindFieldFromCode(field_idx, referrer, self, true, false, sizeof(Object*));
+  field = FindFieldFromCode(field_idx, referrer, self, true, false, true, sizeof(Object*));
   if (LIKELY(field != NULL)) {
     field->SetObj(NULL, new_value);
     return 0;  // success
@@ -801,13 +812,13 @@
 
 extern "C" int artSet32InstanceFromCode(uint32_t field_idx, Object* obj, uint32_t new_value,
                                         const Method* referrer, Thread* self, Method** sp) {
-  Field* field = FindFieldFast(field_idx, referrer, true, sizeof(int32_t));
+  Field* field = FindFieldFast(field_idx, referrer, true, true, 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, sizeof(int32_t));
+  field = FindFieldFromCode(field_idx, referrer, self, false, true, true, sizeof(int32_t));
   if (LIKELY(field != NULL)) {
     if (UNLIKELY(obj == NULL)) {
       ThrowNullPointerExceptionForFieldAccess(self, field, false);
@@ -823,14 +834,14 @@
                                         Thread* self, Method** sp) {
   Method* callee_save = Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsOnly);
   Method* referrer = sp[callee_save->GetFrameSizeInBytes() / sizeof(Method*)];
-  Field* field = FindFieldFast(field_idx, referrer, true, sizeof(int64_t));
+  Field* field = FindFieldFast(field_idx, referrer, true, true, 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, sizeof(int64_t));
+  field = FindFieldFromCode(field_idx, referrer, self, false, true, true, sizeof(int64_t));
   if (LIKELY(field != NULL)) {
     if (UNLIKELY(obj == NULL)) {
       ThrowNullPointerExceptionForFieldAccess(self, field, false);
@@ -844,13 +855,13 @@
 
 extern "C" int artSetObjInstanceFromCode(uint32_t field_idx, Object* obj, Object* new_value,
                                          const Method* referrer, Thread* self, Method** sp) {
-  Field* field = FindFieldFast(field_idx, referrer, false, sizeof(Object*));
+  Field* field = FindFieldFast(field_idx, referrer, false, true, 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, sizeof(Object*));
+  field = FindFieldFromCode(field_idx, referrer, self, false, false, true, sizeof(Object*));
   if (LIKELY(field != NULL)) {
     if (UNLIKELY(obj == NULL)) {
       ThrowNullPointerExceptionForFieldAccess(self, field, false);
diff --git a/src/runtime_support.h b/src/runtime_support.h
index 97197e6..5831b16 100644
--- a/src/runtime_support.h
+++ b/src/runtime_support.h
@@ -31,7 +31,7 @@
 extern void UpdateDebuggerFromCode(Method* method, Thread* thread , int32_t dex_pc, Method** sp);
 extern Object* DecodeJObjectInThread(Thread* thread, jobject obj);
 extern Field* FindFieldFromCode(uint32_t field_idx, const Method* referrer, Thread* self,
-                                bool is_static, bool is_primitive, size_t expected_size);
+                                bool is_static, bool is_primitive, bool is_set, size_t expected_size);
 extern void* FindNativeMethod(Thread* thread);
 extern void ThrowAbstractMethodErrorFromCode(Method* method, Thread* thread, Method** sp);
 void* UnresolvedDirectMethodTrampolineFromCode(int32_t, Method**, Thread*, Runtime::TrampolineType);