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

This reverts commit 5dc5727261e87ba8a418e2d0e970c75f67e4ab79.

Change-Id: I3299c8ca5c3ce3f2de994bab61ea16a734f1de33
diff --git a/compiler/dex/quick/arm/call_arm.cc b/compiler/dex/quick/arm/call_arm.cc
index 22466f0..661050f 100644
--- a/compiler/dex/quick/arm/call_arm.cc
+++ b/compiler/dex/quick/arm/call_arm.cc
@@ -127,19 +127,15 @@
   }
 }
 
-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.
+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;
   }
-
-  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);
@@ -152,24 +148,19 @@
   // 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, 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.
+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;
   }
-
-  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);
@@ -183,7 +174,7 @@
   rl_src = ArmMir2Lir::ArgLoc(rl_src);
   rl_obj = ArmMir2Lir::ArgLoc(rl_obj);
   // Reject if source is split across registers & frame
-  if (rl_src.location == kLocInvalid) {
+  if (rl_obj.location == kLocInvalid) {
     ResetRegPool();
     return NULL;
   }
@@ -191,7 +182,6 @@
   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);
 }
@@ -229,6 +219,8 @@
  */
 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;
@@ -239,17 +231,30 @@
       break;
     case kInlineOpConst:
       ArmMir2Lir::GenPrintLabel(mir);
-      LoadConstant(rARM_RET0, static_cast<int>(special.d.data));
+      LoadConstant(rARM_RET0, special.data);
       next_mir = GetNextMir(&bb, mir);
       break;
-    case kInlineOpIGet:
-      next_mir = SpecialIGet(&bb, mir, special);
+    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);
       break;
-    case kInlineOpIPut:
-      next_mir = SpecialIPut(&bb, mir, special);
+    }
+    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);
       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 598da89..0ed4576 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, const InlineMethod& special);
-    MIR* SpecialIPut(BasicBlock** bb, MIR* mir, const InlineMethod& special);
+    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* 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 0ad8abf..0937be3 100644
--- a/compiler/dex/quick/dex_file_method_inliner.cc
+++ b/compiler/dex/quick/dex_file_method_inliner.cc
@@ -24,27 +24,11 @@
 #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
@@ -183,7 +167,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),
@@ -264,58 +248,57 @@
 DexFileMethodInliner::~DexFileMethodInliner() {
 }
 
