Merge "ART: Fix possible soft+hard failure in verifier" into lmp-mr1-dev
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 4897381..c88a295 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -2117,91 +2117,95 @@
       break;
 
     case Instruction::IGET_BOOLEAN:
-      VerifyISGet(inst, reg_types_.Boolean(), true, false);
+      VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Boolean(), true, false);
       break;
     case Instruction::IGET_BYTE:
-      VerifyISGet(inst, reg_types_.Byte(), true, false);
+      VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Byte(), true, false);
       break;
     case Instruction::IGET_CHAR:
-      VerifyISGet(inst, reg_types_.Char(), true, false);
+      VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Char(), true, false);
       break;
     case Instruction::IGET_SHORT:
-      VerifyISGet(inst, reg_types_.Short(), true, false);
+      VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Short(), true, false);
       break;
     case Instruction::IGET:
-      VerifyISGet(inst, reg_types_.Integer(), true, false);
+      VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Integer(), true, false);
       break;
     case Instruction::IGET_WIDE:
-      VerifyISGet(inst, reg_types_.LongLo(), true, false);
+      VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.LongLo(), true, false);
       break;
     case Instruction::IGET_OBJECT:
-      VerifyISGet(inst, reg_types_.JavaLangObject(false), false, false);
+      VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.JavaLangObject(false), false,
+                                                    false);
       break;
 
     case Instruction::IPUT_BOOLEAN:
-      VerifyISPut(inst, reg_types_.Boolean(), true, false);
+      VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Boolean(), true, false);
       break;
     case Instruction::IPUT_BYTE:
-      VerifyISPut(inst, reg_types_.Byte(), true, false);
+      VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Byte(), true, false);
       break;
     case Instruction::IPUT_CHAR:
-      VerifyISPut(inst, reg_types_.Char(), true, false);
+      VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Char(), true, false);
       break;
     case Instruction::IPUT_SHORT:
-      VerifyISPut(inst, reg_types_.Short(), true, false);
+      VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Short(), true, false);
       break;
     case Instruction::IPUT:
-      VerifyISPut(inst, reg_types_.Integer(), true, false);
+      VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Integer(), true, false);
       break;
     case Instruction::IPUT_WIDE:
-      VerifyISPut(inst, reg_types_.LongLo(), true, false);
+      VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.LongLo(), true, false);
       break;
     case Instruction::IPUT_OBJECT:
-      VerifyISPut(inst, reg_types_.JavaLangObject(false), false, false);
+      VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.JavaLangObject(false), false,
+                                                    false);
       break;
 
     case Instruction::SGET_BOOLEAN:
-      VerifyISGet(inst, reg_types_.Boolean(), true, true);
+      VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Boolean(), true, true);
       break;
     case Instruction::SGET_BYTE:
-      VerifyISGet(inst, reg_types_.Byte(), true, true);
+      VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Byte(), true, true);
       break;
     case Instruction::SGET_CHAR:
-      VerifyISGet(inst, reg_types_.Char(), true, true);
+      VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Char(), true, true);
       break;
     case Instruction::SGET_SHORT:
-      VerifyISGet(inst, reg_types_.Short(), true, true);
+      VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Short(), true, true);
       break;
     case Instruction::SGET:
-      VerifyISGet(inst, reg_types_.Integer(), true, true);
+      VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Integer(), true, true);
       break;
     case Instruction::SGET_WIDE:
-      VerifyISGet(inst, reg_types_.LongLo(), true, true);
+      VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.LongLo(), true, true);
       break;
     case Instruction::SGET_OBJECT:
-      VerifyISGet(inst, reg_types_.JavaLangObject(false), false, true);
+      VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.JavaLangObject(false), false,
+                                                    true);
       break;
 
     case Instruction::SPUT_BOOLEAN:
-      VerifyISPut(inst, reg_types_.Boolean(), true, true);
+      VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Boolean(), true, true);
       break;
     case Instruction::SPUT_BYTE:
-      VerifyISPut(inst, reg_types_.Byte(), true, true);
+      VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Byte(), true, true);
       break;
     case Instruction::SPUT_CHAR:
-      VerifyISPut(inst, reg_types_.Char(), true, true);
+      VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Char(), true, true);
       break;
     case Instruction::SPUT_SHORT:
-      VerifyISPut(inst, reg_types_.Short(), true, true);
+      VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Short(), true, true);
       break;
     case Instruction::SPUT:
