No access check support.

This CL adds support to disable access check when a method is preverified (at
compilation time) and we know we don't need to do any access check.

The interpreter has now two modes of execution: with or without access check.
This is realized by using a template function.

A new runtime access flag kAccPreverified is added onto each method belonging
to a preverified class. If this flag is set, we enter the interpreter in "no
access check" mode. Otherwise, we enter the interpreter in "with access check"
mode.

Change-Id: Ic34163421d5b0aca3d1bce22ef7c095dcf465a18
diff --git a/src/class_linker.cc b/src/class_linker.cc
index c5c669e..6e32065 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -2247,7 +2247,6 @@
   const DexFile& dex_file = *klass->GetDexCache()->GetDexFile();
   mirror::Class::Status oat_file_class_status(mirror::Class::kStatusNotReady);
   bool preverified = VerifyClassUsingOatFile(dex_file, klass, oat_file_class_status);
-  verifier::MethodVerifier::FailureKind verifier_failure = verifier::MethodVerifier::kNoFailure;
   if (oat_file_class_status == mirror::Class::kStatusError) {
     LOG(WARNING) << "Skipping runtime verification of erroneous class " << PrettyDescriptor(klass)
                  << " in " << klass->GetDexCache()->GetLocation()->ToModifiedUtf8();
@@ -2256,9 +2255,11 @@
     klass->SetStatus(mirror::Class::kStatusError);
     return;
   }
+  verifier::MethodVerifier::FailureKind verifier_failure = verifier::MethodVerifier::kNoFailure;
   std::string error_msg;
   if (!preverified) {
-    verifier_failure = verifier::MethodVerifier::VerifyClass(klass, error_msg, Runtime::Current()->IsCompiler());
+    verifier_failure = verifier::MethodVerifier::VerifyClass(klass, error_msg,
+                                                             Runtime::Current()->IsCompiler());
   }
   if (preverified || verifier_failure != verifier::MethodVerifier::kHardFailure) {
     if (!preverified && verifier_failure != verifier::MethodVerifier::kNoFailure) {
@@ -2290,6 +2291,15 @@
     ThrowVerifyError(klass, "%s", error_msg.c_str());
     klass->SetStatus(mirror::Class::kStatusError);
   }
+  if (preverified || verifier_failure == verifier::MethodVerifier::kNoFailure) {
+    // Class is verified so we don't need to do any access check in its methods.
+    // Let the interpreter know it by setting the kAccPreverified flag onto each
+    // method.
+    // Note: we're going here during compilation and at runtime. When we set the
+    // kAccPreverified flag when compiling image classes, the flag is recorded
+    // in the image and is set when loading the image.
+    klass->SetPreverifiedFlagOnAllMethods();
+  }
 }
 
 bool ClassLinker::VerifyClassUsingOatFile(const DexFile& dex_file, mirror::Class* klass,
diff --git a/src/compiler/llvm/runtime_support_llvm.cc b/src/compiler/llvm/runtime_support_llvm.cc
index 6f2d07a..f3cfb33 100644
--- a/src/compiler/llvm/runtime_support_llvm.cc
+++ b/src/compiler/llvm/runtime_support_llvm.cc
@@ -436,7 +436,7 @@
     return 0;
   }
   field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
-                            StaticPrimitiveWrite, sizeof(uint32_t));
+                            StaticPrimitiveWrite, sizeof(uint32_t), true);
   if (LIKELY(field != NULL)) {
     field->Set32(field->GetDeclaringClass(), new_value);
     return 0;
@@ -452,7 +452,7 @@
     return 0;
   }
   field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
-                            StaticPrimitiveWrite, sizeof(uint64_t));
+                            StaticPrimitiveWrite, sizeof(uint64_t), true);
   if (LIKELY(field != NULL)) {
     field->Set64(field->GetDeclaringClass(), new_value);
     return 0;
@@ -468,7 +468,7 @@
     return 0;
   }
   field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
-                            StaticObjectWrite, sizeof(mirror::Object*));
+                            StaticObjectWrite, sizeof(mirror::Object*), true);
   if (LIKELY(field != NULL)) {
     field->SetObj(field->GetDeclaringClass(), new_value);
     return 0;
@@ -483,7 +483,7 @@
     return field->Get32(field->GetDeclaringClass());
   }
   field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
-                            StaticPrimitiveRead, sizeof(uint32_t));
+                            StaticPrimitiveRead, sizeof(uint32_t), true);
   if (LIKELY(field != NULL)) {
     return field->Get32(field->GetDeclaringClass());
   }