-bool DexFileMethodInliner::AnalyseMethodCode(verifier::MethodVerifier* verifier) {
+bool DexFileMethodInliner::AnalyseMethodCode(uint32_t method_idx,
+                                             const DexFile::CodeItem* code_item) {
   // 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:
-      method.opcode = kInlineOpNop;
-      method.flags = kInlineSpecial;
-      method.d.data = 0u;
-      success = true;
-      break;
+      return AddInlineMethod(method_idx, kInlineOpNop, kInlineSpecial, 0);
     case Instruction::RETURN:
     case Instruction::RETURN_OBJECT:
+      return AnalyseReturnMethod(method_idx, code_item, kWord);
     case Instruction::RETURN_WIDE:
-      success = AnalyseReturnMethod(code_item, &method);
-      break;
+      return AnalyseReturnMethod(method_idx, code_item, kLong);
     case Instruction::CONST:
     case Instruction::CONST_4:
     case Instruction::CONST_16:
     case Instruction::CONST_HIGH16:
       // TODO: Support wide constants (RETURN_WIDE).
-      success = AnalyseConstMethod(code_item, &method);
-      break;
+      return AnalyseConstMethod(method_idx, code_item);
     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:
-      success = AnalyseIGetMethod(verifier, &method);
-      break;
+      return AnalyseIGetMethod(method_idx, code_item, kLong, false);
     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:
-      success = AnalyseIPutMethod(verifier, &method);
-      break;
+      return AnalyseIPutMethod(method_idx, code_item, kLong, false);
     default:
-      success = false;
-      break;
-  }
-  return success && AddInlineMethod(verifier->GetMethodReference().dex_method_index, method);
+      return false;
+    }
 }
 
 bool DexFileMethodInliner::IsIntrinsic(uint32_t method_index) {
@@ -340,13 +323,13 @@
     case kIntrinsicFloatCvt:
       return backend->GenInlinedFloatCvt(info);
     case kIntrinsicReverseBytes:
-      return backend->GenInlinedReverseBytes(info, static_cast<OpSize>(intrinsic.d.data));
+      return backend->GenInlinedReverseBytes(info, static_cast<OpSize>(intrinsic.data));
     case kIntrinsicAbsInt:
       return backend->GenInlinedAbsInt(info);
     case kIntrinsicAbsLong:
       return backend->GenInlinedAbsLong(info);
     case kIntrinsicMinMaxInt:
-      return backend->GenInlinedMinMaxInt(info, intrinsic.d.data & kIntrinsicFlagMin);
+      return backend->GenInlinedMinMaxInt(info, intrinsic.data & kIntrinsicFlagMin);
     case kIntrinsicSqrt:
       return backend->GenInlinedSqrt(info);
     case kIntrinsicCharAt:
@@ -354,27 +337,26 @@
     case kIntrinsicCompareTo:
       return backend->GenInlinedStringCompareTo(info);
     case kIntrinsicIsEmptyOrLength:
-      return backend->GenInlinedStringIsEmptyOrLength(
-          info, intrinsic.d.data & kIntrinsicFlagIsEmpty);
+      return backend->GenInlinedStringIsEmptyOrLength(info, intrinsic.data & kIntrinsicFlagIsEmpty);
     case kIntrinsicIndexOf:
-      return backend->GenInlinedIndexOf(info, intrinsic.d.data & kIntrinsicFlagBase0);
+      return backend->GenInlinedIndexOf(info, intrinsic.data & kIntrinsicFlagBase0);
     case kIntrinsicCurrentThread:
       return backend->GenInlinedCurrentThread(info);
     case kIntrinsicPeek:
-      return backend->GenInlinedPeek(info, static_cast<OpSize>(intrinsic.d.data));
+      return backend->GenInlinedPeek(info, static_cast<OpSize>(intrinsic.data));
     case kIntrinsicPoke:
-      return backend->GenInlinedPoke(info, static_cast<OpSize>(intrinsic.d.data));
+      return backend->GenInlinedPoke(info, static_cast<OpSize>(intrinsic.data));
     case kIntrinsicCas:
-      return backend->GenInlinedCas(info, intrinsic.d.data & kIntrinsicFlagIsLong,
-                                    intrinsic.d.data & kIntrinsicFlagIsObject);
+      return backend->GenInlinedCas(info, intrinsic.data & kIntrinsicFlagIsLong,
+                                    intrinsic.data & kIntrinsicFlagIsObject);
     case kIntrinsicUnsafeGet:
-      return backend->GenInlinedUnsafeGet(info, intrinsic.d.data & kIntrinsicFlagIsLong,
-                                          intrinsic.d.data & kIntrinsicFlagIsVolatile);
+      return backend->GenInlinedUnsafeGet(info, intrinsic.data & kIntrinsicFlagIsLong,
+                                          intrinsic.data & kIntrinsicFlagIsVolatile);
     case kIntrinsicUnsafePut:
-      return backend->GenInlinedUnsafePut(info, intrinsic.d.data & kIntrinsicFlagIsLong,
-                                          intrinsic.d.data & kIntrinsicFlagIsObject,
-                                          intrinsic.d.data & kIntrinsicFlagIsVolatile,
-                                          intrinsic.d.data & kIntrinsicFlagIsOrdered);
+      return backend->GenInlinedUnsafePut(info, intrinsic.data & kIntrinsicFlagIsLong,
+                                          intrinsic.data & kIntrinsicFlagIsObject,
+                                          intrinsic.data & kIntrinsicFlagIsVolatile,
+                                          intrinsic.data & kIntrinsicFlagIsOrdered);
     default:
       LOG(FATAL) << "Unexpected intrinsic opcode: " << intrinsic.opcode;
       return false;  // avoid warning "control reaches end of non-void function"
@@ -523,10 +505,12 @@
   dex_file_ = dex_file;
 }
 