-      VerifyISPut(inst, reg_types_.Integer(), true, true);
+      VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Integer(), true, true);
       break;
     case Instruction::SPUT_WIDE:
-      VerifyISPut(inst, reg_types_.LongLo(), true, true);
+      VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.LongLo(), true, true);
       break;
     case Instruction::SPUT_OBJECT:
-      VerifyISPut(inst, reg_types_.JavaLangObject(false), false, true);
+      VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.JavaLangObject(false), false,
+                                                    true);
       break;
 
     case Instruction::INVOKE_VIRTUAL:
@@ -2645,22 +2649,22 @@
     // As such they use Class*/Field*/AbstractMethod* as these offsets only have
     // meaning if the class linking and resolution were successful.
     case Instruction::IGET_QUICK:
-      VerifyIGetQuick(inst, reg_types_.Integer(), true);
+      VerifyQuickFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Integer(), true);
       break;
     case Instruction::IGET_WIDE_QUICK:
-      VerifyIGetQuick(inst, reg_types_.LongLo(), true);
+      VerifyQuickFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.LongLo(), true);
       break;
     case Instruction::IGET_OBJECT_QUICK:
-      VerifyIGetQuick(inst, reg_types_.JavaLangObject(false), false);
+      VerifyQuickFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.JavaLangObject(false), false);
       break;
     case Instruction::IPUT_QUICK:
-      VerifyIPutQuick(inst, reg_types_.Integer(), true);
+      VerifyQuickFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Integer(), true);
       break;
     case Instruction::IPUT_WIDE_QUICK:
-      VerifyIPutQuick(inst, reg_types_.LongLo(), true);
+      VerifyQuickFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.LongLo(), true);
       break;
     case Instruction::IPUT_OBJECT_QUICK:
-      VerifyIPutQuick(inst, reg_types_.JavaLangObject(false), false);
+      VerifyQuickFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.JavaLangObject(false), false);
       break;
     case Instruction::INVOKE_VIRTUAL_QUICK:
     case Instruction::INVOKE_VIRTUAL_RANGE_QUICK: {
@@ -3747,8 +3751,9 @@
   }
 }
 