@@ -497,7 +497,7 @@
     return field->Get64(field->GetDeclaringClass());
   }
   field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
-                            StaticPrimitiveRead, sizeof(uint64_t));
+                            StaticPrimitiveRead, sizeof(uint64_t), true);
   if (LIKELY(field != NULL)) {
     return field->Get64(field->GetDeclaringClass());
   }
@@ -511,7 +511,7 @@
     return field->GetObj(field->GetDeclaringClass());
   }
   field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
-                            StaticObjectRead, sizeof(mirror::Object*));
+                            StaticObjectRead, sizeof(mirror::Object*), true);
   if (LIKELY(field != NULL)) {
     return field->GetObj(field->GetDeclaringClass());
   }
@@ -527,7 +527,7 @@
     return 0;
   }
   field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
-                            InstancePrimitiveWrite, sizeof(uint32_t));
+                            InstancePrimitiveWrite, sizeof(uint32_t), true);
   if (LIKELY(field != NULL)) {
     field->Set32(obj, new_value);
     return 0;
@@ -544,7 +544,7 @@
     return 0;
   }
   field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
-                            InstancePrimitiveWrite, sizeof(uint64_t));
+                            InstancePrimitiveWrite, sizeof(uint64_t), true);
   if (LIKELY(field != NULL)) {
     field->Set64(obj, new_value);
     return 0;
@@ -561,7 +561,7 @@
     return 0;
   }
   field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
-                            InstanceObjectWrite, sizeof(mirror::Object*));
+                            InstanceObjectWrite, sizeof(mirror::Object*), true);
   if (LIKELY(field != NULL)) {
     field->SetObj(obj, new_value);
     return 0;
@@ -576,7 +576,7 @@
     return field->Get32(obj);
   }
   field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
-                            InstancePrimitiveRead, sizeof(uint32_t));
+                            InstancePrimitiveRead, sizeof(uint32_t), true);
   if (LIKELY(field != NULL)) {
     return field->Get32(obj);
   }
@@ -590,7 +590,7 @@
     return field->Get64(obj);
   }
   field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
-                            InstancePrimitiveRead, sizeof(uint64_t));
+                            InstancePrimitiveRead, sizeof(uint64_t), true);
   if (LIKELY(field != NULL)) {
     return field->Get64(obj);
   }
@@ -604,7 +604,7 @@
     return field->GetObj(obj);
   }
   field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
-                            InstanceObjectRead, sizeof(mirror::Object*));
+                            InstanceObjectRead, sizeof(mirror::Object*), true);
   if (LIKELY(field != NULL)) {
     return field->GetObj(obj);
   }
diff --git a/src/interpreter/interpreter.cc b/src/interpreter/interpreter.cc
index 0e3ed28..657bf43 100644
--- a/src/interpreter/interpreter.cc
+++ b/src/interpreter/interpreter.cc
@@ -386,18 +386,18 @@
 
 // TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template
 // specialization.
-template<InvokeType type, bool is_range>
+template<InvokeType type, bool is_range, bool do_access_check>
 static void DoInvoke(Thread* self, ShadowFrame& shadow_frame,
                      const Instruction* inst, JValue* result) NO_THREAD_SAFETY_ANALYSIS;
 