-bool DexFileMethodInliner::AddInlineMethod(int32_t method_idx, const InlineMethod& method) {
+bool DexFileMethodInliner::AddInlineMethod(int32_t method_idx, InlineMethodOpcode opcode,
+                                           InlineMethodFlags flags, uint32_t data) {
   WriterMutexLock mu(Thread::Current(), lock_);
   if (LIKELY(inline_methods_.find(method_idx) == inline_methods_.end())) {
-    inline_methods_.Put(method_idx, method);
+    InlineMethod im = {opcode, flags, data};
+    inline_methods_.Put(method_idx, im);
     return true;
   } else {
     if (PrettyMethod(method_idx, *dex_file_) == "int java.lang.String.length()") {
@@ -538,30 +522,26 @@
   }
 }
 
-bool DexFileMethodInliner::AnalyseReturnMethod(const DexFile::CodeItem* code_item,
-                                               InlineMethod* result) {
+bool DexFileMethodInliner::AnalyseReturnMethod(int32_t method_idx,
+                                               const DexFile::CodeItem* code_item, OpSize size) {
   const Instruction* return_instruction = Instruction::At(code_item->insns_);
-  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;
+  if (return_instruction->Opcode() == Instruction::RETURN_VOID) {
+    return AddInlineMethod(method_idx, kInlineOpNop, kInlineSpecial, 0);
+  }
   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_);
 
-  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;
+  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);
 }
 
-bool DexFileMethodInliner::AnalyseConstMethod(const DexFile::CodeItem* code_item,
-                                              InlineMethod* result) {
+bool DexFileMethodInliner::AnalyseConstMethod(int32_t method_idx,
+                                              const DexFile::CodeItem* code_item) {
   const Instruction* instruction = Instruction::At(code_item->insns_);
   const Instruction* return_instruction = instruction->Next();
   Instruction::Code return_opcode = return_instruction->Opcode();
@@ -586,20 +566,13 @@
   if (return_opcode == Instruction::RETURN_OBJECT && vB != 0) {
     return false;  // Returning non-null reference constant?
   }
-  result->opcode = kInlineOpConst;
-  result->flags = kInlineSpecial;
-  result->d.data = static_cast<uint64_t>(vB);
-  return true;
+  return AddInlineMethod(method_idx, kInlineOpConst, kInlineSpecial, vB);
 }
 
-bool DexFileMethodInliner::AnalyseIGetMethod(verifier::MethodVerifier* verifier,
-                                             InlineMethod* result) {
-  const DexFile::CodeItem* code_item = verifier->CodeItem();
+bool DexFileMethodInliner::AnalyseIGetMethod(int32_t method_idx, const DexFile::CodeItem* code_item,
+                                             OpSize size, bool is_object) {
   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) &&
@@ -612,74 +585,61 @@
   DCHECK_LT(return_opcode == Instruction::RETURN_WIDE ? return_reg + 1 : return_reg,
             code_item->registers_size_);
 
-  uint32_t dst_reg = instruction->VRegA_22c();
-  uint32_t object_reg = instruction->VRegB_22c();
-  uint32_t field_idx = instruction->VRegC_22c();
+  uint32_t vA, vB, vC;
+  uint64_t dummy_wide;
+  instruction->Decode(vA, vB, dummy_wide, vC, nullptr);
   uint32_t arg_start = code_item->registers_size_ - code_item->ins_size_;
-  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?
+  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?
   }
 
-  if (!CompilerDriver::ComputeSpecialAccessorInfo(field_idx, false, verifier,
-                                                  &result->d.ifield_data)) {
-    return false;
-  }
+  // TODO: Check that the field is FastInstance().
 
-  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;
+  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);
 }
 
-bool DexFileMethodInliner::AnalyseIPutMethod(verifier::MethodVerifier* verifier,
-                                             InlineMethod* result) {
-  const DexFile::CodeItem* code_item = verifier->CodeItem();
+bool DexFileMethodInliner::AnalyseIPutMethod(int32_t method_idx, const DexFile::CodeItem* code_item,
+                                             OpSize size, bool is_object) {
   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::reserved to hold the information.
+    // Use InlineIGetIPutData::d::reserved to hold the information.
     return false;
   }
 
-  uint32_t src_reg = instruction->VRegA_22c();
-  uint32_t object_reg = instruction->VRegB_22c();
-  uint32_t field_idx = instruction->VRegC_22c();
+  uint32_t vA, vB, vC;
+  uint64_t dummy_wide;
+  instruction->Decode(vA, vB, dummy_wide, vC, nullptr);
   uint32_t arg_start = code_item->registers_size_ - code_item->ins_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_);
+  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_);
 
