Revert "Revert "Check FastInstance() early for special getters and setters.""

This reverts commit 632e458dc267fadfb8120be3ab02701e09e64875.

Change-Id: I5098c41ee84fbbb39397133a7ecfd367fecebe42
diff --git a/compiler/dex/quick/arm/call_arm.cc b/compiler/dex/quick/arm/call_arm.cc
index 661050f..22466f0 100644
--- a/compiler/dex/quick/arm/call_arm.cc
+++ b/compiler/dex/quick/arm/call_arm.cc
@@ -127,15 +127,19 @@
   }
 }
 
-MIR* ArmMir2Lir::SpecialIGet(BasicBlock** bb, MIR* mir,
-                             OpSize size, bool long_or_double, bool is_object) {
-  int32_t field_offset;
-  bool is_volatile;
-  uint32_t field_idx = mir->dalvikInsn.vC;
-  bool fast_path = FastInstance(field_idx, false, &field_offset, &is_volatile);
-  if (!fast_path || !(mir->optimization_flags & MIR_IGNORE_NULL_CHECK)) {
-    return NULL;
+MIR* ArmMir2Lir::SpecialIGet(BasicBlock** bb, MIR* mir, const InlineMethod& special) {
+  // FastInstance() already checked by DexFileMethodInliner.
+  const InlineIGetIPutData& data = special.d.ifield_data;
+  if (!data.method_is_static || data.object_arg != 0) {
+    return NULL;  // The object is not "this" and has to be null-checked.
   }
+
+  OpSize size = static_cast<OpSize>(data.op_size);
+  DCHECK_NE(data.op_size, kDouble);  // The inliner doesn't distinguish kDouble, uses kLong.
+  bool long_or_double = (data.op_size == kLong);
+  bool is_object = data.is_object;
+
+  // TODO: Generate the method using only the data in special.
   RegLocation rl_obj = mir_graph_->GetSrc(mir, 0);
   LockLiveArgs(mir);
   rl_obj = ArmMir2Lir::ArgLoc(rl_obj);
@@ -148,19 +152,24 @@
   // Point of no return - no aborts after this
   ArmMir2Lir::GenPrintLabel(mir);
   rl_obj = LoadArg(rl_obj);
+  uint32_t field_idx = mir->dalvikInsn.vC;
   GenIGet(field_idx, mir->optimization_flags, size, rl_dest, rl_obj, long_or_double, is_object);
   return GetNextMir(bb, mir);
 }
 
-MIR* ArmMir2Lir::SpecialIPut(BasicBlock** bb, MIR* mir,
-                             OpSize size, bool long_or_double, bool is_object) {
-  int32_t field_offset;
-  bool is_volatile;
-  uint32_t field_idx = mir->dalvikInsn.vC;
-  bool fast_path = FastInstance(field_idx, false, &field_offset, &is_volatile);
-  if (!fast_path || !(mir->optimization_flags & MIR_IGNORE_NULL_CHECK)) {
-    return NULL;
+MIR* ArmMir2Lir::SpecialIPut(BasicBlock** bb, MIR* mir, const InlineMethod& special) {
+  // FastInstance() already checked by DexFileMethodInliner.
+  const InlineIGetIPutData& data = special.d.ifield_data;
+  if (!data.method_is_static || data.object_arg != 0) {
+    return NULL;  // The object is not "this" and has to be null-checked.
   }
+
+  OpSize size = static_cast<OpSize>(data.op_size);
+  DCHECK_NE(data.op_size, kDouble);  // The inliner doesn't distinguish kDouble, uses kLong.
+  bool long_or_double = (data.op_size == kLong);
+  bool is_object = data.is_object;
+
+  // TODO: Generate the method using only the data in special.
   RegLocation rl_src;
   RegLocation rl_obj;
   LockLiveArgs(mir);
@@ -174,7 +183,7 @@
   rl_src = ArmMir2Lir::ArgLoc(rl_src);
   rl_obj = ArmMir2Lir::ArgLoc(rl_obj);
   // Reject if source is split across registers & frame
-  if (rl_obj.location == kLocInvalid) {
+  if (rl_src.location == kLocInvalid) {
     ResetRegPool();
     return NULL;
   }
@@ -182,6 +191,7 @@
   ArmMir2Lir::GenPrintLabel(mir);
   rl_obj = LoadArg(rl_obj);
   rl_src = LoadArg(rl_src);
+  uint32_t field_idx = mir->dalvikInsn.vC;
   GenIPut(field_idx, mir->optimization_flags, size, rl_src, rl_obj, long_or_double, is_object);
   return GetNextMir(bb, mir);
 }
@@ -219,8 +229,6 @@
  */
 void ArmMir2Lir::GenSpecialCase(BasicBlock* bb, MIR* mir,
                                 const InlineMethod& special) {
-  // TODO: Generate the method using only the data in special. (Requires FastInstance() field
-  // validation in DexFileMethodInliner::AnalyseIGetMethod()/AnalyseIPutMethod().)
   DCHECK(special.flags & kInlineSpecial);
   current_dalvik_offset_ = mir->offset;
   MIR* next_mir = NULL;
@@ -231,30 +239,17 @@
       break;
     case kInlineOpConst:
       ArmMir2Lir::GenPrintLabel(mir);
-      LoadConstant(rARM_RET0, special.data);
+      LoadConstant(rARM_RET0, static_cast<int>(special.d.data));
       next_mir = GetNextMir(&bb, mir);
       break;
-    case kInlineOpIGet: {
-      InlineIGetIPutData data;
-      data.data = special.data;
-      OpSize op_size = static_cast<OpSize>(data.d.op_size);
-      DCHECK_NE(data.d.op_size, kDouble);  // The inliner doesn't distinguish kDouble, uses kLong.
-      bool long_or_double = (data.d.op_size == kLong);
-      bool is_object = data.d.is_object;
-      next_mir = SpecialIGet(&bb, mir, op_size, long_or_double, is_object);
+    case kInlineOpIGet:
+      next_mir = SpecialIGet(&bb, mir, special);
       break;
-    }
-    case kInlineOpIPut: {
-      InlineIGetIPutData data;
-      data.data = special.data;
-      OpSize op_size = static_cast<OpSize>(data.d.op_size);
-      DCHECK_NE(data.d.op_size, kDouble);  // The inliner doesn't distinguish kDouble, uses kLong.
-      bool long_or_double = (data.d.op_size == kLong);
-      bool is_object = data.d.is_object;
-      next_mir = SpecialIPut(&bb, mir, op_size, long_or_double, is_object);
+    case kInlineOpIPut:
+      next_mir = SpecialIPut(&bb, mir, special);
       break;
-    }
     case kInlineOpReturnArg:
+      // TODO: Generate the method using only the data in special.
       next_mir = SpecialIdentity(mir);
       break;
     default:
diff --git a/compiler/dex/quick/arm/codegen_arm.h b/compiler/dex/quick/arm/codegen_arm.h
index 0ed4576..598da89 100644
--- a/compiler/dex/quick/arm/codegen_arm.h
+++ b/compiler/dex/quick/arm/codegen_arm.h
@@ -190,8 +190,8 @@
     RegLocation LoadArg(RegLocation loc);
     void LockLiveArgs(MIR* mir);
     MIR* GetNextMir(BasicBlock** p_bb, MIR* mir);
-    MIR* SpecialIGet(BasicBlock** bb, MIR* mir, OpSize size, bool long_or_double, bool is_object);
-    MIR* SpecialIPut(BasicBlock** bb, MIR* mir, OpSize size, bool long_or_double, bool is_object);
+    MIR* SpecialIGet(BasicBlock** bb, MIR* mir, const InlineMethod& special);
+    MIR* SpecialIPut(BasicBlock** bb, MIR* mir, const InlineMethod& special);
     MIR* SpecialIdentity(MIR* mir);
     LIR* LoadFPConstantValue(int r_dest, int value);
     void ReplaceFixup(LIR* prev_lir, LIR* orig_lir, LIR* new_lir);
diff --git a/compiler/dex/quick/dex_file_method_inliner.cc b/compiler/dex/quick/dex_file_method_inliner.cc
index 0937be3..0ad8abf 100644
--- a/compiler/dex/quick/dex_file_method_inliner.cc
+++ b/compiler/dex/quick/dex_file_method_inliner.cc
@@ -24,11 +24,27 @@
 #include "dex/mir_graph.h"
 #include "dex_instruction.h"
 #include "dex_instruction-inl.h"
+#include "verifier/method_verifier.h"
+#include "verifier/method_verifier-inl.h"
 
 #include "dex_file_method_inliner.h"
 
 namespace art {
 
+namespace {  // anonymous namespace
+
+constexpr uint8_t kIGetIPutOpSizes[] = {
+    kWord,          // IGET, IPUT
+    kLong,          // IGET_WIDE, IPUT_WIDE
+    kWord,          // IGET_OBJECT, IPUT_OBJECT
+    kSignedByte,    // IGET_BOOLEAN, IPUT_BOOLEAN
+    kSignedByte,    // IGET_BYTE, IPUT_BYTE
+    kUnsignedHalf,  // IGET_CHAR, IPUT_CHAR
+    kSignedHalf,    // IGET_SHORT, IPUT_SHORT
+};
+
+}  // anonymous namespace
+
 const uint32_t DexFileMethodInliner::kIndexUnresolved;
 const char* const DexFileMethodInliner::kClassCacheNames[] = {
     "Z",                       // kClassCacheBoolean
@@ -167,7 +183,7 @@
 
 const DexFileMethodInliner::IntrinsicDef DexFileMethodInliner::kIntrinsicMethods[] = {
 #define INTRINSIC(c, n, p, o, d) \
-    { { kClassCache ## c, kNameCache ## n, kProtoCache ## p }, { o, kInlineIntrinsic, d } }
+    { { kClassCache ## c, kNameCache ## n, kProtoCache ## p }, { o, kInlineIntrinsic, { d } } }
 
     INTRINSIC(JavaLangDouble, DoubleToRawLongBits, D_J, kIntrinsicDoubleCvt, 0),
     INTRINSIC(JavaLangDouble, LongBitsToDouble, J_D, kIntrinsicDoubleCvt, 0),
@@ -248,57 +264,58 @@
 DexFileMethodInliner::~DexFileMethodInliner() {
 }
 
-bool DexFileMethodInliner::AnalyseMethodCode(uint32_t method_idx,
-                                             const DexFile::CodeItem* code_item) {
+bool DexFileMethodInliner::AnalyseMethodCode(verifier::MethodVerifier* verifier) {
   // We currently support only plain return or 2-instruction methods.
 
+  const DexFile::CodeItem* code_item = verifier->CodeItem();
   DCHECK_NE(code_item->insns_size_in_code_units_, 0u);
   const Instruction* instruction = Instruction::At(code_item->insns_);
   Instruction::Code opcode = instruction->Opcode();
 
+  InlineMethod method;
+  bool success;
   switch (opcode) {
     case Instruction::RETURN_VOID:
-      return AddInlineMethod(method_idx, kInlineOpNop, kInlineSpecial, 0);
+      method.opcode = kInlineOpNop;
+      method.flags = kInlineSpecial;
+      method.d.data = 0u;
+      success = true;
+      break;
     case Instruction::RETURN:
     case Instruction::RETURN_OBJECT:
-      return AnalyseReturnMethod(method_idx, code_item, kWord);
     case Instruction::RETURN_WIDE:
-      return AnalyseReturnMethod(method_idx, code_item, kLong);
+      success = AnalyseReturnMethod(code_item, &method);
+      break;
     case Instruction::CONST:
     case Instruction::CONST_4:
     case Instruction::CONST_16:
     case Instruction::CONST_HIGH16:
       // TODO: Support wide constants (RETURN_WIDE).
-      return AnalyseConstMethod(method_idx, code_item);
+      success = AnalyseConstMethod(code_item, &method);
+      break;
     case Instruction::IGET:
-      return AnalyseIGetMethod(method_idx, code_item, kWord, false);
     case Instruction::IGET_OBJECT:
-      return AnalyseIGetMethod(method_idx, code_item, kWord, true);
     case Instruction::IGET_BOOLEAN:
     case Instruction::IGET_BYTE:
-      return AnalyseIGetMethod(method_idx, code_item, kSignedByte, false);
     case Instruction::IGET_CHAR:
-      return AnalyseIGetMethod(method_idx, code_item, kUnsignedHalf, false);
     case Instruction::IGET_SHORT:
-      return AnalyseIGetMethod(method_idx, code_item, kSignedHalf, false);
     case Instruction::IGET_WIDE:
-      return AnalyseIGetMethod(method_idx, code_item, kLong, false);
+      success = AnalyseIGetMethod(verifier, &method);
+      break;
     case Instruction::IPUT:
-      return AnalyseIPutMethod(method_idx, code_item, kWord, false);
     case Instruction::IPUT_OBJECT:
-      return AnalyseIPutMethod(method_idx, code_item, kWord, true);
     case Instruction::IPUT_BOOLEAN:
     case Instruction::IPUT_BYTE:
-      return AnalyseIPutMethod(method_idx, code_item, kSignedByte, false);
     case Instruction::IPUT_CHAR:
-      return AnalyseIPutMethod(method_idx, code_item, kUnsignedHalf, false);
     case Instruction::IPUT_SHORT:
-      return AnalyseIPutMethod(method_idx, code_item, kSignedHalf, false);
     case Instruction::IPUT_WIDE:
-      return AnalyseIPutMethod(method_idx, code_item, kLong, false);
+      success = AnalyseIPutMethod(verifier, &method);
+      break;
     default:
-      return false;
-    }
+      success = false;
+      break;
+  }
+  return success && AddInlineMethod(verifier->GetMethodReference().dex_method_index, method);
 }
 
 bool DexFileMethodInliner::IsIntrinsic(uint32_t method_index) {
@@ -323,13 +340,13 @@
     case kIntrinsicFloatCvt:
       return backend->GenInlinedFloatCvt(info);
     case kIntrinsicReverseBytes:
-      return backend->GenInlinedReverseBytes(info, static_cast<OpSize>(intrinsic.data));
+      return backend->GenInlinedReverseBytes(info, static_cast<OpSize>(intrinsic.d.data));
     case kIntrinsicAbsInt:
       return backend->GenInlinedAbsInt(info);
     case kIntrinsicAbsLong:
       return backend->GenInlinedAbsLong(info);
     case kIntrinsicMinMaxInt:
-      return backend->GenInlinedMinMaxInt(info, intrinsic.data & kIntrinsicFlagMin);
+      return backend->GenInlinedMinMaxInt(info, intrinsic.d.data & kIntrinsicFlagMin);
     case kIntrinsicSqrt:
       return backend->GenInlinedSqrt(info);
     case kIntrinsicCharAt:
@@ -337,26 +354,27 @@
     case kIntrinsicCompareTo:
       return backend->GenInlinedStringCompareTo(info);
     case kIntrinsicIsEmptyOrLength:
-      return backend->GenInlinedStringIsEmptyOrLength(info, intrinsic.data & kIntrinsicFlagIsEmpty);
+      return backend->GenInlinedStringIsEmptyOrLength(
+          info, intrinsic.d.data & kIntrinsicFlagIsEmpty);
     case kIntrinsicIndexOf:
-      return backend->GenInlinedIndexOf(info, intrinsic.data & kIntrinsicFlagBase0);
+      return backend->GenInlinedIndexOf(info, intrinsic.d.data & kIntrinsicFlagBase0);
     case kIntrinsicCurrentThread:
       return backend->GenInlinedCurrentThread(info);
     case kIntrinsicPeek:
-      return backend->GenInlinedPeek(info, static_cast<OpSize>(intrinsic.data));
+      return backend->GenInlinedPeek(info, static_cast<OpSize>(intrinsic.d.data));
     case kIntrinsicPoke:
-      return backend->GenInlinedPoke(info, static_cast<OpSize>(intrinsic.data));
+      return backend->GenInlinedPoke(info, static_cast<OpSize>(intrinsic.d.data));
     case kIntrinsicCas:
-      return backend->GenInlinedCas(info, intrinsic.data & kIntrinsicFlagIsLong,
-                                    intrinsic.data & kIntrinsicFlagIsObject);
+      return backend->GenInlinedCas(info, intrinsic.d.data & kIntrinsicFlagIsLong,
+                                    intrinsic.d.data & kIntrinsicFlagIsObject);
     case kIntrinsicUnsafeGet:
-      return backend->GenInlinedUnsafeGet(info, intrinsic.data & kIntrinsicFlagIsLong,
-                                          intrinsic.data & kIntrinsicFlagIsVolatile);
+      return backend->GenInlinedUnsafeGet(info, intrinsic.d.data & kIntrinsicFlagIsLong,
+                                          intrinsic.d.data & kIntrinsicFlagIsVolatile);
     case kIntrinsicUnsafePut:
-      return backend->GenInlinedUnsafePut(info, intrinsic.data & kIntrinsicFlagIsLong,
-                                          intrinsic.data & kIntrinsicFlagIsObject,
-                                          intrinsic.data & kIntrinsicFlagIsVolatile,
-                                          intrinsic.data & kIntrinsicFlagIsOrdered);
+      return backend->GenInlinedUnsafePut(info, intrinsic.d.data & kIntrinsicFlagIsLong,
+                                          intrinsic.d.data & kIntrinsicFlagIsObject,
+                                          intrinsic.d.data & kIntrinsicFlagIsVolatile,
+                                          intrinsic.d.data & kIntrinsicFlagIsOrdered);
     default:
       LOG(FATAL) << "Unexpected intrinsic opcode: " << intrinsic.opcode;
       return false;  // avoid warning "control reaches end of non-void function"
@@ -505,12 +523,10 @@
   dex_file_ = dex_file;
 }
 
-bool DexFileMethodInliner::AddInlineMethod(int32_t method_idx, InlineMethodOpcode opcode,
-                                           InlineMethodFlags flags, uint32_t data) {
+bool DexFileMethodInliner::AddInlineMethod(int32_t method_idx, const InlineMethod& method) {
   WriterMutexLock mu(Thread::Current(), lock_);
   if (LIKELY(inline_methods_.find(method_idx) == inline_methods_.end())) {
-    InlineMethod im = {opcode, flags, data};
-    inline_methods_.Put(method_idx, im);
+    inline_methods_.Put(method_idx, method);
     return true;
   } else {
     if (PrettyMethod(method_idx, *dex_file_) == "int java.lang.String.length()") {
@@ -522,26 +538,30 @@
   }
 }
 
-bool DexFileMethodInliner::AnalyseReturnMethod(int32_t method_idx,
-                                               const DexFile::CodeItem* code_item, OpSize size) {
+bool DexFileMethodInliner::AnalyseReturnMethod(const DexFile::CodeItem* code_item,
+                                               InlineMethod* result) {
   const Instruction* return_instruction = Instruction::At(code_item->insns_);
-  if (return_instruction->Opcode() == Instruction::RETURN_VOID) {
-    return AddInlineMethod(method_idx, kInlineOpNop, kInlineSpecial, 0);
-  }
+  Instruction::Code return_opcode = return_instruction->Opcode();
+  uint16_t size = (return_opcode == Instruction::RETURN_WIDE) ? kLong : kWord;
+  uint16_t is_object = (return_opcode == Instruction::RETURN_OBJECT) ? 1u : 0u;
   uint32_t reg = return_instruction->VRegA_11x();
   uint32_t arg_start = code_item->registers_size_ - code_item->ins_size_;
   DCHECK_GE(reg, arg_start);
   DCHECK_LT(size == kLong ? reg + 1 : reg, code_item->registers_size_);
 
-  InlineReturnArgData data;
-  data.d.arg = reg - arg_start;
-  data.d.op_size = size;
-  data.d.reserved = 0;
-  return AddInlineMethod(method_idx, kInlineOpReturnArg, kInlineSpecial, data.data);
+  result->opcode = kInlineOpReturnArg;
+  result->flags = kInlineSpecial;
+  InlineReturnArgData* data = &result->d.return_data;
+  data->arg = reg - arg_start;
+  data->op_size = size;
+  data->is_object = is_object;
+  data->reserved = 0u;
+  data->reserved2 = 0u;
+  return true;
 }
 
-bool DexFileMethodInliner::AnalyseConstMethod(int32_t method_idx,
-                                              const DexFile::CodeItem* code_item) {
+bool DexFileMethodInliner::AnalyseConstMethod(const DexFile::CodeItem* code_item,
+                                              InlineMethod* result) {
   const Instruction* instruction = Instruction::At(code_item->insns_);
   const Instruction* return_instruction = instruction->Next();
   Instruction::Code return_opcode = return_instruction->Opcode();
@@ -566,13 +586,20 @@
   if (return_opcode == Instruction::RETURN_OBJECT && vB != 0) {
     return false;  // Returning non-null reference constant?
   }
-  return AddInlineMethod(method_idx, kInlineOpConst, kInlineSpecial, vB);
+  result->opcode = kInlineOpConst;
+  result->flags = kInlineSpecial;
+  result->d.data = static_cast<uint64_t>(vB);
+  return true;
 }
 
-bool DexFileMethodInliner::AnalyseIGetMethod(int32_t method_idx, const DexFile::CodeItem* code_item,
-                                             OpSize size, bool is_object) {
+bool DexFileMethodInliner::AnalyseIGetMethod(verifier::MethodVerifier* verifier,
+                                             InlineMethod* result) {
+  const DexFile::CodeItem* code_item = verifier->CodeItem();
   const Instruction* instruction = Instruction::At(code_item->insns_);
   Instruction::Code opcode = instruction->Opcode();
+  DCHECK_LT(static_cast<size_t>(opcode - Instruction::IGET), arraysize(kIGetIPutOpSizes));
+  uint16_t size = kIGetIPutOpSizes[opcode - Instruction::IGET];
+
   const Instruction* return_instruction = instruction->Next();
   Instruction::Code return_opcode = return_instruction->Opcode();
   if (!(return_opcode == Instruction::RETURN && size != kLong) &&
@@ -585,61 +612,74 @@
   DCHECK_LT(return_opcode == Instruction::RETURN_WIDE ? return_reg + 1 : return_reg,
             code_item->registers_size_);
 
-  uint32_t vA, vB, vC;
-  uint64_t dummy_wide;
-  instruction->Decode(vA, vB, dummy_wide, vC, nullptr);
+  uint32_t dst_reg = instruction->VRegA_22c();
+  uint32_t object_reg = instruction->VRegB_22c();
+  uint32_t field_idx = instruction->VRegC_22c();
   uint32_t arg_start = code_item->registers_size_ - code_item->ins_size_;
-  DCHECK_GE(vB, arg_start);
-  DCHECK_LT(vB, code_item->registers_size_);
-  DCHECK_LT(size == kLong ? vA + 1 : vA, code_item->registers_size_);
-  if (vA != return_reg) {
-    return false;  // Not returning the value retrieved by iget?
+  DCHECK_GE(object_reg, arg_start);
+  DCHECK_LT(object_reg, code_item->registers_size_);
+  DCHECK_LT(size == kLong ? dst_reg + 1 : dst_reg, code_item->registers_size_);
+  if (dst_reg != return_reg) {
+    return false;  // Not returning the value retrieved by IGET?
   }
 
-  // TODO: Check that the field is FastInstance().
+  if (!CompilerDriver::ComputeSpecialAccessorInfo(field_idx, false, verifier,
+                                                  &result->d.ifield_data)) {
+    return false;
+  }
 
-  InlineIGetIPutData data;
-  data.d.field = vC;
-  data.d.op_size = size;
-  data.d.is_object = is_object;
-  data.d.object_arg = vB - arg_start;  // Allow iget on any register, not just "this"
-  data.d.src_arg = 0;
-  data.d.reserved = 0;
-  return AddInlineMethod(method_idx, kInlineOpIGet, kInlineSpecial, data.data);
+  result->opcode = kInlineOpIGet;
+  result->flags = kInlineSpecial;
+  InlineIGetIPutData* data = &result->d.ifield_data;
+  data->op_size = size;
+  data->is_object = (opcode == Instruction::IGET_OBJECT) ? 1u : 0u;
+  data->object_arg = object_reg - arg_start;  // Allow IGET on any register, not just "this".
+  data->src_arg = 0;
+  data->reserved = 0;
+  return true;
 }
 
-bool DexFileMethodInliner::AnalyseIPutMethod(int32_t method_idx, const DexFile::CodeItem* code_item,
-                                             OpSize size, bool is_object) {
+bool DexFileMethodInliner::AnalyseIPutMethod(verifier::MethodVerifier* verifier,
+                                             InlineMethod* result) {
+  const DexFile::CodeItem* code_item = verifier->CodeItem();
   const Instruction* instruction = Instruction::At(code_item->insns_);
+  Instruction::Code opcode = instruction->Opcode();
+  DCHECK_LT(static_cast<size_t>(opcode - Instruction::IPUT), arraysize(kIGetIPutOpSizes));
+  uint16_t size = kIGetIPutOpSizes[opcode - Instruction::IPUT];
+
   const Instruction* return_instruction = instruction->Next();
   if (return_instruction->Opcode() != Instruction::RETURN_VOID) {
     // TODO: Support returning an argument.
     // This is needed by builder classes and generated accessor setters.
     //    builder.setX(value): iput value, this, fieldX; return-object this;
     //    object.access$nnn(value): iput value, this, fieldX; return value;
-    // Use InlineIGetIPutData::d::reserved to hold the information.
+    // Use InlineIGetIPutData::reserved to hold the information.
     return false;
   }
 
-  uint32_t vA, vB, vC;
-  uint64_t dummy_wide;
-  instruction->Decode(vA, vB, dummy_wide, vC, nullptr);
+  uint32_t src_reg = instruction->VRegA_22c();
+  uint32_t object_reg = instruction->VRegB_22c();
+  uint32_t field_idx = instruction->VRegC_22c();
   uint32_t arg_start = code_item->registers_size_ - code_item->ins_size_;
-  DCHECK_GE(vB, arg_start);
-  DCHECK_GE(vA, arg_start);
-  DCHECK_LT(vB, code_item->registers_size_);
-  DCHECK_LT(size == kLong ? vA + 1 : vA, code_item->registers_size_);
+  DCHECK_GE(object_reg, arg_start);
+  DCHECK_LT(object_reg, code_item->registers_size_);
+  DCHECK_GE(src_reg, arg_start);
+  DCHECK_LT(size == kLong ? src_reg + 1 : src_reg, code_item->registers_size_);
 
-  // TODO: Check that the field (vC) is FastInstance().
+  if (!CompilerDriver::ComputeSpecialAccessorInfo(field_idx, true, verifier,
+                                                  &result->d.ifield_data)) {
+    return false;
+  }
 
-  InlineIGetIPutData data;
-  data.d.field = vC;
-  data.d.op_size = size;
-  data.d.is_object = is_object;
-  data.d.object_arg = vB - arg_start;  // Allow iput on any register, not just "this"
-  data.d.src_arg = vA - arg_start;
-  data.d.reserved = 0;
-  return AddInlineMethod(method_idx, kInlineOpIPut, kInlineSpecial, data.data);
+  result->opcode = kInlineOpIPut;
+  result->flags = kInlineSpecial;
+  InlineIGetIPutData* data = &result->d.ifield_data;
+  data->op_size = size;
+  data->is_object = (opcode == Instruction::IPUT_OBJECT) ? 1u : 0u;
+  data->object_arg = object_reg - arg_start;  // Allow IPUT on any register, not just "this".
+  data->src_arg = src_reg - arg_start;
+  data->reserved = 0;
+  return true;
 }
 
 }  // namespace art
diff --git a/compiler/dex/quick/dex_file_method_inliner.h b/compiler/dex/quick/dex_file_method_inliner.h
index 6e81303..fe0824c 100644
--- a/compiler/dex/quick/dex_file_method_inliner.h
+++ b/compiler/dex/quick/dex_file_method_inliner.h
@@ -27,6 +27,10 @@
 
 namespace art {
 
+namespace verifier {
+class MethodVerifier;
+}  // namespace verifier
+
 class CallInfo;
 class Mir2Lir;
 
@@ -62,13 +66,7 @@
   kInlineSpecial       = 0x0002,
 };
 
-struct InlineMethod {
-  InlineMethodOpcode opcode;
-  InlineMethodFlags flags;
-  uint32_t data;
-};
-
-// IntrinsicFlags are stored in InlineMethod::data
+// IntrinsicFlags are stored in InlineMethod::d::raw_data
 enum IntrinsicFlags {
   kIntrinsicFlagNone = 0,
 
@@ -97,28 +95,37 @@
 COMPILE_ASSERT(kWord < 8 && kLong < 8 && kSingle < 8 && kDouble < 8 && kUnsignedHalf < 8 &&
                kSignedHalf < 8 && kUnsignedByte < 8 && kSignedByte < 8, op_size_field_too_narrow);
 
-union InlineIGetIPutData {
-  uint32_t data;
-  struct {
-    uint16_t field;
-    uint32_t op_size : 3;  // OpSize
-    uint32_t is_object : 1;
-    uint32_t object_arg : 4;
-    uint32_t src_arg : 4;  // iput only
-    uint32_t reserved : 4;
-  } d;
+struct InlineIGetIPutData {
+  uint16_t op_size : 3;  // OpSize
+  uint16_t is_object : 1;
+  uint16_t object_arg : 4;
+  uint16_t src_arg : 4;  // iput only
+  uint16_t method_is_static : 1;
+  uint16_t reserved : 3;
+  uint16_t field_idx;
+  uint32_t is_volatile : 1;
+  uint32_t field_offset : 31;
 };
-COMPILE_ASSERT(sizeof(InlineIGetIPutData) == sizeof(uint32_t), InvalidSizeOfInlineIGetIPutData);
+COMPILE_ASSERT(sizeof(InlineIGetIPutData) == sizeof(uint64_t), InvalidSizeOfInlineIGetIPutData);
 
-union InlineReturnArgData {
-  uint32_t data;
-  struct {
-    uint16_t arg;
-    uint32_t op_size : 3;  // OpSize
-    uint32_t reserved : 13;
+struct InlineReturnArgData {
+  uint16_t arg;
+  uint16_t op_size : 3;  // OpSize
+  uint16_t is_object : 1;
+  uint16_t reserved : 12;
+  uint32_t reserved2;
+};
+COMPILE_ASSERT(sizeof(InlineReturnArgData) == sizeof(uint64_t), InvalidSizeOfInlineReturnArgData);
+
+struct InlineMethod {
+  InlineMethodOpcode opcode;
+  InlineMethodFlags flags;
+  union {
+    uint64_t data;
+    InlineIGetIPutData ifield_data;
+    InlineReturnArgData return_data;
   } d;
 };
-COMPILE_ASSERT(sizeof(InlineReturnArgData) == sizeof(uint32_t), InvalidSizeOfInlineReturnArgData);
 
 /**
  * Handles inlining of methods from a particular DexFile.
@@ -144,8 +151,8 @@
      * @param method_idx the index of the inlining candidate.
      * @param code_item a previously verified code item of the method.
      */
-    bool AnalyseMethodCode(uint32_t method_idx,
-                           const DexFile::CodeItem* code_item) LOCKS_EXCLUDED(lock_);
+    bool AnalyseMethodCode(verifier::MethodVerifier* verifier)
+        SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) LOCKS_EXCLUDED(lock_);
 
     /**
      * Check whether a particular method index corresponds to an intrinsic function.
@@ -369,17 +376,14 @@
 
     friend class DexFileToMethodInlinerMap;
 
-    bool AddInlineMethod(int32_t method_idx, InlineMethodOpcode opcode,
-                         InlineMethodFlags flags, uint32_t data) LOCKS_EXCLUDED(lock_);
+    bool AddInlineMethod(int32_t method_idx, const InlineMethod& method) LOCKS_EXCLUDED(lock_);
 
-    bool AnalyseReturnMethod(int32_t method_idx, const DexFile::CodeItem* code_item,
-                             OpSize size) LOCKS_EXCLUDED(lock_);
-    bool AnalyseConstMethod(int32_t method_idx, const DexFile::CodeItem* code_item)
-                            LOCKS_EXCLUDED(lock_);
-    bool AnalyseIGetMethod(int32_t method_idx, const DexFile::CodeItem* code_item,
-                           OpSize size, bool is_object) LOCKS_EXCLUDED(lock_);
-    bool AnalyseIPutMethod(int32_t method_idx, const DexFile::CodeItem* code_item,
-                           OpSize size, bool is_object) LOCKS_EXCLUDED(lock_);
+    static bool AnalyseReturnMethod(const DexFile::CodeItem* code_item, InlineMethod* result);
+    static bool AnalyseConstMethod(const DexFile::CodeItem* code_item, InlineMethod* result);
+    static bool AnalyseIGetMethod(verifier::MethodVerifier* verifier, InlineMethod* result)
+        SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+    static bool AnalyseIPutMethod(verifier::MethodVerifier* verifier, InlineMethod* result)
+        SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
     ReaderWriterMutex lock_;
     /*
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 9f48351..5b9d66c 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -29,6 +29,7 @@
 #include "dex_file-inl.h"
 #include "dex/verification_results.h"
 #include "dex/verified_method.h"
+#include "dex/quick/dex_file_method_inliner.h"
 #include "jni_internal.h"
 #include "object_utils.h"
 #include "runtime.h"
@@ -49,6 +50,7 @@
 #include "thread_pool.h"
 #include "trampolines/trampoline_compiler.h"
 #include "verifier/method_verifier.h"
+#include "verifier/method_verifier-inl.h"
 
 #if defined(ART_USE_PORTABLE_COMPILER)
 #include "elf_writer_mclinker.h"
@@ -995,6 +997,30 @@
                                                 class_loader, NULL, type);
 }
 
+bool CompilerDriver::ComputeSpecialAccessorInfo(uint32_t field_idx, bool is_put,
+                                                verifier::MethodVerifier* verifier,
+                                                InlineIGetIPutData* result) {
+  mirror::DexCache* dex_cache = verifier->GetDexCache();
+  uint32_t method_idx = verifier->GetMethodReference().dex_method_index;
+  mirror::ArtMethod* method = dex_cache->GetResolvedMethod(method_idx);
+  mirror::ArtField* field = dex_cache->GetResolvedField(field_idx);
+  if (method == nullptr || field == nullptr) {
+    return false;
+  }
+  mirror::Class* method_class = method->GetDeclaringClass();
+  mirror::Class* field_class = field->GetDeclaringClass();
+  if (!method_class->CanAccessResolvedField(field_class, field, dex_cache, field_idx) ||
+      (is_put && field->IsFinal() && method_class != field_class)) {
+    return false;
+  }
+  DCHECK_GE(field->GetOffset().Int32Value(), 0);
+  result->method_is_static = method->IsStatic();
+  result->field_idx = field_idx;
+  result->field_offset = field->GetOffset().Int32Value();
+  result->is_volatile = field->IsVolatile();
+  return true;
+}
+
 bool CompilerDriver::ComputeInstanceFieldInfo(uint32_t field_idx, const DexCompilationUnit* mUnit,
                                               bool is_put, int* field_offset, bool* is_volatile) {
   ScopedObjectAccess soa(Thread::Current());
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index 4307212..ea43e4f 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -38,10 +38,15 @@
 
 namespace art {
 
+namespace verifier {
+class MethodVerifier;
+}  // namespace verifier
+
 class AOTCompilationStats;
 class ParallelCompilationManager;
 class DexCompilationUnit;
 class DexFileToMethodInlinerMap;
+class InlineIGetIPutData;
 class OatWriter;
 class TimingLogger;
 class VerificationResults;
@@ -194,6 +199,13 @@
                           bool* is_type_initialized, bool* use_direct_type_ptr,
                           uintptr_t* direct_type_ptr);
 
+  // Can we fast path instance field access in a verified accessor?
+  // If yes, computes field's offset and volatility and whether the method is static or not.
+  static bool ComputeSpecialAccessorInfo(uint32_t field_idx, bool is_put,
+                                         verifier::MethodVerifier* verifier,
+                                         InlineIGetIPutData* result)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   // Can we fast path instance field access? Computes field's offset and volatility.
   bool ComputeInstanceFieldInfo(uint32_t field_idx, const DexCompilationUnit* mUnit, bool is_put,
                                 int* field_offset, bool* is_volatile)
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 5ac01f2..90eea5e 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -364,7 +364,7 @@
         if (result && method_inliner_map_ != nullptr) {
           MethodReference ref = verifier->GetMethodReference();
           method_inliner_map_->GetMethodInliner(ref.dex_file)
-              ->AnalyseMethodCode(ref.dex_method_index, verifier->CodeItem());
+              ->AnalyseMethodCode(verifier);
         }
         return result;
       }
diff --git a/runtime/common_test.h b/runtime/common_test.h
index ddaf52a..daa2ff1 100644
--- a/runtime/common_test.h
+++ b/runtime/common_test.h
@@ -677,7 +677,7 @@
       if (result && method_inliner_map_ != nullptr) {
         MethodReference ref = verifier->GetMethodReference();
         method_inliner_map_->GetMethodInliner(ref.dex_file)
-            ->AnalyseMethodCode(ref.dex_method_index, verifier->CodeItem());
+            ->AnalyseMethodCode(verifier);
       }
       return result;
     }