-template<InvokeType type, bool is_range>
+template<InvokeType type, bool is_range, bool do_access_check>
 static void DoInvoke(Thread* self, ShadowFrame& shadow_frame,
                      const Instruction* inst, JValue* result) {
   uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
   uint32_t vregC = (is_range) ? inst->VRegC_3rc() : inst->VRegC_35c();
   Object* receiver = (type == kStatic) ? NULL : shadow_frame.GetVRegReference(vregC);
   AbstractMethod* method = FindMethodFromCode(method_idx, receiver, shadow_frame.GetMethod(), self,
-                                              true, type);
+                                              do_access_check, type);
   if (UNLIKELY(method == NULL)) {
     CHECK(self->IsExceptionPending());
     result->SetJ(0);
@@ -477,18 +477,19 @@
 // part of the final object file.
 // TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template
 // specialization.
-template<FindFieldType find_type, Primitive::Type field_type>
+template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check>
 static void DoFieldGet(Thread* self, ShadowFrame& shadow_frame,
                        const Instruction* inst)
     NO_THREAD_SAFETY_ANALYSIS ALWAYS_INLINE;
 
-template<FindFieldType find_type, Primitive::Type field_type>
+template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check>
 static inline void DoFieldGet(Thread* self, ShadowFrame& shadow_frame,
                               const Instruction* inst) {
   bool is_static = (find_type == StaticObjectRead) || (find_type == StaticPrimitiveRead);
   uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c();
   Field* f = FindFieldFromCode(field_idx, shadow_frame.GetMethod(), self,
-                               find_type, Primitive::FieldSize(field_type));
+                               find_type, Primitive::FieldSize(field_type),
+                               do_access_check);
   if (UNLIKELY(f == NULL)) {
     CHECK(self->IsExceptionPending());
     return;
@@ -533,18 +534,19 @@
 
 // TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template
 // specialization.
-template<FindFieldType find_type, Primitive::Type field_type>
+template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check>
 static void DoFieldPut(Thread* self, const ShadowFrame& shadow_frame,
                        const Instruction* inst)
     NO_THREAD_SAFETY_ANALYSIS ALWAYS_INLINE;
 
-template<FindFieldType find_type, Primitive::Type field_type>
+template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check>
 static inline void DoFieldPut(Thread* self, const ShadowFrame& shadow_frame,
                               const Instruction* inst) {
   bool is_static = (find_type == StaticObjectWrite) || (find_type == StaticPrimitiveWrite);
   uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c();
   Field* f = FindFieldFromCode(field_idx, shadow_frame.GetMethod(), self,
-                               find_type, Primitive::FieldSize(field_type));
+                               find_type, Primitive::FieldSize(field_type),
+                               do_access_check);
   if (UNLIKELY(f == NULL)) {
     CHECK(self->IsExceptionPending());
     return;
@@ -708,11 +710,15 @@
 // Code to run before each dex instruction.
 #define PREAMBLE()
 
-static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
+// TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template
+// specialization.
+template<bool do_access_check>
+static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
                       ShadowFrame& shadow_frame, JValue result_register)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) __attribute__ ((hot));
+    NO_THREAD_SAFETY_ANALYSIS __attribute__ ((hot));
 
-static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
+template<bool do_access_check>
+static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
                       ShadowFrame& shadow_frame, JValue result_register) {
   if (UNLIKELY(!shadow_frame.HasReferenceArray())) {
     LOG(FATAL) << "Invalid shadow frame for interpreter use";
@@ -984,7 +990,7 @@
       case Instruction::CONST_CLASS: {
         PREAMBLE();
         Class* c = ResolveVerifyAndClinit(inst->VRegB_21c(), shadow_frame.GetMethod(),
-                                          self, false, true);
+                                          self, false, do_access_check);
         if (UNLIKELY(c == NULL)) {
           HANDLE_PENDING_EXCEPTION();
         } else {
@@ -1020,7 +1026,7 @@
       case Instruction::CHECK_CAST: {
         PREAMBLE();
         Class* c = ResolveVerifyAndClinit(inst->VRegB_21c(), shadow_frame.GetMethod(),
-                                          self, false, true);
+                                          self, false, do_access_check);
         if (UNLIKELY(c == NULL)) {
           HANDLE_PENDING_EXCEPTION();
         } else {
@@ -1037,7 +1043,7 @@
       case Instruction::INSTANCE_OF: {
         PREAMBLE();
         Class* c = ResolveVerifyAndClinit(inst->VRegC_22c(), shadow_frame.GetMethod(),
-                                          self, false, true);
+                                          self, false, do_access_check);
         if (UNLIKELY(c == NULL)) {
           HANDLE_PENDING_EXCEPTION();
         } else {
@@ -1062,7 +1068,7 @@
       case Instruction::NEW_INSTANCE: {
         PREAMBLE();
         Object* obj = AllocObjectFromCode(inst->VRegB_21c(), shadow_frame.GetMethod(),
-                                          self, true);
+                                          self, do_access_check);
         if (UNLIKELY(obj == NULL)) {
           HANDLE_PENDING_EXCEPTION();
         } else {
@@ -1075,7 +1081,7 @@
         PREAMBLE();
         int32_t length = shadow_frame.GetVReg(inst->VRegB_22c());
         Object* obj = AllocArrayFromCode(inst->VRegC_22c(), shadow_frame.GetMethod(),
-                                         length, self, true);
+                                         length, self, do_access_check);
         if (UNLIKELY(obj == NULL)) {
           HANDLE_PENDING_EXCEPTION();
         } else {
@@ -1094,7 +1100,7 @@
           break;
         }
         Class* arrayClass = ResolveVerifyAndClinit(inst->VRegB_35c(), shadow_frame.GetMethod(),
-                                                   self, false, true);
+                                                   self, false, do_access_check);
         if (UNLIKELY(arrayClass == NULL)) {
           HANDLE_PENDING_EXCEPTION();
           break;
@@ -1142,7 +1148,7 @@
           break;
         }
         Class* arrayClass = ResolveVerifyAndClinit(inst->VRegB_3rc(), shadow_frame.GetMethod(),
-                                                   self, false, true);
+                                                   self, false, do_access_check);
         if (UNLIKELY(arrayClass == NULL)) {
           HANDLE_PENDING_EXCEPTION();
           break;
@@ -1730,192 +1736,192 @@
       }
       case Instruction::IGET_BOOLEAN:
         PREAMBLE();
-        DoFieldGet<InstancePrimitiveRead, Primitive::kPrimBoolean>(self, shadow_frame, inst);
+        DoFieldGet<InstancePrimitiveRead, Primitive::kPrimBoolean, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::IGET_BYTE:
         PREAMBLE();
-        DoFieldGet<InstancePrimitiveRead, Primitive::kPrimByte>(self, shadow_frame, inst);
+        DoFieldGet<InstancePrimitiveRead, Primitive::kPrimByte, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::IGET_CHAR:
         PREAMBLE();
-        DoFieldGet<InstancePrimitiveRead, Primitive::kPrimChar>(self, shadow_frame, inst);
+        DoFieldGet<InstancePrimitiveRead, Primitive::kPrimChar, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::IGET_SHORT:
         PREAMBLE();
-        DoFieldGet<InstancePrimitiveRead, Primitive::kPrimShort>(self, shadow_frame, inst);
+        DoFieldGet<InstancePrimitiveRead, Primitive::kPrimShort, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::IGET:
         PREAMBLE();
-        DoFieldGet<InstancePrimitiveRead, Primitive::kPrimInt>(self, shadow_frame, inst);
+        DoFieldGet<InstancePrimitiveRead, Primitive::kPrimInt, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::IGET_WIDE:
         PREAMBLE();
-        DoFieldGet<InstancePrimitiveRead, Primitive::kPrimLong>(self, shadow_frame, inst);
+        DoFieldGet<InstancePrimitiveRead, Primitive::kPrimLong, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::IGET_OBJECT:
         PREAMBLE();
-        DoFieldGet<InstanceObjectRead, Primitive::kPrimNot>(self, shadow_frame, inst);
+        DoFieldGet<InstanceObjectRead, Primitive::kPrimNot, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::SGET_BOOLEAN:
         PREAMBLE();
-        DoFieldGet<StaticPrimitiveRead, Primitive::kPrimBoolean>(self, shadow_frame, inst);
+        DoFieldGet<StaticPrimitiveRead, Primitive::kPrimBoolean, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::SGET_BYTE:
         PREAMBLE();
-        DoFieldGet<StaticPrimitiveRead, Primitive::kPrimByte>(self, shadow_frame, inst);
+        DoFieldGet<StaticPrimitiveRead, Primitive::kPrimByte, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::SGET_CHAR:
         PREAMBLE();
-        DoFieldGet<StaticPrimitiveRead, Primitive::kPrimChar>(self, shadow_frame, inst);
+        DoFieldGet<StaticPrimitiveRead, Primitive::kPrimChar, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::SGET_SHORT:
         PREAMBLE();
-        DoFieldGet<StaticPrimitiveRead, Primitive::kPrimShort>(self, shadow_frame, inst);
+        DoFieldGet<StaticPrimitiveRead, Primitive::kPrimShort, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::SGET:
         PREAMBLE();
-        DoFieldGet<StaticPrimitiveRead, Primitive::kPrimInt>(self, shadow_frame, inst);
+        DoFieldGet<StaticPrimitiveRead, Primitive::kPrimInt, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::SGET_WIDE:
         PREAMBLE();
-        DoFieldGet<StaticPrimitiveRead, Primitive::kPrimLong>(self, shadow_frame, inst);
+        DoFieldGet<StaticPrimitiveRead, Primitive::kPrimLong, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::SGET_OBJECT:
         PREAMBLE();
-        DoFieldGet<StaticObjectRead, Primitive::kPrimNot>(self, shadow_frame, inst);
+        DoFieldGet<StaticObjectRead, Primitive::kPrimNot, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::IPUT_BOOLEAN:
         PREAMBLE();
-        DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimBoolean>(self, shadow_frame, inst);
+        DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimBoolean, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::IPUT_BYTE:
         PREAMBLE();
-        DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimByte>(self, shadow_frame, inst);
+        DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimByte, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::IPUT_CHAR:
         PREAMBLE();
-        DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimChar>(self, shadow_frame, inst);
+        DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimChar, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::IPUT_SHORT:
         PREAMBLE();
-        DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimShort>(self, shadow_frame, inst);
+        DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimShort, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::IPUT:
         PREAMBLE();
-        DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimInt>(self, shadow_frame, inst);
+        DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimInt, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::IPUT_WIDE:
         PREAMBLE();
-        DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimLong>(self, shadow_frame, inst);
+        DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimLong, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::IPUT_OBJECT:
         PREAMBLE();
-        DoFieldPut<InstanceObjectWrite, Primitive::kPrimNot>(self, shadow_frame, inst);
+        DoFieldPut<InstanceObjectWrite, Primitive::kPrimNot, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::SPUT_BOOLEAN:
         PREAMBLE();
-        DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimBoolean>(self, shadow_frame, inst);
+        DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimBoolean, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::SPUT_BYTE:
         PREAMBLE();
-        DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimByte>(self, shadow_frame, inst);
+        DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimByte, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::SPUT_CHAR:
         PREAMBLE();
-        DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimChar>(self, shadow_frame, inst);
+        DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimChar, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::SPUT_SHORT:
         PREAMBLE();
-        DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimShort>(self, shadow_frame, inst);
+        DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimShort, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::SPUT:
         PREAMBLE();
-        DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimInt>(self, shadow_frame, inst);
+        DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimInt, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::SPUT_WIDE:
         PREAMBLE();
-        DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimLong>(self, shadow_frame, inst);
+        DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimLong, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::SPUT_OBJECT:
         PREAMBLE();
-        DoFieldPut<StaticObjectWrite, Primitive::kPrimNot>(self, shadow_frame, inst);
+        DoFieldPut<StaticObjectWrite, Primitive::kPrimNot, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::INVOKE_VIRTUAL:
         PREAMBLE();
-        DoInvoke<kVirtual, false>(self, shadow_frame, inst, &result_register);
+        DoInvoke<kVirtual, false, do_access_check>(self, shadow_frame, inst, &result_register);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx);
         break;
       case Instruction::INVOKE_VIRTUAL_RANGE:
         PREAMBLE();
-        DoInvoke<kVirtual, true>(self, shadow_frame, inst, &result_register);
+        DoInvoke<kVirtual, true, do_access_check>(self, shadow_frame, inst, &result_register);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx);
         break;
       case Instruction::INVOKE_SUPER:
         PREAMBLE();
-        DoInvoke<kSuper, false>(self, shadow_frame, inst, &result_register);
+        DoInvoke<kSuper, false, do_access_check>(self, shadow_frame, inst, &result_register);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx);
         break;
       case Instruction::INVOKE_SUPER_RANGE:
         PREAMBLE();