-  if (!CompilerDriver::ComputeSpecialAccessorInfo(field_idx, true, verifier,
-                                                  &result->d.ifield_data)) {
-    return false;
-  }
+  // TODO: Check that the field (vC) is FastInstance().
 
-  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;
+  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);
 }
 
 }  // namespace art
diff --git a/compiler/dex/quick/dex_file_method_inliner.h b/compiler/dex/quick/dex_file_method_inliner.h
index fe0824c..6e81303 100644
--- a/compiler/dex/quick/dex_file_method_inliner.h
+++ b/compiler/dex/quick/dex_file_method_inliner.h
@@ -27,10 +27,6 @@
 
 namespace art {
 
-namespace verifier {
-class MethodVerifier;
-}  // namespace verifier
-
 class CallInfo;
 class Mir2Lir;
 
@@ -66,7 +62,13 @@
   kInlineSpecial       = 0x0002,
 };
 
-// IntrinsicFlags are stored in InlineMethod::d::raw_data
+struct InlineMethod {
+  InlineMethodOpcode opcode;
+  InlineMethodFlags flags;
+  uint32_t data;
+};
+
+// IntrinsicFlags are stored in InlineMethod::data
 enum IntrinsicFlags {
   kIntrinsicFlagNone = 0,
 
@@ -95,37 +97,28 @@
 COMPILE_ASSERT(kWord < 8 && kLong < 8 && kSingle < 8 && kDouble < 8 && kUnsignedHalf < 8 &&
                kSignedHalf < 8 && kUnsignedByte < 8 && kSignedByte < 8, op_size_field_too_narrow);
 
-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(uint64_t), InvalidSizeOfInlineIGetIPutData);
-
-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;
+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;
 };
+COMPILE_ASSERT(sizeof(InlineIGetIPutData) == sizeof(uint32_t), InvalidSizeOfInlineIGetIPutData);
+
+union InlineReturnArgData {
+  uint32_t data;
+  struct {
+    uint16_t arg;
+    uint32_t op_size : 3;  // OpSize
+    uint32_t reserved : 13;
+  } d;
+};
+COMPILE_ASSERT(sizeof(InlineReturnArgData) == sizeof(uint32_t), InvalidSizeOfInlineReturnArgData);
 
 /**
  * Handles inlining of methods from a particular DexFile.
@@ -151,8 +144,8 @@
      * @param method_idx the index of the inlining candidate.
      * @param code_item a previously verified code item of the method.
      */
-    bool AnalyseMethodCode(verifier::MethodVerifier* verifier)
-        SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) LOCKS_EXCLUDED(lock_);
+    bool AnalyseMethodCode(uint32_t method_idx,
+                           const DexFile::CodeItem* code_item) LOCKS_EXCLUDED(lock_);
 
     /**
      * Check whether a particular method index corresponds to an intrinsic function.
@@ -376,14 +369,17 @@
 
     friend class DexFileToMethodInlinerMap;
 
-    bool AddInlineMethod(int32_t method_idx, const InlineMethod& method) LOCKS_EXCLUDED(lock_);
+    bool AddInlineMethod(int32_t method_idx, InlineMethodOpcode opcode,
+                         InlineMethodFlags flags, uint32_t data) 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_);
+    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_);
 
     ReaderWriterMutex lock_;
     /*
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 5b9d66c..9f48351 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -29,7 +29,6 @@
 #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"
@@ -50,7 +49,6 @@
 #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"
@@ -997,30 +995,6 @@
                                                 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 ea43e4f..4307212 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -38,15 +38,10 @@
 
 namespace art {
 
-namespace verifier {
-class MethodVerifier;
-}  // namespace verifier
-
 class AOTCompilationStats;
 class ParallelCompilationManager;
 class DexCompilationUnit;
 class DexFileToMethodInlinerMap;
-class InlineIGetIPutData;
 class OatWriter;
 class TimingLogger;
 class VerificationResults;
@@ -199,13 +194,6 @@
                           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 90eea5e..5ac01f2 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(verifier);
+              ->AnalyseMethodCode(ref.dex_method_index, verifier->CodeItem());
         }
         return result;
       }
diff --git a/runtime/common_test.h b/runtime/common_test.h
index daa2ff1..ddaf52a 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(verifier);
+            ->AnalyseMethodCode(ref.dex_method_index, verifier->CodeItem());
       }
       return result;
     }