Check FastInstance() early for special getters and setters.

Perform the FastInstance() check for getters and setters
when they are detected by the inliner. This will help avoid
the FastInstance() check for inlining.

We also record the field offset and whether the field is
volatile and whether the method is static for use when
inlining or generating the special accessors.

Change-Id: I3f832fc9ae263883b8a984be89a3b7793398b55a
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;
     }