-        DoInvoke<kSuper, true>(self, shadow_frame, inst, &result_register);
+        DoInvoke<kSuper, true, do_access_check>(self, shadow_frame, inst, &result_register);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx);
         break;
       case Instruction::INVOKE_DIRECT:
         PREAMBLE();
-        DoInvoke<kDirect, false>(self, shadow_frame, inst, &result_register);
+        DoInvoke<kDirect, false, do_access_check>(self, shadow_frame, inst, &result_register);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx);
         break;
       case Instruction::INVOKE_DIRECT_RANGE:
         PREAMBLE();
-        DoInvoke<kDirect, true>(self, shadow_frame, inst, &result_register);
+        DoInvoke<kDirect, true, do_access_check>(self, shadow_frame, inst, &result_register);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx);
         break;
       case Instruction::INVOKE_INTERFACE:
         PREAMBLE();
-        DoInvoke<kInterface, false>(self, shadow_frame, inst, &result_register);
+        DoInvoke<kInterface, false, do_access_check>(self, shadow_frame, inst, &result_register);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx);
         break;
       case Instruction::INVOKE_INTERFACE_RANGE:
         PREAMBLE();
-        DoInvoke<kInterface, true>(self, shadow_frame, inst, &result_register);
+        DoInvoke<kInterface, true, do_access_check>(self, shadow_frame, inst, &result_register);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx);
         break;
       case Instruction::INVOKE_STATIC:
         PREAMBLE();
