Compiler: rearranging the deck chairs.

First of several steps to adopt the new source directory layout.  No
logic changes - just moved files around.

Change-Id: I087631f8aa23973e18da4dc7706249c490bee061
diff --git a/src/compiler/dex/quick/gen_invoke.cc b/src/compiler/dex/quick/gen_invoke.cc
new file mode 100644
index 0000000..9a1fa5c
--- /dev/null
+++ b/src/compiler/dex/quick/gen_invoke.cc
@@ -0,0 +1,1477 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "codegen_util.h"
+#include "compiler/dex/compiler_ir.h"
+#include "oat/runtime/oat_support_entrypoints.h"
+#include "ralloc_util.h"
+#include "x86/codegen_x86.h"
+
+namespace art {
+
+/*
+ * This source files contains "gen" codegen routines that should
+ * be applicable to most targets.  Only mid-level support utilities
+ * and "op" calls may be used here.
+ */
+
+/*
+ * To save scheduling time, helper calls are broken into two parts: generation of
+ * the helper target address, and the actuall call to the helper.  Because x86
+ * has a memory call operation, part 1 is a NOP for x86.  For other targets,
+ * load arguments between the two parts.
+ */
+int Codegen::CallHelperSetup(CompilationUnit* cu, int helper_offset)
+{
+  return (cu->instruction_set == kX86) ? 0 : LoadHelper(cu, helper_offset);
+}
+
+/* NOTE: if r_tgt is a temp, it will be freed following use */
+LIR* Codegen::CallHelper(CompilationUnit* cu, int r_tgt, int helper_offset, bool safepoint_pc)
+{
+  LIR* call_inst;
+  if (cu->instruction_set == kX86) {
+    call_inst = OpThreadMem(cu, kOpBlx, helper_offset);
+  } else {
+    call_inst = OpReg(cu, kOpBlx, r_tgt);
+    FreeTemp(cu, r_tgt);
+  }
+  if (safepoint_pc) {
+    MarkSafepointPC(cu, call_inst);
+  }
+  return call_inst;
+}
+
+void Codegen::CallRuntimeHelperImm(CompilationUnit* cu, int helper_offset, int arg0,
+                                   bool safepoint_pc) {
+  int r_tgt = CallHelperSetup(cu, helper_offset);
+  LoadConstant(cu, TargetReg(kArg0), arg0);
+  ClobberCalleeSave(cu);
+  CallHelper(cu, r_tgt, helper_offset, safepoint_pc);
+}
+
+void Codegen::CallRuntimeHelperReg(CompilationUnit* cu, int helper_offset, int arg0,
+                                   bool safepoint_pc) {
+  int r_tgt = CallHelperSetup(cu, helper_offset);
+  OpRegCopy(cu, TargetReg(kArg0), arg0);
+  ClobberCalleeSave(cu);
+  CallHelper(cu, r_tgt, helper_offset, safepoint_pc);
+}
+
+void Codegen::CallRuntimeHelperRegLocation(CompilationUnit* cu, int helper_offset, RegLocation arg0,
+                                          bool safepoint_pc) {
+  int r_tgt = CallHelperSetup(cu, helper_offset);
+  if (arg0.wide == 0) {
+    LoadValueDirectFixed(cu, arg0, TargetReg(kArg0));
+  } else {
+    LoadValueDirectWideFixed(cu, arg0, TargetReg(kArg0), TargetReg(kArg1));
+  }
+  ClobberCalleeSave(cu);
+  CallHelper(cu, r_tgt, helper_offset, safepoint_pc);
+}
+
+void Codegen::CallRuntimeHelperImmImm(CompilationUnit* cu, int helper_offset, int arg0, int arg1,
+                                      bool safepoint_pc) {
+  int r_tgt = CallHelperSetup(cu, helper_offset);
+  LoadConstant(cu, TargetReg(kArg0), arg0);
+  LoadConstant(cu, TargetReg(kArg1), arg1);
+  ClobberCalleeSave(cu);
+  CallHelper(cu, r_tgt, helper_offset, safepoint_pc);
+}
+
+void Codegen::CallRuntimeHelperImmRegLocation(CompilationUnit* cu, int helper_offset, int arg0,
+                                              RegLocation arg1, bool safepoint_pc) {
+  int r_tgt = CallHelperSetup(cu, helper_offset);
+  if (arg1.wide == 0) {
+    LoadValueDirectFixed(cu, arg1, TargetReg(kArg1));
+  } else {
+    LoadValueDirectWideFixed(cu, arg1, TargetReg(kArg1), TargetReg(kArg2));
+  }
+  LoadConstant(cu, TargetReg(kArg0), arg0);
+  ClobberCalleeSave(cu);
+  CallHelper(cu, r_tgt, helper_offset, safepoint_pc);
+}
+
+void Codegen::CallRuntimeHelperRegLocationImm(CompilationUnit* cu, int helper_offset,
+                                              RegLocation arg0, int arg1, bool safepoint_pc) {
+  int r_tgt = CallHelperSetup(cu, helper_offset);
+  LoadValueDirectFixed(cu, arg0, TargetReg(kArg0));
+  LoadConstant(cu, TargetReg(kArg1), arg1);
+  ClobberCalleeSave(cu);
+  CallHelper(cu, r_tgt, helper_offset, safepoint_pc);
+}
+
+void Codegen::CallRuntimeHelperImmReg(CompilationUnit* cu, int helper_offset, int arg0, int arg1,
+                                      bool safepoint_pc) {
+  int r_tgt = CallHelperSetup(cu, helper_offset);
+  OpRegCopy(cu, TargetReg(kArg1), arg1);
+  LoadConstant(cu, TargetReg(kArg0), arg0);
+  ClobberCalleeSave(cu);
+  CallHelper(cu, r_tgt, helper_offset, safepoint_pc);
+}
+
+void Codegen::CallRuntimeHelperRegImm(CompilationUnit* cu, int helper_offset, int arg0, int arg1,
+                             bool safepoint_pc) {
+  int r_tgt = CallHelperSetup(cu, helper_offset);
+  OpRegCopy(cu, TargetReg(kArg0), arg0);
+  LoadConstant(cu, TargetReg(kArg1), arg1);
+  ClobberCalleeSave(cu);
+  CallHelper(cu, r_tgt, helper_offset, safepoint_pc);
+}
+
+void Codegen::CallRuntimeHelperImmMethod(CompilationUnit* cu, int helper_offset, int arg0,
+                                         bool safepoint_pc) {
+  int r_tgt = CallHelperSetup(cu, helper_offset);
+  LoadCurrMethodDirect(cu, TargetReg(kArg1));
+  LoadConstant(cu, TargetReg(kArg0), arg0);
+  ClobberCalleeSave(cu);
+  CallHelper(cu, r_tgt, helper_offset, safepoint_pc);
+}
+
+void Codegen::CallRuntimeHelperRegLocationRegLocation(CompilationUnit* cu, int helper_offset,
+                                                      RegLocation arg0, RegLocation arg1,
+                                                      bool safepoint_pc) {
+  int r_tgt = CallHelperSetup(cu, helper_offset);
+  if (arg0.wide == 0) {
+    LoadValueDirectFixed(cu, arg0, arg0.fp ? TargetReg(kFArg0) : TargetReg(kArg0));
+    if (arg1.wide == 0) {
+      if (cu->instruction_set == kMips) {
+        LoadValueDirectFixed(cu, arg1, arg1.fp ? TargetReg(kFArg2) : TargetReg(kArg1));
+      } else {
+        LoadValueDirectFixed(cu, arg1, TargetReg(kArg1));
+      }
+    } else {
+      if (cu->instruction_set == kMips) {
+        LoadValueDirectWideFixed(cu, arg1, arg1.fp ? TargetReg(kFArg2) : TargetReg(kArg1), arg1.fp ? TargetReg(kFArg3) : TargetReg(kArg2));
+      } else {
+        LoadValueDirectWideFixed(cu, arg1, TargetReg(kArg1), TargetReg(kArg2));
+      }
+    }
+  } else {
+    LoadValueDirectWideFixed(cu, arg0, arg0.fp ? TargetReg(kFArg0) : TargetReg(kArg0), arg0.fp ? TargetReg(kFArg1) : TargetReg(kArg1));
+    if (arg1.wide == 0) {
+      LoadValueDirectFixed(cu, arg1, arg1.fp ? TargetReg(kFArg2) : TargetReg(kArg2));
+    } else {
+      LoadValueDirectWideFixed(cu, arg1, arg1.fp ? TargetReg(kFArg2) : TargetReg(kArg2), arg1.fp ? TargetReg(kFArg3) : TargetReg(kArg3));
+    }
+  }
+  ClobberCalleeSave(cu);
+  CallHelper(cu, r_tgt, helper_offset, safepoint_pc);
+}
+
+void Codegen::CallRuntimeHelperRegReg(CompilationUnit* cu, int helper_offset, int arg0, int arg1,
+                                      bool safepoint_pc) {
+  int r_tgt = CallHelperSetup(cu, helper_offset);
+  DCHECK_NE(TargetReg(kArg0), arg1);  // check copy into arg0 won't clobber arg1
+  OpRegCopy(cu, TargetReg(kArg0), arg0);
+  OpRegCopy(cu, TargetReg(kArg1), arg1);
+  ClobberCalleeSave(cu);
+  CallHelper(cu, r_tgt, helper_offset, safepoint_pc);
+}
+
+void Codegen::CallRuntimeHelperRegRegImm(CompilationUnit* cu, int helper_offset, int arg0, int arg1,
+                                         int arg2, bool safepoint_pc) {
+  int r_tgt = CallHelperSetup(cu, helper_offset);
+  DCHECK_NE(TargetReg(kArg0), arg1);  // check copy into arg0 won't clobber arg1
+  OpRegCopy(cu, TargetReg(kArg0), arg0);
+  OpRegCopy(cu, TargetReg(kArg1), arg1);
+  LoadConstant(cu, TargetReg(kArg2), arg2);
+  ClobberCalleeSave(cu);
+  CallHelper(cu, r_tgt, helper_offset, safepoint_pc);
+}
+
+void Codegen::CallRuntimeHelperImmMethodRegLocation(CompilationUnit* cu, int helper_offset,
+                                                    int arg0, RegLocation arg2, bool safepoint_pc) {
+  int r_tgt = CallHelperSetup(cu, helper_offset);
+  LoadValueDirectFixed(cu, arg2, TargetReg(kArg2));
+  LoadCurrMethodDirect(cu, TargetReg(kArg1));
+  LoadConstant(cu, TargetReg(kArg0), arg0);
+  ClobberCalleeSave(cu);
+  CallHelper(cu, r_tgt, helper_offset, safepoint_pc);
+}
+
+void Codegen::CallRuntimeHelperImmMethodImm(CompilationUnit* cu, int helper_offset, int arg0,
+                                            int arg2, bool safepoint_pc) {
+  int r_tgt = CallHelperSetup(cu, helper_offset);
+  LoadCurrMethodDirect(cu, TargetReg(kArg1));
+  LoadConstant(cu, TargetReg(kArg2), arg2);
+  LoadConstant(cu, TargetReg(kArg0), arg0);
+  ClobberCalleeSave(cu);
+  CallHelper(cu, r_tgt, helper_offset, safepoint_pc);
+}
+
+void Codegen::CallRuntimeHelperImmRegLocationRegLocation(CompilationUnit* cu, int helper_offset,
+                                                         int arg0, RegLocation arg1,
+                                                         RegLocation arg2, bool safepoint_pc) {
+  int r_tgt = CallHelperSetup(cu, helper_offset);
+  LoadValueDirectFixed(cu, arg1, TargetReg(kArg1));
+  if (arg2.wide == 0) {
+    LoadValueDirectFixed(cu, arg2, TargetReg(kArg2));
+  } else {
+    LoadValueDirectWideFixed(cu, arg2, TargetReg(kArg2), TargetReg(kArg3));
+  }
+  LoadConstant(cu, TargetReg(kArg0), arg0);
+  ClobberCalleeSave(cu);
+  CallHelper(cu, r_tgt, helper_offset, safepoint_pc);
+}
+
+/*
+ * If there are any ins passed in registers that have not been promoted
+ * to a callee-save register, flush them to the frame.  Perform intial
+ * assignment of promoted arguments.
+ *
+ * ArgLocs is an array of location records describing the incoming arguments
+ * with one location record per word of argument.
+ */
+void Codegen::FlushIns(CompilationUnit* cu, RegLocation* ArgLocs, RegLocation rl_method)
+{
+  /*
+   * Dummy up a RegLocation for the incoming Method*
+   * It will attempt to keep kArg0 live (or copy it to home location
+   * if promoted).
+   */
+  RegLocation rl_src = rl_method;
+  rl_src.location = kLocPhysReg;
+  rl_src.low_reg = TargetReg(kArg0);
+  rl_src.home = false;
+  MarkLive(cu, rl_src.low_reg, rl_src.s_reg_low);
+  StoreValue(cu, rl_method, rl_src);
+  // If Method* has been promoted, explicitly flush
+  if (rl_method.location == kLocPhysReg) {
+    StoreWordDisp(cu, TargetReg(kSp), 0, TargetReg(kArg0));
+  }
+
+  if (cu->num_ins == 0)
+    return;
+  const int num_arg_regs = 3;
+  static SpecialTargetRegister arg_regs[] = {kArg1, kArg2, kArg3};
+  int start_vreg = cu->num_dalvik_registers - cu->num_ins;
+  /*
+   * Copy incoming arguments to their proper home locations.
+   * NOTE: an older version of dx had an issue in which
+   * it would reuse static method argument registers.
+   * This could result in the same Dalvik virtual register
+   * being promoted to both core and fp regs. To account for this,
+   * we only copy to the corresponding promoted physical register
+   * if it matches the type of the SSA name for the incoming
+   * argument.  It is also possible that long and double arguments
+   * end up half-promoted.  In those cases, we must flush the promoted
+   * half to memory as well.
+   */
+  for (int i = 0; i < cu->num_ins; i++) {
+    PromotionMap* v_map = &cu->promotion_map[start_vreg + i];
+    if (i < num_arg_regs) {
+      // If arriving in register
+      bool need_flush = true;
+      RegLocation* t_loc = &ArgLocs[i];
+      if ((v_map->core_location == kLocPhysReg) && !t_loc->fp) {
+        OpRegCopy(cu, v_map->core_reg, TargetReg(arg_regs[i]));
+        need_flush = false;
+      } else if ((v_map->fp_location == kLocPhysReg) && t_loc->fp) {
+        OpRegCopy(cu, v_map->FpReg, TargetReg(arg_regs[i]));
+        need_flush = false;
+      } else {
+        need_flush = true;
+      }
+
+      // For wide args, force flush if only half is promoted
+      if (t_loc->wide) {
+        PromotionMap* p_map = v_map + (t_loc->high_word ? -1 : +1);
+        need_flush |= (p_map->core_location != v_map->core_location) ||
+            (p_map->fp_location != v_map->fp_location);
+      }
+      if (need_flush) {
+        StoreBaseDisp(cu, TargetReg(kSp), SRegOffset(cu, start_vreg + i),
+                      TargetReg(arg_regs[i]), kWord);
+      }
+    } else {
+      // If arriving in frame & promoted
+      if (v_map->core_location == kLocPhysReg) {
+        LoadWordDisp(cu, TargetReg(kSp), SRegOffset(cu, start_vreg + i),
+                     v_map->core_reg);
+      }
+      if (v_map->fp_location == kLocPhysReg) {
+        LoadWordDisp(cu, TargetReg(kSp), SRegOffset(cu, start_vreg + i),
+                     v_map->FpReg);
+      }
+    }
+  }
+}
+
+/*
+ * Bit of a hack here - in the absence of a real scheduling pass,
+ * emit the next instruction in static & direct invoke sequences.
+ */
+static int NextSDCallInsn(CompilationUnit* cu, CallInfo* info,
+                          int state, uint32_t dex_idx, uint32_t unused,
+                          uintptr_t direct_code, uintptr_t direct_method,
+                          InvokeType type)
+{
+  Codegen* cg = cu->cg.get();
+  if (cu->instruction_set != kThumb2) {
+    // Disable sharpening
+    direct_code = 0;
+    direct_method = 0;
+  }
+  if (direct_code != 0 && direct_method != 0) {
+    switch (state) {
+    case 0:  // Get the current Method* [sets kArg0]
+      if (direct_code != static_cast<unsigned int>(-1)) {
+        cg->LoadConstant(cu, cg->TargetReg(kInvokeTgt), direct_code);
+      } else {
+        LIR* data_target = ScanLiteralPool(cu->code_literal_list, dex_idx, 0);
+        if (data_target == NULL) {
+          data_target = AddWordData(cu, &cu->code_literal_list, dex_idx);
+          data_target->operands[1] = type;
+        }
+        LIR* load_pc_rel = cg->OpPcRelLoad(cu, cg->TargetReg(kInvokeTgt), data_target);
+        AppendLIR(cu, load_pc_rel);
+        DCHECK_EQ(cu->instruction_set, kThumb2) << reinterpret_cast<void*>(data_target);
+      }
+      if (direct_method != static_cast<unsigned int>(-1)) {
+        cg->LoadConstant(cu, cg->TargetReg(kArg0), direct_method);
+      } else {
+        LIR* data_target = ScanLiteralPool(cu->method_literal_list, dex_idx, 0);
+        if (data_target == NULL) {
+          data_target = AddWordData(cu, &cu->method_literal_list, dex_idx);
+          data_target->operands[1] = type;
+        }
+        LIR* load_pc_rel = cg->OpPcRelLoad(cu, cg->TargetReg(kArg0), data_target);
+        AppendLIR(cu, load_pc_rel);
+        DCHECK_EQ(cu->instruction_set, kThumb2) << reinterpret_cast<void*>(data_target);
+      }
+      break;
+    default:
+      return -1;
+    }
+  } else {
+    switch (state) {
+    case 0:  // Get the current Method* [sets kArg0]
+      // TUNING: we can save a reg copy if Method* has been promoted.
+      cg->LoadCurrMethodDirect(cu, cg->TargetReg(kArg0));
+      break;
+    case 1:  // Get method->dex_cache_resolved_methods_
+      cg->LoadWordDisp(cu, cg->TargetReg(kArg0),
+        mirror::AbstractMethod::DexCacheResolvedMethodsOffset().Int32Value(), cg->TargetReg(kArg0));
+      // Set up direct code if known.
+      if (direct_code != 0) {
+        if (direct_code != static_cast<unsigned int>(-1)) {
+          cg->LoadConstant(cu, cg->TargetReg(kInvokeTgt), direct_code);
+        } else {
+          LIR* data_target = ScanLiteralPool(cu->code_literal_list, dex_idx, 0);
+          if (data_target == NULL) {
+            data_target = AddWordData(cu, &cu->code_literal_list, dex_idx);
+            data_target->operands[1] = type;
+          }
+          LIR* load_pc_rel = cg->OpPcRelLoad(cu, cg->TargetReg(kInvokeTgt), data_target);
+          AppendLIR(cu, load_pc_rel);
+          DCHECK_EQ(cu->instruction_set, kThumb2) << reinterpret_cast<void*>(data_target);
+        }
+      }
+      break;
+    case 2:  // Grab target method*
+      cg->LoadWordDisp(cu, cg->TargetReg(kArg0),
+                       mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() + dex_idx * 4,
+                       cg-> TargetReg(kArg0));
+      break;
+    case 3:  // Grab the code from the method*
+      if (cu->instruction_set != kX86) {
+        if (direct_code == 0) {
+          cg->LoadWordDisp(cu, cg->TargetReg(kArg0),
+                           mirror::AbstractMethod::GetCodeOffset().Int32Value(),
+                           cg->TargetReg(kInvokeTgt));
+        }
+        break;
+      }
+      // Intentional fallthrough for x86
+    default:
+      return -1;
+    }
+  }
+  return state + 1;
+}
+
+/*
+ * Bit of a hack here - in the absence of a real scheduling pass,
+ * emit the next instruction in a virtual invoke sequence.
+ * We can use kLr as a temp prior to target address loading
+ * Note also that we'll load the first argument ("this") into
+ * kArg1 here rather than the standard LoadArgRegs.
+ */
+static int NextVCallInsn(CompilationUnit* cu, CallInfo* info,
+                         int state, uint32_t dex_idx, uint32_t method_idx,
+                         uintptr_t unused, uintptr_t unused2, InvokeType unused3)
+{
+  Codegen* cg = cu->cg.get();
+  /*
+   * This is the fast path in which the target virtual method is
+   * fully resolved at compile time.
+   */
+  switch (state) {
+    case 0: {  // Get "this" [set kArg1]
+      RegLocation  rl_arg = info->args[0];
+      cg->LoadValueDirectFixed(cu, rl_arg, cg->TargetReg(kArg1));
+      break;
+    }
+    case 1: // Is "this" null? [use kArg1]
+      cg->GenNullCheck(cu, info->args[0].s_reg_low, cg->TargetReg(kArg1), info->opt_flags);
+      // get this->klass_ [use kArg1, set kInvokeTgt]
+      cg->LoadWordDisp(cu, cg->TargetReg(kArg1), mirror::Object::ClassOffset().Int32Value(),
+                       cg->TargetReg(kInvokeTgt));
+      break;
+    case 2: // Get this->klass_->vtable [usr kInvokeTgt, set kInvokeTgt]
+      cg->LoadWordDisp(cu, cg->TargetReg(kInvokeTgt), mirror::Class::VTableOffset().Int32Value(),
+                       cg->TargetReg(kInvokeTgt));
+      break;
+    case 3: // Get target method [use kInvokeTgt, set kArg0]
+      cg->LoadWordDisp(cu, cg->TargetReg(kInvokeTgt), (method_idx * 4) +
+                       mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value(),
+                       cg->TargetReg(kArg0));
+      break;
+    case 4: // Get the compiled code address [uses kArg0, sets kInvokeTgt]
+      if (cu->instruction_set != kX86) {
+        cg->LoadWordDisp(cu, cg->TargetReg(kArg0),
+                         mirror::AbstractMethod::GetCodeOffset().Int32Value(),
+                         cg->TargetReg(kInvokeTgt));
+        break;
+      }
+      // Intentional fallthrough for X86
+    default:
+      return -1;
+  }
+  return state + 1;
+}
+
+/*
+ * All invoke-interface calls bounce off of art_quick_invoke_interface_trampoline,
+ * which will locate the target and continue on via a tail call.
+ */
+static int NextInterfaceCallInsn(CompilationUnit* cu, CallInfo* info, int state,
+                                 uint32_t dex_idx, uint32_t unused, uintptr_t unused2,
+                                 uintptr_t direct_method, InvokeType unused4)
+{
+  Codegen* cg = cu->cg.get();
+  if (cu->instruction_set != kThumb2) {
+    // Disable sharpening
+    direct_method = 0;
+  }
+  int trampoline = (cu->instruction_set == kX86) ? 0
+      : ENTRYPOINT_OFFSET(pInvokeInterfaceTrampoline);
+
+  if (direct_method != 0) {
+    switch (state) {
+      case 0:  // Load the trampoline target [sets kInvokeTgt].
+        if (cu->instruction_set != kX86) {
+          cg->LoadWordDisp(cu, cg->TargetReg(kSelf), trampoline, cg->TargetReg(kInvokeTgt));
+        }
+        // Get the interface Method* [sets kArg0]
+        if (direct_method != static_cast<unsigned int>(-1)) {
+          cg->LoadConstant(cu, cg->TargetReg(kArg0), direct_method);
+        } else {
+          LIR* data_target = ScanLiteralPool(cu->method_literal_list, dex_idx, 0);
+          if (data_target == NULL) {
+            data_target = AddWordData(cu, &cu->method_literal_list, dex_idx);
+            data_target->operands[1] = kInterface;
+          }
+          LIR* load_pc_rel = cg->OpPcRelLoad(cu, cg->TargetReg(kArg0), data_target);
+          AppendLIR(cu, load_pc_rel);
+          DCHECK_EQ(cu->instruction_set, kThumb2) << reinterpret_cast<void*>(data_target);
+        }
+        break;
+      default:
+        return -1;
+    }
+  } else {
+    switch (state) {
+      case 0:
+        // Get the current Method* [sets kArg0] - TUNING: remove copy of method if it is promoted.
+        cg->LoadCurrMethodDirect(cu, cg->TargetReg(kArg0));
+        // Load the trampoline target [sets kInvokeTgt].
+        if (cu->instruction_set != kX86) {
+          cg->LoadWordDisp(cu, cg->TargetReg(kSelf), trampoline, cg->TargetReg(kInvokeTgt));
+        }
+        break;
+    case 1:  // Get method->dex_cache_resolved_methods_ [set/use kArg0]
+      cg->LoadWordDisp(cu, cg->TargetReg(kArg0),
+                       mirror::AbstractMethod::DexCacheResolvedMethodsOffset().Int32Value(),
+                       cg->TargetReg(kArg0));
+      break;
+    case 2:  // Grab target method* [set/use kArg0]
+      cg->LoadWordDisp(cu, cg->TargetReg(kArg0),
+                       mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() + dex_idx * 4,
+                       cg->TargetReg(kArg0));
+      break;
+    default:
+      return -1;
+    }
+  }
+  return state + 1;
+}
+
+static int NextInvokeInsnSP(CompilationUnit* cu, CallInfo* info, int trampoline,
+                            int state, uint32_t dex_idx, uint32_t method_idx)
+{
+  Codegen* cg = cu->cg.get();
+  /*
+   * This handles the case in which the base method is not fully
+   * resolved at compile time, we bail to a runtime helper.
+   */
+  if (state == 0) {
+    if (cu->instruction_set != kX86) {
+      // Load trampoline target
+      cg->LoadWordDisp(cu, cg->TargetReg(kSelf), trampoline, cg->TargetReg(kInvokeTgt));
+    }
+    // Load kArg0 with method index
+    cg->LoadConstant(cu, cg->TargetReg(kArg0), dex_idx);
+    return 1;
+  }
+  return -1;
+}
+
+static int NextStaticCallInsnSP(CompilationUnit* cu, CallInfo* info,
+                                int state, uint32_t dex_idx, uint32_t method_idx,
+                                uintptr_t unused, uintptr_t unused2,
+                         InvokeType unused3)
+{
+  int trampoline = ENTRYPOINT_OFFSET(pInvokeStaticTrampolineWithAccessCheck);
+  return NextInvokeInsnSP(cu, info, trampoline, state, dex_idx, 0);
+}
+
+static int NextDirectCallInsnSP(CompilationUnit* cu, CallInfo* info, int state,
+                                uint32_t dex_idx, uint32_t method_idx, uintptr_t unused,
+                                uintptr_t unused2, InvokeType unused3)
+{
+  int trampoline = ENTRYPOINT_OFFSET(pInvokeDirectTrampolineWithAccessCheck);
+  return NextInvokeInsnSP(cu, info, trampoline, state, dex_idx, 0);
+}
+
+static int NextSuperCallInsnSP(CompilationUnit* cu, CallInfo* info, int state,
+                               uint32_t dex_idx, uint32_t method_idx, uintptr_t unused,
+                        uintptr_t unused2, InvokeType unused3)
+{
+  int trampoline = ENTRYPOINT_OFFSET(pInvokeSuperTrampolineWithAccessCheck);
+  return NextInvokeInsnSP(cu, info, trampoline, state, dex_idx, 0);
+}
+
+static int NextVCallInsnSP(CompilationUnit* cu, CallInfo* info, int state,
+                           uint32_t dex_idx, uint32_t method_idx, uintptr_t unused,
+                           uintptr_t unused2, InvokeType unused3)
+{
+  int trampoline = ENTRYPOINT_OFFSET(pInvokeVirtualTrampolineWithAccessCheck);
+  return NextInvokeInsnSP(cu, info, trampoline, state, dex_idx, 0);
+}
+
+static int NextInterfaceCallInsnWithAccessCheck(CompilationUnit* cu,
+                                                CallInfo* info, int state,
+                                         uint32_t dex_idx, uint32_t unused,
+                                         uintptr_t unused2, uintptr_t unused3,
+                                         InvokeType unused4)
+{
+  int trampoline = ENTRYPOINT_OFFSET(pInvokeInterfaceTrampolineWithAccessCheck);
+  return NextInvokeInsnSP(cu, info, trampoline, state, dex_idx, 0);
+}
+
+static int LoadArgRegs(CompilationUnit* cu, CallInfo* info, int call_state,
+                       NextCallInsn next_call_insn, uint32_t dex_idx,
+                       uint32_t method_idx, uintptr_t direct_code,
+                       uintptr_t direct_method, InvokeType type, bool skip_this)
+{
+  Codegen* cg = cu->cg.get();
+  int last_arg_reg = cg->TargetReg(kArg3);
+  int next_reg = cg->TargetReg(kArg1);
+  int next_arg = 0;
+  if (skip_this) {
+    next_reg++;
+    next_arg++;
+  }
+  for (; (next_reg <= last_arg_reg) && (next_arg < info->num_arg_words); next_reg++) {
+    RegLocation rl_arg = info->args[next_arg++];
+    rl_arg = UpdateRawLoc(cu, rl_arg);
+    if (rl_arg.wide && (next_reg <= cg->TargetReg(kArg2))) {
+      cg->LoadValueDirectWideFixed(cu, rl_arg, next_reg, next_reg + 1);
+      next_reg++;
+      next_arg++;
+    } else {
+      if (rl_arg.wide) {
+        rl_arg.wide = false;
+        rl_arg.is_const = false;
+      }
+      cg->LoadValueDirectFixed(cu, rl_arg, next_reg);
+    }
+    call_state = next_call_insn(cu, info, call_state, dex_idx, method_idx,
+                 direct_code, direct_method, type);
+  }
+  return call_state;
+}
+
+/*
+ * Load up to 5 arguments, the first three of which will be in
+ * kArg1 .. kArg3.  On entry kArg0 contains the current method pointer,
+ * and as part of the load sequence, it must be replaced with
+ * the target method pointer.  Note, this may also be called
+ * for "range" variants if the number of arguments is 5 or fewer.
+ */
+int Codegen::GenDalvikArgsNoRange(CompilationUnit* cu, CallInfo* info,
+                                  int call_state, LIR** pcrLabel, NextCallInsn next_call_insn,
+                                  uint32_t dex_idx, uint32_t method_idx, uintptr_t direct_code,
+                                  uintptr_t direct_method, InvokeType type, bool skip_this)
+{
+  RegLocation rl_arg;
+
+  /* If no arguments, just return */
+  if (info->num_arg_words == 0)
+    return call_state;
+
+  call_state = next_call_insn(cu, info, call_state, dex_idx, method_idx,
+                           direct_code, direct_method, type);
+
+  DCHECK_LE(info->num_arg_words, 5);
+  if (info->num_arg_words > 3) {
+    int32_t next_use = 3;
+    //Detect special case of wide arg spanning arg3/arg4
+    RegLocation rl_use0 = info->args[0];
+    RegLocation rl_use1 = info->args[1];
+    RegLocation rl_use2 = info->args[2];
+    if (((!rl_use0.wide && !rl_use1.wide) || rl_use0.wide) &&
+      rl_use2.wide) {
+      int reg = -1;
+      // Wide spans, we need the 2nd half of uses[2].
+      rl_arg = UpdateLocWide(cu, rl_use2);
+      if (rl_arg.location == kLocPhysReg) {
+        reg = rl_arg.high_reg;
+      } else {
+        // kArg2 & rArg3 can safely be used here
+        reg = TargetReg(kArg3);
+        LoadWordDisp(cu, TargetReg(kSp), SRegOffset(cu, rl_arg.s_reg_low) + 4, reg);
+        call_state = next_call_insn(cu, info, call_state, dex_idx,
+                                 method_idx, direct_code, direct_method, type);
+      }
+      StoreBaseDisp(cu, TargetReg(kSp), (next_use + 1) * 4, reg, kWord);
+      StoreBaseDisp(cu, TargetReg(kSp), 16 /* (3+1)*4 */, reg, kWord);
+      call_state = next_call_insn(cu, info, call_state, dex_idx, method_idx,
+                               direct_code, direct_method, type);
+      next_use++;
+    }
+    // Loop through the rest
+    while (next_use < info->num_arg_words) {
+      int low_reg;
+      int high_reg = -1;
+      rl_arg = info->args[next_use];
+      rl_arg = UpdateRawLoc(cu, rl_arg);
+      if (rl_arg.location == kLocPhysReg) {
+        low_reg = rl_arg.low_reg;
+        high_reg = rl_arg.high_reg;
+      } else {
+        low_reg = TargetReg(kArg2);
+        if (rl_arg.wide) {
+          high_reg = TargetReg(kArg3);
+          LoadValueDirectWideFixed(cu, rl_arg, low_reg, high_reg);
+        } else {
+          LoadValueDirectFixed(cu, rl_arg, low_reg);
+        }
+        call_state = next_call_insn(cu, info, call_state, dex_idx,
+                                 method_idx, direct_code, direct_method, type);
+      }
+      int outs_offset = (next_use + 1) * 4;
+      if (rl_arg.wide) {
+        StoreBaseDispWide(cu, TargetReg(kSp), outs_offset, low_reg, high_reg);
+        next_use += 2;
+      } else {
+        StoreWordDisp(cu, TargetReg(kSp), outs_offset, low_reg);
+        next_use++;
+      }
+      call_state = next_call_insn(cu, info, call_state, dex_idx, method_idx,
+                               direct_code, direct_method, type);
+    }
+  }
+
+  call_state = LoadArgRegs(cu, info, call_state, next_call_insn,
+                          dex_idx, method_idx, direct_code, direct_method,
+                          type, skip_this);
+
+  if (pcrLabel) {
+    *pcrLabel = GenNullCheck(cu, info->args[0].s_reg_low, TargetReg(kArg1), info->opt_flags);
+  }
+  return call_state;
+}
+
+/*
+ * May have 0+ arguments (also used for jumbo).  Note that
+ * source virtual registers may be in physical registers, so may
+ * need to be flushed to home location before copying.  This
+ * applies to arg3 and above (see below).
+ *
+ * Two general strategies:
+ *    If < 20 arguments
+ *       Pass args 3-18 using vldm/vstm block copy
+ *       Pass arg0, arg1 & arg2 in kArg1-kArg3
+ *    If 20+ arguments
+ *       Pass args arg19+ using memcpy block copy
+ *       Pass arg0, arg1 & arg2 in kArg1-kArg3
+ *
+ */
+int Codegen::GenDalvikArgsRange(CompilationUnit* cu, CallInfo* info, int call_state,
+                                LIR** pcrLabel, NextCallInsn next_call_insn, uint32_t dex_idx,
+                                uint32_t method_idx, uintptr_t direct_code, uintptr_t direct_method,
+                                InvokeType type, bool skip_this)
+{
+
+  // If we can treat it as non-range (Jumbo ops will use range form)
+  if (info->num_arg_words <= 5)
+    return GenDalvikArgsNoRange(cu, info, call_state, pcrLabel,
+                                next_call_insn, dex_idx, method_idx,
+                                direct_code, direct_method, type, skip_this);
+  /*
+   * First load the non-register arguments.  Both forms expect all
+   * of the source arguments to be in their home frame location, so
+   * scan the s_reg names and flush any that have been promoted to
+   * frame backing storage.
+   */
+  // Scan the rest of the args - if in phys_reg flush to memory
+  for (int next_arg = 0; next_arg < info->num_arg_words;) {
+    RegLocation loc = info->args[next_arg];
+    if (loc.wide) {
+      loc = UpdateLocWide(cu, loc);
+      if ((next_arg >= 2) && (loc.location == kLocPhysReg)) {
+        StoreBaseDispWide(cu, TargetReg(kSp), SRegOffset(cu, loc.s_reg_low),
+                          loc.low_reg, loc.high_reg);
+      }
+      next_arg += 2;
+    } else {
+      loc = UpdateLoc(cu, loc);
+      if ((next_arg >= 3) && (loc.location == kLocPhysReg)) {
+        StoreBaseDisp(cu, TargetReg(kSp), SRegOffset(cu, loc.s_reg_low),
+                      loc.low_reg, kWord);
+      }
+      next_arg++;
+    }
+  }
+
+  int start_offset = SRegOffset(cu, info->args[3].s_reg_low);
+  int outs_offset = 4 /* Method* */ + (3 * 4);
+  if (cu->instruction_set != kThumb2) {
+    // Generate memcpy
+    OpRegRegImm(cu, kOpAdd, TargetReg(kArg0), TargetReg(kSp), outs_offset);
+    OpRegRegImm(cu, kOpAdd, TargetReg(kArg1), TargetReg(kSp), start_offset);
+    CallRuntimeHelperRegRegImm(cu, ENTRYPOINT_OFFSET(pMemcpy), TargetReg(kArg0),
+                               TargetReg(kArg1), (info->num_arg_words - 3) * 4, false);
+  } else {
+    if (info->num_arg_words >= 20) {
+      // Generate memcpy
+      OpRegRegImm(cu, kOpAdd, TargetReg(kArg0), TargetReg(kSp), outs_offset);
+      OpRegRegImm(cu, kOpAdd, TargetReg(kArg1), TargetReg(kSp), start_offset);
+      CallRuntimeHelperRegRegImm(cu, ENTRYPOINT_OFFSET(pMemcpy), TargetReg(kArg0),
+                                 TargetReg(kArg1), (info->num_arg_words - 3) * 4, false);
+    } else {
+      // Use vldm/vstm pair using kArg3 as a temp
+      int regs_left = std::min(info->num_arg_words - 3, 16);
+      call_state = next_call_insn(cu, info, call_state, dex_idx, method_idx,
+                               direct_code, direct_method, type);
+      OpRegRegImm(cu, kOpAdd, TargetReg(kArg3), TargetReg(kSp), start_offset);
+      LIR* ld = OpVldm(cu, TargetReg(kArg3), regs_left);
+      //TUNING: loosen barrier
+      ld->def_mask = ENCODE_ALL;
+      SetMemRefType(cu, ld, true /* is_load */, kDalvikReg);
+      call_state = next_call_insn(cu, info, call_state, dex_idx, method_idx,
+                               direct_code, direct_method, type);
+      OpRegRegImm(cu, kOpAdd, TargetReg(kArg3), TargetReg(kSp), 4 /* Method* */ + (3 * 4));
+      call_state = next_call_insn(cu, info, call_state, dex_idx, method_idx,
+                               direct_code, direct_method, type);
+      LIR* st = OpVstm(cu, TargetReg(kArg3), regs_left);
+      SetMemRefType(cu, st, false /* is_load */, kDalvikReg);
+      st->def_mask = ENCODE_ALL;
+      call_state = next_call_insn(cu, info, call_state, dex_idx, method_idx,
+                               direct_code, direct_method, type);
+    }
+  }
+
+  call_state = LoadArgRegs(cu, info, call_state, next_call_insn,
+                          dex_idx, method_idx, direct_code, direct_method,
+                          type, skip_this);
+
+  call_state = next_call_insn(cu, info, call_state, dex_idx, method_idx,
+                           direct_code, direct_method, type);
+  if (pcrLabel) {
+    *pcrLabel = GenNullCheck(cu, info->args[0].s_reg_low, TargetReg(kArg1),
+                             info->opt_flags);
+  }
+  return call_state;
+}
+
+RegLocation Codegen::InlineTarget(CompilationUnit* cu, CallInfo* info)
+{
+  RegLocation res;
+  if (info->result.location == kLocInvalid) {
+    res = GetReturn(cu, false);
+  } else {
+    res = info->result;
+  }
+  return res;
+}
+
+RegLocation Codegen::InlineTargetWide(CompilationUnit* cu, CallInfo* info)
+{
+  RegLocation res;
+  if (info->result.location == kLocInvalid) {
+    res = GetReturnWide(cu, false);
+  } else {
+    res = info->result;
+  }
+  return res;
+}
+
+bool Codegen::GenInlinedCharAt(CompilationUnit* cu, CallInfo* info)
+{
+  if (cu->instruction_set == kMips) {
+    // TODO - add Mips implementation
+    return false;
+  }
+  // Location of reference to data array
+  int value_offset = mirror::String::ValueOffset().Int32Value();
+  // Location of count
+  int count_offset = mirror::String::CountOffset().Int32Value();
+  // Starting offset within data array
+  int offset_offset = mirror::String::OffsetOffset().Int32Value();
+  // Start of char data with array_
+  int data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Int32Value();
+
+  RegLocation rl_obj = info->args[0];
+  RegLocation rl_idx = info->args[1];
+  rl_obj = LoadValue(cu, rl_obj, kCoreReg);
+  rl_idx = LoadValue(cu, rl_idx, kCoreReg);
+  int reg_max;
+  GenNullCheck(cu, rl_obj.s_reg_low, rl_obj.low_reg, info->opt_flags);
+  bool range_check = (!(info->opt_flags & MIR_IGNORE_RANGE_CHECK));
+  LIR* launch_pad = NULL;
+  int reg_off = INVALID_REG;
+  int reg_ptr = INVALID_REG;
+  if (cu->instruction_set != kX86) {
+    reg_off = AllocTemp(cu);
+    reg_ptr = AllocTemp(cu);
+    if (range_check) {
+      reg_max = AllocTemp(cu);
+      LoadWordDisp(cu, rl_obj.low_reg, count_offset, reg_max);
+    }
+    LoadWordDisp(cu, rl_obj.low_reg, offset_offset, reg_off);
+    LoadWordDisp(cu, rl_obj.low_reg, value_offset, reg_ptr);
+    if (range_check) {
+      // Set up a launch pad to allow retry in case of bounds violation */
+      launch_pad = RawLIR(cu, 0, kPseudoIntrinsicRetry, reinterpret_cast<uintptr_t>(info));
+      InsertGrowableList(cu, &cu->intrinsic_launchpads,
+                            reinterpret_cast<uintptr_t>(launch_pad));
+      OpRegReg(cu, kOpCmp, rl_idx.low_reg, reg_max);
+      FreeTemp(cu, reg_max);
+      OpCondBranch(cu, kCondCs, launch_pad);
+   }
+  } else {
+    if (range_check) {
+      reg_max = AllocTemp(cu);
+      LoadWordDisp(cu, rl_obj.low_reg, count_offset, reg_max);
+      // Set up a launch pad to allow retry in case of bounds violation */
+      launch_pad = RawLIR(cu, 0, kPseudoIntrinsicRetry, reinterpret_cast<uintptr_t>(info));
+      InsertGrowableList(cu, &cu->intrinsic_launchpads,
+                            reinterpret_cast<uintptr_t>(launch_pad));
+      OpRegReg(cu, kOpCmp, rl_idx.low_reg, reg_max);
+      FreeTemp(cu, reg_max);
+      OpCondBranch(cu, kCondCc, launch_pad);
+    }
+    reg_off = AllocTemp(cu);
+    reg_ptr = AllocTemp(cu);
+    LoadWordDisp(cu, rl_obj.low_reg, offset_offset, reg_off);
+    LoadWordDisp(cu, rl_obj.low_reg, value_offset, reg_ptr);
+  }
+  OpRegImm(cu, kOpAdd, reg_ptr, data_offset);
+  OpRegReg(cu, kOpAdd, reg_off, rl_idx.low_reg);
+  FreeTemp(cu, rl_obj.low_reg);
+  FreeTemp(cu, rl_idx.low_reg);
+  RegLocation rl_dest = InlineTarget(cu, info);
+  RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
+  LoadBaseIndexed(cu, reg_ptr, reg_off, rl_result.low_reg, 1, kUnsignedHalf);
+  FreeTemp(cu, reg_off);
+  FreeTemp(cu, reg_ptr);
+  StoreValue(cu, rl_dest, rl_result);
+  if (range_check) {
+    launch_pad->operands[2] = 0;  // no resumption
+  }
+  // Record that we've already inlined & null checked
+  info->opt_flags |= (MIR_INLINED | MIR_IGNORE_NULL_CHECK);
+  return true;
+}
+
+// Generates an inlined String.is_empty or String.length.
+bool Codegen::GenInlinedStringIsEmptyOrLength(CompilationUnit* cu, CallInfo* info, bool is_empty)
+{
+  if (cu->instruction_set == kMips) {
+    // TODO - add Mips implementation
+    return false;
+  }
+  // dst = src.length();
+  RegLocation rl_obj = info->args[0];
+  rl_obj = LoadValue(cu, rl_obj, kCoreReg);
+  RegLocation rl_dest = InlineTarget(cu, info);
+  RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
+  GenNullCheck(cu, rl_obj.s_reg_low, rl_obj.low_reg, info->opt_flags);
+  LoadWordDisp(cu, rl_obj.low_reg, mirror::String::CountOffset().Int32Value(),
+               rl_result.low_reg);
+  if (is_empty) {
+    // dst = (dst == 0);
+    if (cu->instruction_set == kThumb2) {
+      int t_reg = AllocTemp(cu);
+      OpRegReg(cu, kOpNeg, t_reg, rl_result.low_reg);
+      OpRegRegReg(cu, kOpAdc, rl_result.low_reg, rl_result.low_reg, t_reg);
+    } else {
+      DCHECK_EQ(cu->instruction_set, kX86);
+      OpRegImm(cu, kOpSub, rl_result.low_reg, 1);
+      OpRegImm(cu, kOpLsr, rl_result.low_reg, 31);
+    }
+  }
+  StoreValue(cu, rl_dest, rl_result);
+  return true;
+}
+
+bool Codegen::GenInlinedAbsInt(CompilationUnit *cu, CallInfo* info)
+{
+  if (cu->instruction_set == kMips) {
+    // TODO - add Mips implementation
+    return false;
+  }
+  RegLocation rl_src = info->args[0];
+  rl_src = LoadValue(cu, rl_src, kCoreReg);
+  RegLocation rl_dest = InlineTarget(cu, info);
+  RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
+  int sign_reg = AllocTemp(cu);
+  // abs(x) = y<=x>>31, (x+y)^y.
+  OpRegRegImm(cu, kOpAsr, sign_reg, rl_src.low_reg, 31);
+  OpRegRegReg(cu, kOpAdd, rl_result.low_reg, rl_src.low_reg, sign_reg);
+  OpRegReg(cu, kOpXor, rl_result.low_reg, sign_reg);
+  StoreValue(cu, rl_dest, rl_result);
+  return true;
+}
+
+bool Codegen::GenInlinedAbsLong(CompilationUnit *cu, CallInfo* info)
+{
+  if (cu->instruction_set == kMips) {
+    // TODO - add Mips implementation
+    return false;
+  }
+  if (cu->instruction_set == kThumb2) {
+    RegLocation rl_src = info->args[0];
+    rl_src = LoadValueWide(cu, rl_src, kCoreReg);
+    RegLocation rl_dest = InlineTargetWide(cu, info);
+    RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
+    int sign_reg = AllocTemp(cu);
+    // abs(x) = y<=x>>31, (x+y)^y.
+    OpRegRegImm(cu, kOpAsr, sign_reg, rl_src.high_reg, 31);
+    OpRegRegReg(cu, kOpAdd, rl_result.low_reg, rl_src.low_reg, sign_reg);
+    OpRegRegReg(cu, kOpAdc, rl_result.high_reg, rl_src.high_reg, sign_reg);
+    OpRegReg(cu, kOpXor, rl_result.low_reg, sign_reg);
+    OpRegReg(cu, kOpXor, rl_result.high_reg, sign_reg);
+    StoreValueWide(cu, rl_dest, rl_result);
+    return true;
+  } else {
+    DCHECK_EQ(cu->instruction_set, kX86);
+    // Reuse source registers to avoid running out of temps
+    RegLocation rl_src = info->args[0];
+    rl_src = LoadValueWide(cu, rl_src, kCoreReg);
+    RegLocation rl_dest = InlineTargetWide(cu, info);
+    RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
+    OpRegCopyWide(cu, rl_result.low_reg, rl_result.high_reg, rl_src.low_reg, rl_src.high_reg);
+    FreeTemp(cu, rl_src.low_reg);
+    FreeTemp(cu, rl_src.high_reg);
+    int sign_reg = AllocTemp(cu);
+    // abs(x) = y<=x>>31, (x+y)^y.
+    OpRegRegImm(cu, kOpAsr, sign_reg, rl_result.high_reg, 31);
+    OpRegReg(cu, kOpAdd, rl_result.low_reg, sign_reg);
+    OpRegReg(cu, kOpAdc, rl_result.high_reg, sign_reg);
+    OpRegReg(cu, kOpXor, rl_result.low_reg, sign_reg);
+    OpRegReg(cu, kOpXor, rl_result.high_reg, sign_reg);
+    StoreValueWide(cu, rl_dest, rl_result);
+    return true;
+  }
+}
+
+bool Codegen::GenInlinedFloatCvt(CompilationUnit *cu, CallInfo* info)
+{
+  if (cu->instruction_set == kMips) {
+    // TODO - add Mips implementation
+    return false;
+  }
+  RegLocation rl_src = info->args[0];
+  RegLocation rl_dest = InlineTarget(cu, info);
+  StoreValue(cu, rl_dest, rl_src);
+  return true;
+}
+
+bool Codegen::GenInlinedDoubleCvt(CompilationUnit *cu, CallInfo* info)
+{
+  if (cu->instruction_set == kMips) {
+    // TODO - add Mips implementation
+    return false;
+  }
+  RegLocation rl_src = info->args[0];
+  RegLocation rl_dest = InlineTargetWide(cu, info);
+  StoreValueWide(cu, rl_dest, rl_src);
+  return true;
+}
+
+/*
+ * Fast string.index_of(I) & (II).  Tests for simple case of char <= 0xffff,
+ * otherwise bails to standard library code.
+ */
+bool Codegen::GenInlinedIndexOf(CompilationUnit* cu, CallInfo* info, bool zero_based)
+{
+  if (cu->instruction_set == kMips) {
+    // TODO - add Mips implementation
+    return false;
+  }
+  ClobberCalleeSave(cu);
+  LockCallTemps(cu);  // Using fixed registers
+  int reg_ptr = TargetReg(kArg0);
+  int reg_char = TargetReg(kArg1);
+  int reg_start = TargetReg(kArg2);
+
+  RegLocation rl_obj = info->args[0];
+  RegLocation rl_char = info->args[1];
+  RegLocation rl_start = info->args[2];
+  LoadValueDirectFixed(cu, rl_obj, reg_ptr);
+  LoadValueDirectFixed(cu, rl_char, reg_char);
+  if (zero_based) {
+    LoadConstant(cu, reg_start, 0);
+  } else {
+    LoadValueDirectFixed(cu, rl_start, reg_start);
+  }
+  int r_tgt = (cu->instruction_set != kX86) ? LoadHelper(cu, ENTRYPOINT_OFFSET(pIndexOf)) : 0;
+  GenNullCheck(cu, rl_obj.s_reg_low, reg_ptr, info->opt_flags);
+  LIR* launch_pad = RawLIR(cu, 0, kPseudoIntrinsicRetry, reinterpret_cast<uintptr_t>(info));
+  InsertGrowableList(cu, &cu->intrinsic_launchpads, reinterpret_cast<uintptr_t>(launch_pad));
+  OpCmpImmBranch(cu, kCondGt, reg_char, 0xFFFF, launch_pad);
+  // NOTE: not a safepoint
+  if (cu->instruction_set != kX86) {
+    OpReg(cu, kOpBlx, r_tgt);
+  } else {
+    OpThreadMem(cu, kOpBlx, ENTRYPOINT_OFFSET(pIndexOf));
+  }
+  LIR* resume_tgt = NewLIR0(cu, kPseudoTargetLabel);
+  launch_pad->operands[2] = reinterpret_cast<uintptr_t>(resume_tgt);
+  // Record that we've already inlined & null checked
+  info->opt_flags |= (MIR_INLINED | MIR_IGNORE_NULL_CHECK);
+  RegLocation rl_return = GetReturn(cu, false);
+  RegLocation rl_dest = InlineTarget(cu, info);
+  StoreValue(cu, rl_dest, rl_return);
+  return true;
+}
+
+/* Fast string.compareTo(Ljava/lang/string;)I. */
+bool Codegen::GenInlinedStringCompareTo(CompilationUnit* cu, CallInfo* info)
+{
+  if (cu->instruction_set == kMips) {
+    // TODO - add Mips implementation
+    return false;
+  }
+  ClobberCalleeSave(cu);
+  LockCallTemps(cu);  // Using fixed registers
+  int reg_this = TargetReg(kArg0);
+  int reg_cmp = TargetReg(kArg1);
+
+  RegLocation rl_this = info->args[0];
+  RegLocation rl_cmp = info->args[1];
+  LoadValueDirectFixed(cu, rl_this, reg_this);
+  LoadValueDirectFixed(cu, rl_cmp, reg_cmp);
+  int r_tgt = (cu->instruction_set != kX86) ?
+      LoadHelper(cu, ENTRYPOINT_OFFSET(pStringCompareTo)) : 0;
+  GenNullCheck(cu, rl_this.s_reg_low, reg_this, info->opt_flags);
+  //TUNING: check if rl_cmp.s_reg_low is already null checked
+  LIR* launch_pad = RawLIR(cu, 0, kPseudoIntrinsicRetry, reinterpret_cast<uintptr_t>(info));
+  InsertGrowableList(cu, &cu->intrinsic_launchpads, reinterpret_cast<uintptr_t>(launch_pad));
+  OpCmpImmBranch(cu, kCondEq, reg_cmp, 0, launch_pad);
+  // NOTE: not a safepoint
+  if (cu->instruction_set != kX86) {
+    OpReg(cu, kOpBlx, r_tgt);
+  } else {
+    OpThreadMem(cu, kOpBlx, ENTRYPOINT_OFFSET(pStringCompareTo));
+  }
+  launch_pad->operands[2] = 0;  // No return possible
+  // Record that we've already inlined & null checked
+  info->opt_flags |= (MIR_INLINED | MIR_IGNORE_NULL_CHECK);
+  RegLocation rl_return = GetReturn(cu, false);
+  RegLocation rl_dest = InlineTarget(cu, info);
+  StoreValue(cu, rl_dest, rl_return);
+  return true;
+}
+
+bool Codegen::GenInlinedCurrentThread(CompilationUnit* cu, CallInfo* info) {
+  RegLocation rl_dest = InlineTarget(cu, info);
+  RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
+  int offset = Thread::PeerOffset().Int32Value();
+  if (cu->instruction_set == kThumb2 || cu->instruction_set == kMips) {
+    LoadWordDisp(cu, TargetReg(kSelf), offset, rl_result.low_reg);
+  } else {
+    CHECK(cu->instruction_set == kX86);
+    ((X86Codegen*)this)->OpRegThreadMem(cu, kOpMov, rl_result.low_reg, offset);
+  }
+  StoreValue(cu, rl_dest, rl_result);
+  return true;
+}
+
+bool Codegen::GenInlinedUnsafeGet(CompilationUnit* cu, CallInfo* info,
+                                  bool is_long, bool is_volatile) {
+  if (cu->instruction_set == kMips) {
+    // TODO - add Mips implementation
+    return false;
+  }
+  // Unused - RegLocation rl_src_unsafe = info->args[0];
+  RegLocation rl_src_obj = info->args[1];  // Object
+  RegLocation rl_src_offset = info->args[2];  // long low
+  rl_src_offset.wide = 0;  // ignore high half in info->args[3]
+  RegLocation rl_dest = InlineTarget(cu, info);  // result reg
+  if (is_volatile) {
+    GenMemBarrier(cu, kLoadLoad);
+  }
+  RegLocation rl_object = LoadValue(cu, rl_src_obj, kCoreReg);
+  RegLocation rl_offset = LoadValue(cu, rl_src_offset, kCoreReg);
+  RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
+  if (is_long) {
+    OpRegReg(cu, kOpAdd, rl_object.low_reg, rl_offset.low_reg);
+    LoadBaseDispWide(cu, rl_object.low_reg, 0, rl_result.low_reg, rl_result.high_reg, INVALID_SREG);
+    StoreValueWide(cu, rl_dest, rl_result);
+  } else {
+    LoadBaseIndexed(cu, rl_object.low_reg, rl_offset.low_reg, rl_result.low_reg, 0, kWord);
+    StoreValue(cu, rl_dest, rl_result);
+  }
+  return true;
+}
+
+bool Codegen::GenInlinedUnsafePut(CompilationUnit* cu, CallInfo* info, bool is_long,
+                                  bool is_object, bool is_volatile, bool is_ordered) {
+  if (cu->instruction_set == kMips) {
+    // TODO - add Mips implementation
+    return false;
+  }
+  // Unused - RegLocation rl_src_unsafe = info->args[0];
+  RegLocation rl_src_obj = info->args[1];  // Object
+  RegLocation rl_src_offset = info->args[2];  // long low
+  rl_src_offset.wide = 0;  // ignore high half in info->args[3]
+  RegLocation rl_src_value = info->args[4];  // value to store
+  if (is_volatile || is_ordered) {
+    GenMemBarrier(cu, kStoreStore);
+  }
+  RegLocation rl_object = LoadValue(cu, rl_src_obj, kCoreReg);
+  RegLocation rl_offset = LoadValue(cu, rl_src_offset, kCoreReg);
+  RegLocation rl_value = LoadValue(cu, rl_src_value, kCoreReg);
+  if (is_long) {
+    OpRegReg(cu, kOpAdd, rl_object.low_reg, rl_offset.low_reg);
+    StoreBaseDispWide(cu, rl_object.low_reg, 0, rl_value.low_reg, rl_value.high_reg);
+  } else {
+    StoreBaseIndexed(cu, rl_object.low_reg, rl_offset.low_reg, rl_value.low_reg, 0, kWord);
+  }
+  if (is_volatile) {
+    GenMemBarrier(cu, kStoreLoad);
+  }
+  if (is_object) {
+    MarkGCCard(cu, rl_value.low_reg, rl_object.low_reg);
+  }
+  return true;
+}
+
+bool Codegen::GenIntrinsic(CompilationUnit* cu, CallInfo* info)
+{
+  if (info->opt_flags & MIR_INLINED) {
+    return false;
+  }
+  /*
+   * TODO: move these to a target-specific structured constant array
+   * and use a generic match function.  The list of intrinsics may be
+   * slightly different depending on target.
+   * TODO: Fold this into a matching function that runs during
+   * basic block building.  This should be part of the action for
+   * small method inlining and recognition of the special object init
+   * method.  By doing this during basic block construction, we can also
+   * take advantage of/generate new useful dataflow info.
+   */
+  std::string tgt_method(PrettyMethod(info->index, *cu->dex_file));
+  if (tgt_method.find(" java.lang") != std::string::npos) {
+    if (tgt_method == "long java.lang.Double.doubleToRawLongBits(double)") {
+      return GenInlinedDoubleCvt(cu, info);
+    }
+    if (tgt_method == "double java.lang.Double.longBitsToDouble(long)") {
+      return GenInlinedDoubleCvt(cu, info);
+    }
+    if (tgt_method == "int java.lang.Float.float_to_raw_int_bits(float)") {
+      return GenInlinedFloatCvt(cu, info);
+    }
+    if (tgt_method == "float java.lang.Float.intBitsToFloat(int)") {
+      return GenInlinedFloatCvt(cu, info);
+    }
+    if (tgt_method == "int java.lang.Math.abs(int)" ||
+        tgt_method == "int java.lang.StrictMath.abs(int)") {
+      return GenInlinedAbsInt(cu, info);
+    }
+    if (tgt_method == "long java.lang.Math.abs(long)" ||
+        tgt_method == "long java.lang.StrictMath.abs(long)") {
+      return GenInlinedAbsLong(cu, info);
+    }
+    if (tgt_method == "int java.lang.Math.max(int, int)" ||
+        tgt_method == "int java.lang.StrictMath.max(int, int)") {
+      return GenInlinedMinMaxInt(cu, info, false /* is_min */);
+    }
+    if (tgt_method == "int java.lang.Math.min(int, int)" ||
+        tgt_method == "int java.lang.StrictMath.min(int, int)") {
+      return GenInlinedMinMaxInt(cu, info, true /* is_min */);
+    }
+    if (tgt_method == "double java.lang.Math.sqrt(double)" ||
+        tgt_method == "double java.lang.StrictMath.sqrt(double)") {
+      return GenInlinedSqrt(cu, info);
+    }
+    if (tgt_method == "char java.lang.String.charAt(int)") {
+      return GenInlinedCharAt(cu, info);
+    }
+    if (tgt_method == "int java.lang.String.compareTo(java.lang.String)") {
+      return GenInlinedStringCompareTo(cu, info);
+    }
+    if (tgt_method == "boolean java.lang.String.is_empty()") {
+      return GenInlinedStringIsEmptyOrLength(cu, info, true /* is_empty */);
+    }
+    if (tgt_method == "int java.lang.String.index_of(int, int)") {
+      return GenInlinedIndexOf(cu, info, false /* base 0 */);
+    }
+    if (tgt_method == "int java.lang.String.index_of(int)") {
+      return GenInlinedIndexOf(cu, info, true /* base 0 */);
+    }
+    if (tgt_method == "int java.lang.String.length()") {
+      return GenInlinedStringIsEmptyOrLength(cu, info, false /* is_empty */);
+    }
+    if (tgt_method == "java.lang.Thread java.lang.Thread.currentThread()") {
+      return GenInlinedCurrentThread(cu, info);
+    }
+  } else if (tgt_method.find(" sun.misc.Unsafe") != std::string::npos) {
+    if (tgt_method == "boolean sun.misc.Unsafe.compareAndSwapInt(java.lang.Object, long, int, int)") {
+      return GenInlinedCas32(cu, info, false);
+    }
+    if (tgt_method == "boolean sun.misc.Unsafe.compareAndSwapObject(java.lang.Object, long, java.lang.Object, java.lang.Object)") {
+      return GenInlinedCas32(cu, info, true);
+    }
+    if (tgt_method == "int sun.misc.Unsafe.getInt(java.lang.Object, long)") {
+      return GenInlinedUnsafeGet(cu, info, false /* is_long */, false /* is_volatile */);
+    }
+    if (tgt_method == "int sun.misc.Unsafe.getIntVolatile(java.lang.Object, long)") {
+      return GenInlinedUnsafeGet(cu, info, false /* is_long */, true /* is_volatile */);
+    }
+    if (tgt_method == "void sun.misc.Unsafe.putInt(java.lang.Object, long, int)") {
+      return GenInlinedUnsafePut(cu, info, false /* is_long */, false /* is_object */,
+                                 false /* is_volatile */, false /* is_ordered */);
+    }
+    if (tgt_method == "void sun.misc.Unsafe.putIntVolatile(java.lang.Object, long, int)") {
+      return GenInlinedUnsafePut(cu, info, false /* is_long */, false /* is_object */,
+                                 true /* is_volatile */, false /* is_ordered */);
+    }
+    if (tgt_method == "void sun.misc.Unsafe.putOrderedInt(java.lang.Object, long, int)") {
+      return GenInlinedUnsafePut(cu, info, false /* is_long */, false /* is_object */,
+                                 false /* is_volatile */, true /* is_ordered */);
+    }
+    if (tgt_method == "long sun.misc.Unsafe.getLong(java.lang.Object, long)") {
+      return GenInlinedUnsafeGet(cu, info, true /* is_long */, false /* is_volatile */);
+    }
+    if (tgt_method == "long sun.misc.Unsafe.getLongVolatile(java.lang.Object, long)") {
+      return GenInlinedUnsafeGet(cu, info, true /* is_long */, true /* is_volatile */);
+    }
+    if (tgt_method == "void sun.misc.Unsafe.putLong(java.lang.Object, long, long)") {
+      return GenInlinedUnsafePut(cu, info, true /* is_long */, false /* is_object */,
+                                 false /* is_volatile */, false /* is_ordered */);
+    }
+    if (tgt_method == "void sun.misc.Unsafe.putLongVolatile(java.lang.Object, long, long)") {
+      return GenInlinedUnsafePut(cu, info, true /* is_long */, false /* is_object */,
+                                 true /* is_volatile */, false /* is_ordered */);
+    }
+    if (tgt_method == "void sun.misc.Unsafe.putOrderedLong(java.lang.Object, long, long)") {
+      return GenInlinedUnsafePut(cu, info, true /* is_long */, false /* is_object */,
+                                 false /* is_volatile */, true /* is_ordered */);
+    }
+    if (tgt_method == "java.lang.Object sun.misc.Unsafe.getObject(java.lang.Object, long)") {
+      return GenInlinedUnsafeGet(cu, info, false /* is_long */, false /* is_volatile */);
+    }
+    if (tgt_method == "java.lang.Object sun.misc.Unsafe.getObjectVolatile(java.lang.Object, long)") {
+      return GenInlinedUnsafeGet(cu, info, false /* is_long */, true /* is_volatile */);
+    }
+    if (tgt_method == "void sun.misc.Unsafe.putObject(java.lang.Object, long, java.lang.Object)") {
+      return GenInlinedUnsafePut(cu, info, false /* is_long */, true /* is_object */,
+                                 false /* is_volatile */, false /* is_ordered */);
+    }
+    if (tgt_method == "void sun.misc.Unsafe.putObjectVolatile(java.lang.Object, long, java.lang.Object)") {
+      return GenInlinedUnsafePut(cu, info, false /* is_long */, true /* is_object */,
+                                 true /* is_volatile */, false /* is_ordered */);
+    }
+    if (tgt_method == "void sun.misc.Unsafe.putOrderedObject(java.lang.Object, long, java.lang.Object)") {
+      return GenInlinedUnsafePut(cu, info, false /* is_long */, true /* is_object */,
+                                 false /* is_volatile */, true /* is_ordered */);
+    }
+  }
+  return false;
+}
+
+void Codegen::GenInvoke(CompilationUnit* cu, CallInfo* info)
+{
+  if (GenIntrinsic(cu, info)) {
+    return;
+  }
+  InvokeType original_type = info->type;  // avoiding mutation by ComputeInvokeInfo
+  int call_state = 0;
+  LIR* null_ck;
+  LIR** p_null_ck = NULL;
+  NextCallInsn next_call_insn;
+  FlushAllRegs(cu);  /* Everything to home location */
+  // Explicit register usage
+  LockCallTemps(cu);
+
+  OatCompilationUnit m_unit(cu->class_loader, cu->class_linker,
+                            *cu->dex_file, cu->code_item,
+                            cu->class_def_idx, cu->method_idx,
+                            cu->access_flags);
+
+  uint32_t dex_method_idx = info->index;
+  int vtable_idx;
+  uintptr_t direct_code;
+  uintptr_t direct_method;
+  bool skip_this;
+  bool fast_path =
+    cu->compiler->ComputeInvokeInfo(dex_method_idx, &m_unit, info->type,
+                                       vtable_idx, direct_code,
+                                       direct_method)
+    && !SLOW_INVOKE_PATH;
+  if (info->type == kInterface) {
+    if (fast_path) {
+      p_null_ck = &null_ck;
+    }
+    next_call_insn = fast_path ? NextInterfaceCallInsn
+                            : NextInterfaceCallInsnWithAccessCheck;
+    skip_this = false;
+  } else if (info->type == kDirect) {
+    if (fast_path) {
+      p_null_ck = &null_ck;
+    }
+    next_call_insn = fast_path ? NextSDCallInsn : NextDirectCallInsnSP;
+    skip_this = false;
+  } else if (info->type == kStatic) {
+    next_call_insn = fast_path ? NextSDCallInsn : NextStaticCallInsnSP;
+    skip_this = false;
+  } else if (info->type == kSuper) {
+    DCHECK(!fast_path);  // Fast path is a direct call.
+    next_call_insn = NextSuperCallInsnSP;
+    skip_this = false;
+  } else {
+    DCHECK_EQ(info->type, kVirtual);
+    next_call_insn = fast_path ? NextVCallInsn : NextVCallInsnSP;
+    skip_this = fast_path;
+  }
+  if (!info->is_range) {
+    call_state = GenDalvikArgsNoRange(cu, info, call_state, p_null_ck,
+                                     next_call_insn, dex_method_idx,
+                                     vtable_idx, direct_code, direct_method,
+                                     original_type, skip_this);
+  } else {
+    call_state = GenDalvikArgsRange(cu, info, call_state, p_null_ck,
+                                   next_call_insn, dex_method_idx, vtable_idx,
+                                   direct_code, direct_method, original_type,
+                                   skip_this);
+  }
+  // Finish up any of the call sequence not interleaved in arg loading
+  while (call_state >= 0) {
+    call_state = next_call_insn(cu, info, call_state, dex_method_idx,
+                             vtable_idx, direct_code, direct_method,
+                             original_type);
+  }
+  if (cu->enable_debug & (1 << kDebugDisplayMissingTargets)) {
+    GenShowTarget(cu);
+  }
+  LIR* call_inst;
+  if (cu->instruction_set != kX86) {
+    call_inst = OpReg(cu, kOpBlx, TargetReg(kInvokeTgt));
+  } else {
+    if (fast_path && info->type != kInterface) {
+      call_inst = OpMem(cu, kOpBlx, TargetReg(kArg0),
+                        mirror::AbstractMethod::GetCodeOffset().Int32Value());
+    } else {
+      int trampoline = 0;
+      switch (info->type) {
+      case kInterface:
+        trampoline = fast_path ? ENTRYPOINT_OFFSET(pInvokeInterfaceTrampoline)
+            : ENTRYPOINT_OFFSET(pInvokeInterfaceTrampolineWithAccessCheck);
+        break;
+      case kDirect:
+        trampoline = ENTRYPOINT_OFFSET(pInvokeDirectTrampolineWithAccessCheck);
+        break;
+      case kStatic:
+        trampoline = ENTRYPOINT_OFFSET(pInvokeStaticTrampolineWithAccessCheck);
+        break;
+      case kSuper:
+        trampoline = ENTRYPOINT_OFFSET(pInvokeSuperTrampolineWithAccessCheck);
+        break;
+      case kVirtual:
+        trampoline = ENTRYPOINT_OFFSET(pInvokeVirtualTrampolineWithAccessCheck);
+        break;
+      default:
+        LOG(FATAL) << "Unexpected invoke type";
+      }
+      call_inst = OpThreadMem(cu, kOpBlx, trampoline);
+    }
+  }
+  MarkSafepointPC(cu, call_inst);
+
+  ClobberCalleeSave(cu);
+  if (info->result.location != kLocInvalid) {
+    // We have a following MOVE_RESULT - do it now.
+    if (info->result.wide) {
+      RegLocation ret_loc = GetReturnWide(cu, info->result.fp);
+      StoreValueWide(cu, info->result, ret_loc);
+    } else {
+      RegLocation ret_loc = GetReturn(cu, info->result.fp);
+      StoreValue(cu, info->result, ret_loc);
+    }
+  }
+}
+
+/*
+ * Build an array of location records for the incoming arguments.
+ * Note: one location record per word of arguments, with dummy
+ * high-word loc for wide arguments.  Also pull up any following
+ * MOVE_RESULT and incorporate it into the invoke.
+ */
+CallInfo* Codegen::NewMemCallInfo(CompilationUnit* cu, BasicBlock* bb, MIR* mir, InvokeType type,
+                                  bool is_range)
+{
+  CallInfo* info = static_cast<CallInfo*>(NewMem(cu, sizeof(CallInfo), true, kAllocMisc));
+  MIR* move_result_mir = FindMoveResult(cu, bb, mir);
+  if (move_result_mir == NULL) {
+    info->result.location = kLocInvalid;
+  } else {
+    info->result = GetRawDest(cu, move_result_mir);
+    move_result_mir->meta.original_opcode = move_result_mir->dalvikInsn.opcode;
+    move_result_mir->dalvikInsn.opcode = static_cast<Instruction::Code>(kMirOpNop);
+  }
+  info->num_arg_words = mir->ssa_rep->num_uses;
+  info->args = (info->num_arg_words == 0) ? NULL : static_cast<RegLocation*>
+      (NewMem(cu, sizeof(RegLocation) * info->num_arg_words, false, kAllocMisc));
+  for (int i = 0; i < info->num_arg_words; i++) {
+    info->args[i] = GetRawSrc(cu, mir, i);
+  }
+  info->opt_flags = mir->optimization_flags;
+  info->type = type;
+  info->is_range = is_range;
+  info->index = mir->dalvikInsn.vB;
+  info->offset = mir->offset;
+  return info;
+}
+
+}  // namespace art