-void MethodVerifier::VerifyISGet(const Instruction* inst, RegType& insn_type,
-                                 bool is_primitive, bool is_static) {
+template <MethodVerifier::FieldAccessType kAccType>
+void MethodVerifier::VerifyISFieldAccess(const Instruction* inst, RegType& insn_type,
+                                         bool is_primitive, bool is_static) {
   uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c();
   mirror::ArtField* field;
   if (is_static) {
@@ -3756,9 +3761,20 @@
   } else {
     RegType& object_type = work_line_->GetRegisterType(inst->VRegB_22c());
     field = GetInstanceField(object_type, field_idx);
+    if (UNLIKELY(have_pending_hard_failure_)) {
+      return;
+    }
   }
   RegType* field_type = nullptr;
   if (field != nullptr) {
+    if (kAccType == FieldAccessType::kAccPut) {
+      if (field->IsFinal() && field->GetDeclaringClass() != GetDeclaringClass().GetClass()) {
+        Fail(VERIFY_ERROR_ACCESS_FIELD) << "cannot modify final field " << PrettyField(field)
+                                        << " from other class " << GetDeclaringClass();
+        return;
+      }
+    }
+
     Thread* self = Thread::Current();
     mirror::Class* field_type_class;
     {
@@ -3781,89 +3797,56 @@
   }
   DCHECK(field_type != nullptr);
   const uint32_t vregA = (is_static) ? inst->VRegA_21c() : inst->VRegA_22c();
-  if (is_primitive) {
-    if (field_type->Equals(insn_type) ||
-        (field_type->IsFloat() && insn_type.IsInteger()) ||
-        (field_type->IsDouble() && insn_type.IsLong())) {
-      // expected that read is of the correct primitive type or that int reads are reading
-      // floats or long reads are reading doubles
+  static_assert(kAccType == FieldAccessType::kAccPut || kAccType == FieldAccessType::kAccGet,
+                "Unexpected third access type");
+  if (kAccType == FieldAccessType::kAccPut) {
+    // sput or iput.
+    if (is_primitive) {
+      VerifyPrimitivePut(*field_type, insn_type, vregA);
     } else {
-      // This is a global failure rather than a class change failure as the instructions and
-      // the descriptors for the type should have been consistent within the same file at
-      // compile time
-      Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "expected field " << PrettyField(field)
-                                        << " to be of type '" << insn_type
-                                        << "' but found type '" << *field_type << "' in get";
-      return;
+      if (!insn_type.IsAssignableFrom(*field_type)) {
+        Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "expected field " << PrettyField(field)
+                                                << " to be compatible with type '" << insn_type
+                                                << "' but found type '" << *field_type
+                                                << "' in put-object";
+        return;
+      }
+      work_line_->VerifyRegisterType(vregA, *field_type);
     }
-  } else {
-    if (!insn_type.IsAssignableFrom(*field_type)) {
-      Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "expected field " << PrettyField(field)
-                                        << " to be compatible with type '" << insn_type
-                                        << "' but found type '" << *field_type
-                                        << "' in Get-object";
-      work_line_->SetRegisterType(vregA, reg_types_.Conflict());
-      return;
-    }
-  }
-  if (!field_type->IsLowHalf()) {
-    work_line_->SetRegisterType(vregA, *field_type);
-  } else {
-    work_line_->SetRegisterTypeWide(vregA, *field_type, field_type->HighHalf(&reg_types_));
-  }
-}
-
-void MethodVerifier::VerifyISPut(const Instruction* inst, RegType& insn_type,
-                                 bool is_primitive, bool is_static) {
-  uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c();
-  mirror::ArtField* field;
-  if (is_static) {
-    field = GetStaticField(field_idx);
-  } else {
-    RegType& object_type = work_line_->GetRegisterType(inst->VRegB_22c());
-    field = GetInstanceField(object_type, field_idx);
-  }
-  RegType* field_type = nullptr;
-  if (field != nullptr) {
-    if (field->IsFinal() && field->GetDeclaringClass() != GetDeclaringClass().GetClass()) {
-      Fail(VERIFY_ERROR_ACCESS_FIELD) << "cannot modify final field " << PrettyField(field)
-                                      << " from other class " << GetDeclaringClass();
-      return;
-    }
-    mirror::Class* field_type_class;
-    {
-      StackHandleScope<1> hs(Thread::Current());
-      HandleWrapper<mirror::ArtField> h_field(hs.NewHandleWrapper(&field));
-      FieldHelper fh(h_field);
-      field_type_class = fh.GetType(can_load_classes_);
-    }
-    if (field_type_class != nullptr) {
-      field_type = &reg_types_.FromClass(field->GetTypeDescriptor(), field_type_class,
-                                         field_type_class->CannotBeAssignedFromOtherTypes());
+  } else if (kAccType == FieldAccessType::kAccGet) {
+    // sget or iget.
+    if (is_primitive) {
+      if (field_type->Equals(insn_type) ||
+          (field_type->IsFloat() && insn_type.IsInteger()) ||
+          (field_type->IsDouble() && insn_type.IsLong())) {
+        // expected that read is of the correct primitive type or that int reads are reading
+        // floats or long reads are reading doubles
+      } else {
+        // This is a global failure rather than a class change failure as the instructions and
+        // the descriptors for the type should have been consistent within the same file at
+        // compile time
+        Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "expected field " << PrettyField(field)
+                                          << " to be of type '" << insn_type
+                                          << "' but found type '" << *field_type << "' in get";
+        return;
+      }
     } else {
-      Thread* self = Thread::Current();
-      DCHECK(!can_load_classes_ || self->IsExceptionPending());
-      self->ClearException();
+      if (!insn_type.IsAssignableFrom(*field_type)) {
+        Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "expected field " << PrettyField(field)
+                                          << " to be compatible with type '" << insn_type
+                                          << "' but found type '" << *field_type
+                                          << "' in get-object";
+        work_line_->SetRegisterType(vregA, reg_types_.Conflict());
+        return;
+      }
     }
-  }
-  if (field_type == nullptr) {
-    const DexFile::FieldId& field_id = dex_file_->GetFieldId(field_idx);
-    const char* descriptor = dex_file_->GetFieldTypeDescriptor(field_id);
-    field_type = &reg_types_.FromDescriptor(class_loader_->Get(), descriptor, false);
-  }
-  DCHECK(field_type != nullptr);
-  const uint32_t vregA = (is_static) ? inst->VRegA_21c() : inst->VRegA_22c();
-  if (is_primitive) {
-    VerifyPrimitivePut(*field_type, insn_type, vregA);
+    if (!field_type->IsLowHalf()) {
+      work_line_->SetRegisterType(vregA, *field_type);
+    } else {
+      work_line_->SetRegisterTypeWide(vregA, *field_type, field_type->HighHalf(&reg_types_));
+    }
   } else {
-    if (!insn_type.IsAssignableFrom(*field_type)) {
-      Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "expected field " << PrettyField(field)
-                                        << " to be compatible with type '" << insn_type
-                                        << "' but found type '" << *field_type
-                                        << "' in put-object";
-      return;
-    }
-    work_line_->VerifyRegisterType(vregA, *field_type);
+    LOG(FATAL) << "Unexpected case.";
   }
 }
 
@@ -3890,132 +3873,137 @@
   return f;
 }
 
-void MethodVerifier::VerifyIGetQuick(const Instruction* inst, RegType& insn_type,
-                                     bool is_primitive) {
+template <MethodVerifier::FieldAccessType kAccType>
+void MethodVerifier::VerifyQuickFieldAccess(const Instruction* inst, RegType& insn_type,
+                                            bool is_primitive) {
   DCHECK(Runtime::Current()->IsStarted() || verify_to_dump_);
-  mirror::ArtField* field = GetQuickFieldAccess(inst, work_line_.get());
-  if (field == nullptr) {
-    Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Cannot infer field from " << inst->Name();
-    return;
-  }
-  mirror::Class* field_type_class;
-  {
-    StackHandleScope<1> hs(Thread::Current());
-    HandleWrapper<mirror::ArtField> h_field(hs.NewHandleWrapper(&field));
-    FieldHelper fh(h_field);
-    field_type_class = fh.GetType(can_load_classes_);
-  }
-  RegType* field_type;
-  if (field_type_class != nullptr) {
-    field_type = &reg_types_.FromClass(field->GetTypeDescriptor(), field_type_class,
-                                       field_type_class->CannotBeAssignedFromOtherTypes());
-  } else {
-    Thread* self = Thread::Current();
-    DCHECK(!can_load_classes_ || self->IsExceptionPending());
-    self->ClearException();
-    field_type = &reg_types_.FromDescriptor(field->GetDeclaringClass()->GetClassLoader(),
-                                            field->GetTypeDescriptor(), false);
-  }
-  DCHECK(field_type != nullptr);
-  const uint32_t vregA = inst->VRegA_22c();
-  if (is_primitive) {
-    if (field_type->Equals(insn_type) ||
-        (field_type->IsFloat() && insn_type.IsIntegralTypes()) ||
-        (field_type->IsDouble() && insn_type.IsLongTypes())) {
-      // expected that read is of the correct primitive type or that int reads are reading
-      // floats or long reads are reading doubles
-    } else {
-      // This is a global failure rather than a class change failure as the instructions and
-      // the descriptors for the type should have been consistent within the same file at
-      // compile time
-      Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "expected field " << PrettyField(field)
-                                        << " to be of type '" << insn_type
-                                        << "' but found type '" << *field_type << "' in Get";
-      return;
-    }
-  } else {
-    if (!insn_type.IsAssignableFrom(*field_type)) {
-      Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "expected field " << PrettyField(field)
-                                        << " to be compatible with type '" << insn_type
-                                        << "' but found type '" << *field_type
-                                        << "' in get-object";
-      work_line_->SetRegisterType(vregA, reg_types_.Conflict());
-      return;
-    }
-  }
-  if (!field_type->IsLowHalf()) {
-    work_line_->SetRegisterType(vregA, *field_type);
-  } else {
-    work_line_->SetRegisterTypeWide(vregA, *field_type, field_type->HighHalf(&reg_types_));
-  }
-}
 
-void MethodVerifier::VerifyIPutQuick(const Instruction* inst, RegType& insn_type,
-                                     bool is_primitive) {
-  DCHECK(Runtime::Current()->IsStarted() || verify_to_dump_);
   mirror::ArtField* field = GetQuickFieldAccess(inst, work_line_.get());
   if (field == nullptr) {
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Cannot infer field from " << inst->Name();
     return;
   }
-  const char* descriptor = field->GetTypeDescriptor();
-  mirror::ClassLoader* loader = field->GetDeclaringClass()->GetClassLoader();
-  RegType& field_type = reg_types_.FromDescriptor(loader, descriptor, false);
-  if (field != nullptr) {
+
+  // For an IPUT_QUICK, we now test for final flag of the field.
+  if (kAccType == FieldAccessType::kAccPut) {
     if (field->IsFinal() && field->GetDeclaringClass() != GetDeclaringClass().GetClass()) {
       Fail(VERIFY_ERROR_ACCESS_FIELD) << "cannot modify final field " << PrettyField(field)
                                       << " from other class " << GetDeclaringClass();
       return;
     }
   }
-  const uint32_t vregA = inst->VRegA_22c();
-  if (is_primitive) {
-    // Primitive field assignability rules are weaker than regular assignability rules
-    bool instruction_compatible;
-    bool value_compatible;
-    RegType& value_type = work_line_->GetRegisterType(vregA);
-    if (field_type.IsIntegralTypes()) {
-      instruction_compatible = insn_type.IsIntegralTypes();
-      value_compatible = value_type.IsIntegralTypes();
-    } else if (field_type.IsFloat()) {
-      instruction_compatible = insn_type.IsInteger();  // no [is]put-float, so expect [is]put-int
-      value_compatible = value_type.IsFloatTypes();
-    } else if (field_type.IsLong()) {
-      instruction_compatible = insn_type.IsLong();
-      value_compatible = value_type.IsLongTypes();
-    } else if (field_type.IsDouble()) {
-      instruction_compatible = insn_type.IsLong();  // no [is]put-double, so expect [is]put-long
-      value_compatible = value_type.IsDoubleTypes();
+
+  // Get the field type.
+  RegType* field_type;
+  {
+    mirror::Class* field_type_class;
+    {
+      StackHandleScope<1> hs(Thread::Current());
+      HandleWrapper<mirror::ArtField> h_field(hs.NewHandleWrapper(&field));
+      field_type_class = FieldHelper(h_field).GetType(can_load_classes_);
+    }
+
+    if (field_type_class != nullptr) {
+      field_type = &reg_types_.FromClass(field->GetTypeDescriptor(), field_type_class,
+                                         field_type_class->CannotBeAssignedFromOtherTypes());
     } else {
-      instruction_compatible = false;  // reference field with primitive store
-      value_compatible = false;  // unused
+      Thread* self = Thread::Current();
+      DCHECK(!can_load_classes_ || self->IsExceptionPending());
+      self->ClearException();
+      field_type = &reg_types_.FromDescriptor(field->GetDeclaringClass()->GetClassLoader(),
+                                              field->GetTypeDescriptor(), false);
     }
-    if (!instruction_compatible) {
-      // This is a global failure rather than a class change failure as the instructions and
-      // the descriptors for the type should have been consistent within the same file at
-      // compile time
-      Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "expected field " << PrettyField(field)
-                                        << " to be of type '" << insn_type
-                                        << "' but found type '" << field_type
-                                        << "' in put";
+    if (field_type == nullptr) {
+      Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Cannot infer field type from " << inst->Name();
       return;
     }
-    if (!value_compatible) {
-      Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "unexpected value in v" << vregA
-          << " of type " << value_type
-          << " but expected " << field_type
-          << " for store to " << PrettyField(field) << " in put";
-      return;
+  }
+
+  const uint32_t vregA = inst->VRegA_22c();
+  static_assert(kAccType == FieldAccessType::kAccPut || kAccType == FieldAccessType::kAccGet,
+                "Unexpected third access type");
+  if (kAccType == FieldAccessType::kAccPut) {
+    if (is_primitive) {
+      // Primitive field assignability rules are weaker than regular assignability rules
+      bool instruction_compatible;
+      bool value_compatible;
+      RegType& value_type = work_line_->GetRegisterType(vregA);
+      if (field_type->IsIntegralTypes()) {
+        instruction_compatible = insn_type.IsIntegralTypes();
+        value_compatible = value_type.IsIntegralTypes();
+      } else if (field_type->IsFloat()) {
+        instruction_compatible = insn_type.IsInteger();  // no [is]put-float, so expect [is]put-int
+        value_compatible = value_type.IsFloatTypes();
+      } else if (field_type->IsLong()) {
+        instruction_compatible = insn_type.IsLong();
+        value_compatible = value_type.IsLongTypes();
+      } else if (field_type->IsDouble()) {
+        instruction_compatible = insn_type.IsLong();  // no [is]put-double, so expect [is]put-long
+        value_compatible = value_type.IsDoubleTypes();
+      } else {
+        instruction_compatible = false;  // reference field with primitive store
+        value_compatible = false;  // unused
+      }
+      if (!instruction_compatible) {
+        // This is a global failure rather than a class change failure as the instructions and
+        // the descriptors for the type should have been consistent within the same file at
+        // compile time
+        Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "expected field " << PrettyField(field)
+                                          << " to be of type '" << insn_type
+                                          << "' but found type '" << *field_type
+                                          << "' in put";
+        return;
+      }
+      if (!value_compatible) {
+        Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "unexpected value in v" << vregA
+            << " of type " << value_type
+            << " but expected " << *field_type
+            << " for store to " << PrettyField(field) << " in put";
+        return;
+      }
+    } else {
+      if (!insn_type.IsAssignableFrom(*field_type)) {
+        Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "expected field " << PrettyField(field)
+                                          << " to be compatible with type '" << insn_type
+                                          << "' but found type '" << *field_type
+                                          << "' in put-object";
+        return;
+      }
+      work_line_->VerifyRegisterType(vregA, *field_type);
+    }
+  } else if (kAccType == FieldAccessType::kAccGet) {
+    if (is_primitive) {
+      if (field_type->Equals(insn_type) ||
+          (field_type->IsFloat() && insn_type.IsIntegralTypes()) ||
+          (field_type->IsDouble() && insn_type.IsLongTypes())) {
+        // expected that read is of the correct primitive type or that int reads are reading
+        // floats or long reads are reading doubles
+      } else {
+        // This is a global failure rather than a class change failure as the instructions and
+        // the descriptors for the type should have been consistent within the same file at
+        // compile time
+        Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "expected field " << PrettyField(field)
+                                          << " to be of type '" << insn_type
+                                          << "' but found type '" << *field_type << "' in Get";
+        return;
+      }
+    } else {
+      if (!insn_type.IsAssignableFrom(*field_type)) {
+        Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "expected field " << PrettyField(field)
+                                          << " to be compatible with type '" << insn_type
+                                          << "' but found type '" << *field_type
+                                          << "' in get-object";
+        work_line_->SetRegisterType(vregA, reg_types_.Conflict());
+        return;
+      }
+    }
+    if (!field_type->IsLowHalf()) {
+      work_line_->SetRegisterType(vregA, *field_type);
+    } else {
+      work_line_->SetRegisterTypeWide(vregA, *field_type, field_type->HighHalf(&reg_types_));
     }
   } else {
-    if (!insn_type.IsAssignableFrom(field_type)) {
-      Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "expected field " << PrettyField(field)
-                                        << " to be compatible with type '" << insn_type
-                                        << "' but found type '" << field_type
-                                        << "' in put-object";
-      return;
-    }
-    work_line_->VerifyRegisterType(vregA, field_type);
+    LOG(FATAL) << "Unexpected case.";
   }
 }
 
diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h
index 17713d2..d7dd4b8 100644
--- a/runtime/verifier/method_verifier.h
+++ b/runtime/verifier/method_verifier.h
@@ -506,14 +506,14 @@
   // Lookup static field and fail for resolution violations
   mirror::ArtField* GetStaticField(int field_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  // Perform verification of an iget or sget instruction.
-  void VerifyISGet(const Instruction* inst, RegType& insn_type,
-                   bool is_primitive, bool is_static)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
-  // Perform verification of an iput or sput instruction.
-  void VerifyISPut(const Instruction* inst, RegType& insn_type,
-                   bool is_primitive, bool is_static)
+  // Perform verification of an iget/sget/iput/sput instruction.
+  enum class FieldAccessType {  // private
+    kAccGet,
+    kAccPut
+  };
+  template <FieldAccessType kAccType>
+  void VerifyISFieldAccess(const Instruction* inst, RegType& insn_type,
+                           bool is_primitive, bool is_static)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Returns the access field of a quick field access (iget/iput-quick) or nullptr
@@ -521,14 +521,8 @@
   mirror::ArtField* GetQuickFieldAccess(const Instruction* inst, RegisterLine* reg_line)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  // Perform verification of an iget-quick instruction.
-  void VerifyIGetQuick(const Instruction* inst, RegType& insn_type,
-                       bool is_primitive)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
-  // Perform verification of an iput-quick instruction.
-  void VerifyIPutQuick(const Instruction* inst, RegType& insn_type,
-                       bool is_primitive)
+  template <FieldAccessType kAccType>
+  void VerifyQuickFieldAccess(const Instruction* inst, RegType& insn_type, bool is_primitive)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Resolves a class based on an index and performs access checks to ensure the referrer can