-        DoInvoke<kStatic, false>(self, shadow_frame, inst, &result_register);
+        DoInvoke<kStatic, false, do_access_check>(self, shadow_frame, inst, &result_register);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx);
         break;
       case Instruction::INVOKE_STATIC_RANGE:
         PREAMBLE();
-        DoInvoke<kStatic, true>(self, shadow_frame, inst, &result_register);
+        DoInvoke<kStatic, true, do_access_check>(self, shadow_frame, inst, &result_register);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx);
         break;
       case Instruction::NEG_INT:
@@ -2717,6 +2723,21 @@
   }
 }
 
+static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
+                      ShadowFrame& shadow_frame, JValue result_register)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+static inline JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
+                             ShadowFrame& shadow_frame, JValue result_register) {
+  if (shadow_frame.GetMethod()->IsPreverified()) {
+    // Enter the "without access check" interpreter.
+    return ExecuteImpl<false>(self, mh, code_item, shadow_frame, result_register);
+  } else {
+    // Enter the "with access check" interpreter.
+    return ExecuteImpl<true>(self, mh, code_item, shadow_frame, result_register);
+  }
+}
+
 void EnterInterpreterFromInvoke(Thread* self, AbstractMethod* method, Object* receiver,
                                 uint32_t* args, JValue* result) {
   DCHECK_EQ(self, Thread::Current());
diff --git a/src/mirror/abstract_method.h b/src/mirror/abstract_method.h
index 59dfdd57..339471d 100644
--- a/src/mirror/abstract_method.h
+++ b/src/mirror/abstract_method.h
@@ -123,6 +123,14 @@
 
   bool IsProxyMethod() const;
 
+  bool IsPreverified() const {
+    return (GetAccessFlags() & kAccPreverified) != 0;
+  }
+
+  void SetPreverified() {
+    SetAccessFlags(GetAccessFlags() | kAccPreverified);
+  }
+
   bool CheckIncompatibleClassChange(InvokeType type) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   uint16_t GetMethodIndex() const;
diff --git a/src/mirror/class.cc b/src/mirror/class.cc
index 15129ab..2dae90c 100644
--- a/src/mirror/class.cc
+++ b/src/mirror/class.cc
@@ -604,5 +604,22 @@
   return NULL;
 }
 
+static void SetPreverifiedFlagOnMethods(mirror::ObjectArray<mirror::AbstractMethod>* methods)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  if (methods != NULL) {
+    for (int32_t index = 0, end = methods->GetLength(); index < end; ++index) {
+      mirror::AbstractMethod* method = methods->GetWithoutChecks(index);
+      DCHECK(method != NULL);
+      method->SetPreverified();
+    }
+  }
+}
+
+void Class::SetPreverifiedFlagOnAllMethods() {
+  DCHECK(IsVerified());
+  SetPreverifiedFlagOnMethods(GetDirectMethods());
+  SetPreverifiedFlagOnMethods(GetVirtualMethods());
+}
+
 }  // namespace mirror
 }  // namespace art
diff --git a/src/mirror/class.h b/src/mirror/class.h
index 16ca2bd..084aa24 100644
--- a/src/mirror/class.h
+++ b/src/mirror/class.h
@@ -743,6 +743,9 @@
   static void SetClassClass(Class* java_lang_Class);
   static void ResetClass();
 
+  // When class is verified, set the kAccPreverified flag on each method.
+  void SetPreverifiedFlagOnAllMethods() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
  private:
   void SetVerifyErrorClass(Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
diff --git a/src/mirror/object_test.cc b/src/mirror/object_test.cc
index abf6c29..52df544 100644
--- a/src/mirror/object_test.cc
+++ b/src/mirror/object_test.cc
@@ -283,7 +283,7 @@
   uint32_t field_idx = dex_file->GetIndexForFieldId(*field_id);
 
   Field* field = FindFieldFromCode(field_idx, clinit, Thread::Current(), StaticObjectRead,
-                                   sizeof(Object*));
+                                   sizeof(Object*), true);
   Object* s0 = field->GetObj(klass);
   EXPECT_TRUE(s0 != NULL);
 
diff --git a/src/modifiers.h b/src/modifiers.h
index a15b096..85bc06d 100644
--- a/src/modifiers.h
+++ b/src/modifiers.h
@@ -46,7 +46,9 @@
 static const uint32_t kAccDeclaredSynchronized = 0x00020000;  // method (dex only)
 static const uint32_t kAccClassIsProxy = 0x00040000;  // class (dex only)
 // TODO: JACK CLASS ACCESS (HACK TO BE REMOVED)
-static const uint32_t kAccClassJack = 0x000080000;  // class (dex only)
+static const uint32_t kAccClassJack = 0x00080000;  // class (dex only)
+
+static const uint32_t kAccPreverified = 0x00100000;  // method (dex only)
 
 // Special runtime-only flags.
 // Note: if only kAccClassIsReference is set, we have a soft reference.
diff --git a/src/oat/runtime/support_field.cc b/src/oat/runtime/support_field.cc
index 5821063..c20326c 100644
--- a/src/oat/runtime/support_field.cc
+++ b/src/oat/runtime/support_field.cc
@@ -34,7 +34,7 @@
     return field->Get32(field->GetDeclaringClass());
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
-  field = FindFieldFromCode(field_idx, referrer, self, StaticPrimitiveRead, sizeof(int32_t));
+  field = FindFieldFromCode(field_idx, referrer, self, StaticPrimitiveRead, sizeof(int32_t), true);
   if (LIKELY(field != NULL)) {
     return field->Get32(field->GetDeclaringClass());
   }
@@ -50,7 +50,7 @@
     return field->Get64(field->GetDeclaringClass());
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
-  field = FindFieldFromCode(field_idx, referrer, self, StaticPrimitiveRead, sizeof(int64_t));
+  field = FindFieldFromCode(field_idx, referrer, self, StaticPrimitiveRead, sizeof(int64_t), true);
   if (LIKELY(field != NULL)) {
     return field->Get64(field->GetDeclaringClass());
   }
@@ -67,7 +67,7 @@
     return field->GetObj(field->GetDeclaringClass());
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
-  field = FindFieldFromCode(field_idx, referrer, self, StaticObjectRead, sizeof(mirror::Object*));
+  field = FindFieldFromCode(field_idx, referrer, self, StaticObjectRead, sizeof(mirror::Object*), true);
   if (LIKELY(field != NULL)) {
     return field->GetObj(field->GetDeclaringClass());
   }
@@ -83,7 +83,7 @@
     return field->Get32(obj);
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
-  field = FindFieldFromCode(field_idx, referrer, self, InstancePrimitiveRead, sizeof(int32_t));
+  field = FindFieldFromCode(field_idx, referrer, self, InstancePrimitiveRead, sizeof(int32_t), true);
   if (LIKELY(field != NULL)) {
     if (UNLIKELY(obj == NULL)) {
       ThrowLocation throw_location = self->GetCurrentLocationForThrow();
@@ -104,7 +104,7 @@
     return field->Get64(obj);
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
-  field = FindFieldFromCode(field_idx, referrer, self, InstancePrimitiveRead, sizeof(int64_t));
+  field = FindFieldFromCode(field_idx, referrer, self, InstancePrimitiveRead, sizeof(int64_t), true);
   if (LIKELY(field != NULL)) {
     if (UNLIKELY(obj == NULL)) {
       ThrowLocation throw_location = self->GetCurrentLocationForThrow();
@@ -126,7 +126,7 @@
     return field->GetObj(obj);
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
-  field = FindFieldFromCode(field_idx, referrer, self, InstanceObjectRead, sizeof(mirror::Object*));
+  field = FindFieldFromCode(field_idx, referrer, self, InstanceObjectRead, sizeof(mirror::Object*), true);
   if (LIKELY(field != NULL)) {
     if (UNLIKELY(obj == NULL)) {
       ThrowLocation throw_location = self->GetCurrentLocationForThrow();
@@ -148,7 +148,7 @@
     return 0;  // success
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
-  field = FindFieldFromCode(field_idx, referrer, self, StaticPrimitiveWrite, sizeof(int32_t));
+  field = FindFieldFromCode(field_idx, referrer, self, StaticPrimitiveWrite, sizeof(int32_t), true);
   if (LIKELY(field != NULL)) {
     field->Set32(field->GetDeclaringClass(), new_value);
     return 0;  // success
@@ -165,7 +165,7 @@
     return 0;  // success
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
-  field = FindFieldFromCode(field_idx, referrer, self, StaticPrimitiveWrite, sizeof(int64_t));
+  field = FindFieldFromCode(field_idx, referrer, self, StaticPrimitiveWrite, sizeof(int64_t), true);
   if (LIKELY(field != NULL)) {
     field->Set64(field->GetDeclaringClass(), new_value);
     return 0;  // success
@@ -186,7 +186,7 @@
     }
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
-  field = FindFieldFromCode(field_idx, referrer, self, StaticObjectWrite, sizeof(mirror::Object*));
+  field = FindFieldFromCode(field_idx, referrer, self, StaticObjectWrite, sizeof(mirror::Object*), true);
   if (LIKELY(field != NULL)) {
     field->SetObj(field->GetDeclaringClass(), new_value);
     return 0;  // success
@@ -204,7 +204,7 @@
     return 0;  // success
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
-  field = FindFieldFromCode(field_idx, referrer, self, InstancePrimitiveWrite, sizeof(int32_t));
+  field = FindFieldFromCode(field_idx, referrer, self, InstancePrimitiveWrite, sizeof(int32_t), true);
   if (LIKELY(field != NULL)) {
     if (UNLIKELY(obj == NULL)) {
       ThrowLocation throw_location = self->GetCurrentLocationForThrow();
@@ -231,7 +231,7 @@
   }
   *sp = callee_save;
   self->SetTopOfStack(sp, 0);
-  field = FindFieldFromCode(field_idx, referrer, self, InstancePrimitiveWrite, sizeof(int64_t));
+  field = FindFieldFromCode(field_idx, referrer, self, InstancePrimitiveWrite, sizeof(int64_t), true);
   if (LIKELY(field != NULL)) {
     if (UNLIKELY(obj == NULL)) {
       ThrowLocation throw_location = self->GetCurrentLocationForThrow();
@@ -257,7 +257,7 @@
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
   field = FindFieldFromCode(field_idx, referrer, self, InstanceObjectWrite,
-                            sizeof(mirror::Object*));
+                            sizeof(mirror::Object*), true);
   if (LIKELY(field != NULL)) {
     if (UNLIKELY(obj == NULL)) {
       ThrowLocation throw_location = self->GetCurrentLocationForThrow();
diff --git a/src/runtime_support.cc b/src/runtime_support.cc
index 9242c87..f6225ed 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -142,7 +142,8 @@
 }
 
 mirror::Field* FindFieldFromCode(uint32_t field_idx, const mirror::AbstractMethod* referrer,
-                                 Thread* self, FindFieldType type, size_t expected_size) {
+                                 Thread* self, FindFieldType type, size_t expected_size,
+                                 bool access_check) {
   bool is_primitive;
   bool is_set;
   bool is_static;
@@ -162,12 +163,13 @@
   if (UNLIKELY(resolved_field == NULL)) {
     DCHECK(self->IsExceptionPending());  // Throw exception and unwind.
     return NULL;  // Failure.
-  } else {
+  }
+  mirror::Class* fields_class = resolved_field->GetDeclaringClass();
+  if (access_check) {
     if (UNLIKELY(resolved_field->IsStatic() != is_static)) {
       ThrowIncompatibleClassChangeErrorField(resolved_field, is_static, referrer);
       return NULL;
     }
-    mirror::Class* fields_class = resolved_field->GetDeclaringClass();
     mirror::Class* referring_class = referrer->GetDeclaringClass();
     if (UNLIKELY(!referring_class->CanAccess(fields_class) ||
                  !referring_class->CanAccessMember(fields_class,
@@ -203,23 +205,24 @@
                                  is_primitive ? "primitive" : "non-primitive",
                                  PrettyField(resolved_field, true).c_str());
         return NULL;  // failure
-      } else if (!is_static) {
-        // instance fields must be being accessed on an initialized class
-        return resolved_field;
-      } else {
-        // If the class is initialized we're done.
-        if (fields_class->IsInitialized()) {
-          return resolved_field;
-        } else if (Runtime::Current()->GetClassLinker()->EnsureInitialized(fields_class, true, true)) {
-          // Otherwise let's ensure the class is initialized before resolving the field.
-          return resolved_field;
-        } else {
-          DCHECK(self->IsExceptionPending());  // Throw exception and unwind
-          return NULL;  // failure
-        }
       }
     }
   }
+  if (!is_static) {
+    // instance fields must be being accessed on an initialized class
+    return resolved_field;
+  } else {
+    // If the class is initialized we're done.
+    if (fields_class->IsInitialized()) {
+      return resolved_field;
+    } else if (Runtime::Current()->GetClassLinker()->EnsureInitialized(fields_class, true, true)) {
+      // Otherwise let's ensure the class is initialized before resolving the field.
+      return resolved_field;
+    } else {
+      DCHECK(self->IsExceptionPending());  // Throw exception and unwind
+      return NULL;  // failure
+    }
+  }
 }
 
 // Slow path method resolution
diff --git a/src/runtime_support.h b/src/runtime_support.h
index 094e23a..0cb82a5 100644
--- a/src/runtime_support.h
+++ b/src/runtime_support.h
@@ -144,7 +144,8 @@
 
 // Slow field find that can initialize classes and may throw exceptions.
 extern mirror::Field* FindFieldFromCode(uint32_t field_idx, const mirror::AbstractMethod* referrer,
-                                        Thread* self, FindFieldType type, size_t expected_size)
+                                        Thread* self, FindFieldType type, size_t expected_size,
+                                        bool access_check)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
 // Fast path field resolution that can't initialize classes or throw exceptions.