Merge "Fix wrong thread id being passed to SIRT roots."
diff --git a/Android.mk b/Android.mk
index 62d40bb..8e43879 100644
--- a/Android.mk
+++ b/Android.mk
@@ -92,6 +92,7 @@
 include $(art_path)/disassembler/Android.mk
 include $(art_path)/oatdump/Android.mk
 include $(art_path)/dalvikvm/Android.mk
+include $(art_path)/tools/Android.mk
 include $(art_build_path)/Android.oat.mk
 
 # ART_HOST_DEPENDENCIES depends on Android.executable.mk above for ART_HOST_EXECUTABLES
@@ -300,6 +301,12 @@
 .PHONY: build-art-target
 build-art-target: $(ART_TARGET_EXECUTABLES) $(ART_TARGET_TEST_EXECUTABLES) $(TARGET_CORE_IMG_OUT) $(TARGET_OUT)/lib/libjavacore.so
 
+.PHONY: art-host
+art-host:   $(HOST_OUT_EXECUTABLES)/art $(HOST_OUT)/bin/dalvikvm $(HOST_OUT)/lib/libart.so $(HOST_OUT)/bin/dex2oat $(HOST_OUT_JAVA_LIBRARIES)/core.art $(HOST_OUT)/lib/libjavacore.so
+
+.PHONY: art-host-debug
+art-host-debug:   art-host $(HOST_OUT)/lib/libartd.so $(HOST_OUT)/bin/dex2oatd
+
 ########################################################################
 # oatdump targets
 
diff --git a/compiler/dex/quick/arm/call_arm.cc b/compiler/dex/quick/arm/call_arm.cc
index fdc609a..a30e80a 100644
--- a/compiler/dex/quick/arm/call_arm.cc
+++ b/compiler/dex/quick/arm/call_arm.cc
@@ -24,70 +24,62 @@
 
 namespace art {
 
+// TODO: generalize & move to RegUtil.cc
+// The number of dalvik registers passed in core registers.
+constexpr int kInArgsInCoreRegs = 3;
+// The core register corresponding to the first (index 0) input argument.
+constexpr int kInArg0CoreReg = r1;  // r0 is Method*.
+// Offset, in words, for getting args from stack (even core reg args have space on stack).
+constexpr int kInArgToStackOffset = 1;
 
-/* Return the position of an ssa name within the argument list */
-int ArmMir2Lir::InPosition(int s_reg) {
-  int v_reg = mir_graph_->SRegToVReg(s_reg);
-  return v_reg - cu_->num_regs;
+/* Lock argument if it's in register. */
+void ArmMir2Lir::LockArg(int in_position, bool wide) {
+  if (in_position < kInArgsInCoreRegs) {
+    LockTemp(kInArg0CoreReg + in_position);
+  }
+  if (wide && in_position + 1 < kInArgsInCoreRegs) {
+    LockTemp(kInArg0CoreReg + in_position + 1);
+  }
 }
 
-/*
- * Describe an argument.  If it's already in an arg register, just leave it
- * there.  NOTE: all live arg registers must be locked prior to this call
- * to avoid having them allocated as a temp by downstream utilities.
- */
-RegLocation ArmMir2Lir::ArgLoc(RegLocation loc) {
-  int arg_num = InPosition(loc.s_reg_low);
-  if (loc.wide) {
-    if (arg_num == 2) {
-      // Bad case - half in register, half in frame.  Just punt
-      loc.location = kLocInvalid;
-    } else if (arg_num < 2) {
-      loc.low_reg = rARM_ARG1 + arg_num;
-      loc.high_reg = loc.low_reg + 1;
-      loc.location = kLocPhysReg;
+/* Load argument into register. LockArg(in_position, wide) must have been previously called. */
+int ArmMir2Lir::LoadArg(int in_position, bool wide) {
+  if (in_position < kInArgsInCoreRegs) {
+    int low_reg = kInArg0CoreReg + in_position;
+    if (!wide) {
+      return low_reg;
+    }
+    int high_reg = (in_position != kInArgsInCoreRegs - 1) ? low_reg + 1 : LoadArg(in_position + 1);
+    return (low_reg & 0xff) | ((high_reg & 0xff) << 8);
+  }
+  int low_reg = AllocTemp();
+  int offset = (in_position + kInArgToStackOffset) * sizeof(uint32_t);
+  if (!wide) {
+    LoadWordDisp(rARM_SP, offset, low_reg);
+    return low_reg;
+  }
+  int high_reg = AllocTemp();
+  LoadBaseDispWide(rARM_SP, offset, low_reg, high_reg, INVALID_SREG);
+  return (low_reg & 0xff) | ((high_reg & 0xff) << 8);
+}
+
+void ArmMir2Lir::LoadArgDirect(int in_position, RegLocation rl_dest) {
+  int reg = kInArg0CoreReg + in_position;
+  int offset = (in_position + kInArgToStackOffset) * sizeof(uint32_t);
+  if (!rl_dest.wide) {
+    if (in_position < kInArgsInCoreRegs) {
+      OpRegCopy(rl_dest.low_reg, reg);
     } else {
-      loc.location = kLocDalvikFrame;
+      LoadWordDisp(rARM_SP, offset, rl_dest.low_reg);
     }
   } else {
-    if (arg_num < 3) {
-      loc.low_reg = rARM_ARG1 + arg_num;
-      loc.location = kLocPhysReg;
+    if (in_position < kInArgsInCoreRegs - 1) {
+      OpRegCopyWide(rl_dest.low_reg, rl_dest.high_reg, reg, reg + 1);
+    } else if (in_position == kInArgsInCoreRegs - 1) {
+      OpRegCopy(rl_dest.low_reg, reg);
+      LoadWordDisp(rARM_SP, offset + sizeof(uint32_t), rl_dest.high_reg);
     } else {
-      loc.location = kLocDalvikFrame;
-    }
-  }
-  return loc;
-}
-
-/*
- * Load an argument.  If already in a register, just return.  If in
- * the frame, we can't use the normal LoadValue() because it assumed
- * a proper frame - and we're frameless.
- */
-RegLocation ArmMir2Lir::LoadArg(RegLocation loc) {
-  if (loc.location == kLocDalvikFrame) {
-    int start = (InPosition(loc.s_reg_low) + 1) * sizeof(uint32_t);
-    loc.low_reg = AllocTemp();
-    LoadWordDisp(rARM_SP, start, loc.low_reg);
-    if (loc.wide) {
-      loc.high_reg = AllocTemp();
-      LoadWordDisp(rARM_SP, start + sizeof(uint32_t), loc.high_reg);
-    }
-    loc.location = kLocPhysReg;
-  }
-  return loc;
-}
-
-/* Lock any referenced arguments that arrive in registers */
-void ArmMir2Lir::LockLiveArgs(MIR* mir) {
-  int first_in = cu_->num_regs;
-  const int num_arg_regs = 3;  // TODO: generalize & move to RegUtil.cc
-  for (int i = 0; i < mir->ssa_rep->num_uses; i++) {
-    int v_reg = mir_graph_->SRegToVReg(mir->ssa_rep->uses[i]);
-    int InPosition = v_reg - first_in;
-    if (InPosition < num_arg_regs) {
-      LockTemp(rARM_ARG1 + InPosition);
+      LoadBaseDispWide(rARM_SP, offset, rl_dest.low_reg, rl_dest.high_reg, INVALID_SREG);
     }
   }
 }
@@ -134,26 +126,22 @@
     return NULL;  // The object is not "this" and has to be null-checked.
   }
 
-  OpSize size = static_cast<OpSize>(data.op_size);
   DCHECK_NE(data.op_size, kDouble);  // The inliner doesn't distinguish kDouble, uses kLong.
-  bool long_or_double = (data.op_size == kLong);
-  bool is_object = data.is_object;
+  bool wide = (data.op_size == kLong);
 
-  // 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);
-  RegLocation rl_dest;
-  if (long_or_double) {
-    rl_dest = GetReturnWide(false);
-  } else {
-    rl_dest = GetReturn(false);
-  }
   // 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);
+  LockArg(data.object_arg);
+  RegLocation rl_dest = wide ? GetReturnWide(false) : GetReturn(false);
+  int reg_obj = LoadArg(data.object_arg);
+  if (wide) {
+    LoadBaseDispWide(reg_obj, data.field_offset, rl_dest.low_reg, rl_dest.high_reg, INVALID_SREG);
+  } else {
+    LoadBaseDisp(reg_obj, data.field_offset, rl_dest.low_reg, kWord, INVALID_SREG);
+  }
+  if (data.is_volatile) {
+    GenMemBarrier(kLoadLoad);
+  }
   return GetNextMir(bb, mir);
 }
 
@@ -164,63 +152,42 @@
     return NULL;  // The object is not "this" and has to be null-checked.
   }
 
-  OpSize size = static_cast<OpSize>(data.op_size);
   DCHECK_NE(data.op_size, kDouble);  // The inliner doesn't distinguish kDouble, uses kLong.
-  bool long_or_double = (data.op_size == kLong);
-  bool is_object = data.is_object;
+  bool wide = (data.op_size == kLong);
 
-  // TODO: Generate the method using only the data in special.
-  RegLocation rl_src;
-  RegLocation rl_obj;
-  LockLiveArgs(mir);
-  if (long_or_double) {
-    rl_src = mir_graph_->GetSrcWide(mir, 0);
-    rl_obj = mir_graph_->GetSrc(mir, 2);
-  } else {
-    rl_src = mir_graph_->GetSrc(mir, 0);
-    rl_obj = mir_graph_->GetSrc(mir, 1);
-  }
-  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) {
-    ResetRegPool();
-    return NULL;
-  }
   // Point of no return - no aborts after this
   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);
+  LockArg(data.object_arg);
+  LockArg(data.src_arg, wide);
+  int reg_obj = LoadArg(data.object_arg);
+  int reg_src = LoadArg(data.src_arg, wide);
+  if (data.is_volatile) {
+    GenMemBarrier(kStoreStore);
+  }
+  if (wide) {
+    StoreBaseDispWide(reg_obj, data.field_offset, reg_src & 0xff, reg_src >> 8);
+  } else {
+    StoreBaseDisp(reg_obj, data.field_offset, reg_src, kWord);
+  }
+  if (data.is_volatile) {
+    GenMemBarrier(kLoadLoad);
+  }
+  if (data.is_object) {
+    MarkGCCard(reg_src, reg_obj);
+  }
   return GetNextMir(bb, mir);
 }
 
-MIR* ArmMir2Lir::SpecialIdentity(MIR* mir) {
-  RegLocation rl_src;
-  RegLocation rl_dest;
-  bool wide = (mir->ssa_rep->num_uses == 2);
-  if (wide) {
-    rl_src = mir_graph_->GetSrcWide(mir, 0);
-    rl_dest = GetReturnWide(false);
-  } else {
-    rl_src = mir_graph_->GetSrc(mir, 0);
-    rl_dest = GetReturn(false);
-  }
-  LockLiveArgs(mir);
-  rl_src = ArmMir2Lir::ArgLoc(rl_src);
-  if (rl_src.location == kLocInvalid) {
-    ResetRegPool();
-    return NULL;
-  }
+MIR* ArmMir2Lir::SpecialIdentity(MIR* mir, const InlineMethod& special) {
+  const InlineReturnArgData& data = special.d.return_data;
+  DCHECK_NE(data.op_size, kDouble);  // The inliner doesn't distinguish kDouble, uses kLong.
+  bool wide = (data.op_size == kLong);
+
   // Point of no return - no aborts after this
   ArmMir2Lir::GenPrintLabel(mir);
-  rl_src = LoadArg(rl_src);
-  if (wide) {
-    StoreValueWide(rl_dest, rl_src);
-  } else {
-    StoreValue(rl_dest, rl_src);
-  }
+  LockArg(data.arg, wide);
+  RegLocation rl_dest = wide ? GetReturnWide(false) : GetReturn(false);
+  LoadArgDirect(data.arg, rl_dest);
   return mir;
 }
 
@@ -249,8 +216,7 @@
       next_mir = SpecialIPut(&bb, mir, special);
       break;
     case kInlineOpReturnArg:
-      // TODO: Generate the method using only the data in special.
-      next_mir = SpecialIdentity(mir);
+      next_mir = SpecialIdentity(mir, special);
       break;
     default:
       return;
diff --git a/compiler/dex/quick/arm/codegen_arm.h b/compiler/dex/quick/arm/codegen_arm.h
index 598da89..7ee241c 100644
--- a/compiler/dex/quick/arm/codegen_arm.h
+++ b/compiler/dex/quick/arm/codegen_arm.h
@@ -167,7 +167,6 @@
     void OpRegCopyWide(int dest_lo, int dest_hi, int src_lo, int src_hi);
     void OpTlsCmp(ThreadOffset offset, int val);
 
-    RegLocation ArgLoc(RegLocation loc);
     LIR* LoadBaseDispBody(int rBase, int displacement, int r_dest, int r_dest_hi, OpSize size,
                           int s_reg);
     LIR* StoreBaseDispBody(int rBase, int displacement, int r_src, int r_src_hi, OpSize size);
@@ -186,13 +185,13 @@
   private:
     void GenFusedLongCmpImmBranch(BasicBlock* bb, RegLocation rl_src1, int64_t val,
                                   ConditionCode ccode);
-    int InPosition(int s_reg);
-    RegLocation LoadArg(RegLocation loc);
-    void LockLiveArgs(MIR* mir);
+    void LockArg(int in_position, bool wide = false);
+    int LoadArg(int in_position, bool wide = false);
+    void LoadArgDirect(int in_position, RegLocation rl_dest);
     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* SpecialIdentity(MIR* mir);
+    MIR* SpecialIdentity(MIR* mir, const InlineMethod& special);
     LIR* LoadFPConstantValue(int r_dest, int value);
     void ReplaceFixup(LIR* prev_lir, LIR* orig_lir, LIR* new_lir);
     void InsertFixupBefore(LIR* prev_lir, LIR* orig_lir, LIR* new_lir);
diff --git a/compiler/dex/quick/arm/int_arm.cc b/compiler/dex/quick/arm/int_arm.cc
index 150794e..43928fc 100644
--- a/compiler/dex/quick/arm/int_arm.cc
+++ b/compiler/dex/quick/arm/int_arm.cc
@@ -357,6 +357,7 @@
     } else {
       // Handle overlap
       if (src_hi == dest_lo) {
+        DCHECK_NE(src_lo, dest_hi);
         OpRegCopy(dest_hi, src_hi);
         OpRegCopy(dest_lo, src_lo);
       } else {
diff --git a/compiler/dex/quick/x86/x86_lir.h b/compiler/dex/quick/x86/x86_lir.h
index c49f627..8c385a1 100644
--- a/compiler/dex/quick/x86/x86_lir.h
+++ b/compiler/dex/quick/x86/x86_lir.h
@@ -22,54 +22,53 @@
 namespace art {
 
 /*
- * Runtime register conventions. We consider both x86, x86-64 and x32 (32bit mode x86-64), although
- * we currently only target x86. The ABI has different conventions and we hope to have a single
- * convention to simplify code generation. Changing something that is callee save and making it
- * caller save places a burden on up-calls to save/restore the callee save register, however, there
- * are few registers that are callee save in the ABI. Changing something that is caller save and
- * making it callee save places a burden on down-calls to save/restore the callee save register.
- * For these reasons we aim to match native conventions for caller and callee save. The first 4
- * registers can be used for byte operations, for this reason they are preferred for temporary
- * scratch registers.
+ * Runtime register conventions. We consider both x86, x86-64 and x32 (32bit mode x86-64). The ABI
+ * has different conventions and we capture those here. Changing something that is callee save and
+ * making it caller save places a burden on up-calls to save/restore the callee save register,
+ * however, there are few registers that are callee save in the ABI. Changing something that is
+ * caller save and making it callee save places a burden on down-calls to save/restore the callee
+ * save register. For these reasons we aim to match native conventions for caller and callee save.
+ * On x86 only the first 4 registers can be used for byte operations, for this reason they are
+ * preferred for temporary scratch registers.
  *
  * General Purpose Register:
- *  Native: x86         | x86-64 / x32      | ART
- *  r0/eax: caller save | caller save       | caller, Method*, scratch, return value
- *  r1/ecx: caller save | caller save, arg4 | caller, arg1, scratch
- *  r2/edx: caller save | caller save, arg3 | caller, arg2, scratch, high half of long return
- *  r3/ebx: callEE save | callEE save       | callER, arg3, scratch
+ *  Native: x86    | x86-64 / x32 | ART x86                                         | ART x86-64
+ *  r0/eax: caller | caller       | caller, Method*, scratch, return value          | caller, scratch, return value
+ *  r1/ecx: caller | caller, arg4 | caller, arg1, scratch                           | caller, arg3, scratch
+ *  r2/edx: caller | caller, arg3 | caller, arg2, scratch, high half of long return | caller, arg2, scratch
+ *  r3/ebx: callEE | callEE       | callER, arg3, scratch                           | callee, promotable
  *  r4/esp: stack pointer
- *  r5/ebp: callee save | callee save       | callee, available for dalvik register promotion
- *  r6/esi: callEE save | callER save, arg2 | callee, available for dalvik register promotion
- *  r7/edi: callEE save | callER save, arg1 | callee, available for dalvik register promotion
+ *  r5/ebp: callee | callee       | callee, promotable                              | callee, promotable
+ *  r6/esi: callEE | callER, arg2 | callee, promotable                              | caller, arg1, scratch
+ *  r7/edi: callEE | callER, arg1 | callee, promotable                              | caller, Method*, scratch
  *  ---  x86-64/x32 registers
  *  Native: x86-64 / x32      | ART
- *  r8:     caller save, arg5 | caller, scratch
- *  r9:     caller save, arg6 | caller, scratch
+ *  r8:     caller save, arg5 | caller, arg4, scratch
+ *  r9:     caller save, arg6 | caller, arg5, scratch
  *  r10:    caller save       | caller, scratch
  *  r11:    caller save       | caller, scratch
- *  r12:    callee save       | callee, available for dalvik register promotion
- *  r13:    callee save       | callee, available for dalvik register promotion
- *  r14:    callee save       | callee, available for dalvik register promotion
- *  r15:    callee save       | callee, available for dalvik register promotion
+ *  r12:    callee save       | callee, available for register promotion (promotable)
+ *  r13:    callee save       | callee, available for register promotion (promotable)
+ *  r14:    callee save       | callee, available for register promotion (promotable)
+ *  r15:    callee save       | callee, available for register promotion (promotable)
  *
  * There is no rSELF, instead on x86 fs: has a base address of Thread::Current, whereas on
  * x86-64/x32 gs: holds it.
  *
  * For floating point we don't support CPUs without SSE2 support (ie newer than PIII):
- *  Native: x86       | x86-64 / x32     | ART
- *  XMM0: caller save |caller save, arg1 | caller, float/double return value (except for native x86 code)
- *  XMM1: caller save |caller save, arg2 | caller, scratch
- *  XMM2: caller save |caller save, arg3 | caller, scratch
- *  XMM3: caller save |caller save, arg4 | caller, scratch
- *  XMM4: caller save |caller save, arg5 | caller, scratch
- *  XMM5: caller save |caller save, arg6 | caller, scratch
- *  XMM6: caller save |caller save, arg7 | caller, scratch
- *  XMM7: caller save |caller save, arg8 | caller, scratch
+ *  Native: x86  | x86-64 / x32 | ART x86                    | ART x86-64
+ *  XMM0: caller | caller, arg1 | caller, float return value | caller, arg1, float return value
+ *  XMM1: caller | caller, arg2 | caller, scratch            | caller, arg2, scratch
+ *  XMM2: caller | caller, arg3 | caller, scratch            | caller, arg3, scratch
+ *  XMM3: caller | caller, arg4 | caller, scratch            | caller, arg4, scratch
+ *  XMM4: caller | caller, arg5 | caller, scratch            | caller, arg5, scratch
+ *  XMM5: caller | caller, arg6 | caller, scratch            | caller, arg6, scratch
+ *  XMM6: caller | caller, arg7 | caller, scratch            | caller, arg7, scratch
+ *  XMM7: caller | caller, arg8 | caller, scratch            | caller, arg8, scratch
  *  ---  x86-64/x32 registers
- *  XMM8 .. 15: caller save
+ *  XMM8 .. 15: caller save available as scratch registers for ART.
  *
- * X87 is a necessary evil outside of ART code:
+ * X87 is a necessary evil outside of ART code for x86:
  *  ST0:  x86 float/double native return value, caller save
  *  ST1 .. ST7: caller save
  *
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 402d4f4..61e9fbb 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -1200,7 +1200,7 @@
     if (no_guarantee_of_dex_cache_entry) {
       // See if the method is also declared in this dex cache.
       uint32_t dex_method_idx = MethodHelper(method).FindDexMethodIndexInOtherDexFile(
-          *target_method->dex_file);
+          *target_method->dex_file, target_method->dex_method_index);
       if (dex_method_idx != DexFile::kDexNoIndex) {
         target_method->dex_method_index = dex_method_idx;
       } else {
diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S
index 0e5c60a..cf3f72e 100644
--- a/runtime/arch/arm/quick_entrypoints_arm.S
+++ b/runtime/arch/arm/quick_entrypoints_arm.S
@@ -274,7 +274,7 @@
      *   r2 = size of argument array in bytes
      *   r3 = (managed) thread pointer
      *   [sp] = JValue* result
-     *   [sp + 4] = result type char
+     *   [sp + 4] = shorty
      */
 ENTRY art_quick_invoke_stub
     push   {r0, r4, r5, r9, r11, lr}       @ spill regs
diff --git a/runtime/arch/mips/quick_entrypoints_mips.S b/runtime/arch/mips/quick_entrypoints_mips.S
index c60bca0..f9a200a 100644
--- a/runtime/arch/mips/quick_entrypoints_mips.S
+++ b/runtime/arch/mips/quick_entrypoints_mips.S
@@ -456,7 +456,7 @@
      *   a2 = size of argument array in bytes
      *   a3 = (managed) thread pointer
      *   [sp + 16] = JValue* result
-     *   [sp + 20] = result type char
+     *   [sp + 20] = shorty
      */
 ENTRY art_quick_invoke_stub
     GENERATE_GLOBAL_POINTER
@@ -502,7 +502,8 @@
     addiu $sp, $sp, 16
     .cfi_adjust_cfa_offset -16
     lw    $t0, 16($sp)          # get result pointer
-    lw    $t1, 20($sp)          # get result type char
+    lw    $t1, 20($sp)          # get shorty
+    lb    $t1, 0($t1)           # get result type char
     li    $t2, 68               # put char 'D' into t2
     beq   $t1, $t2, 1f          # branch if result type char == 'D'
     li    $t3, 70               # put char 'F' into t3
diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S
index 9c3eb30..c76c6b2 100644
--- a/runtime/arch/x86/quick_entrypoints_x86.S
+++ b/runtime/arch/x86/quick_entrypoints_x86.S
@@ -251,7 +251,7 @@
      *   [sp + 12] = size of argument array in bytes
      *   [sp + 16] = (managed) thread pointer
      *   [sp + 20] = JValue* result
-     *   [sp + 24] = result type char
+     *   [sp + 24] = shorty
      */
 DEFINE_FUNCTION art_quick_invoke_stub
     PUSH ebp                      // save ebp
@@ -281,17 +281,20 @@
     POP ebx                       // pop ebx
     POP ebp                       // pop ebp
     mov 20(%esp), %ecx            // get result pointer
-    cmpl LITERAL(68), 24(%esp)    // test if result type char == 'D'
-    je return_double_quick
-    cmpl LITERAL(70), 24(%esp)    // test if result type char == 'F'
-    je return_float_quick
-    mov %eax, (%ecx)              // store the result
+    mov %eax, (%ecx)              // store the result assuming its a long, int or Object*
     mov %edx, 4(%ecx)             // store the other half of the result
+    mov 24(%esp), %edx            // get the shorty
+    cmpb LITERAL(68), (%edx)      // test if result type char == 'D'
+    je return_double_quick
+    cmpb LITERAL(70), (%edx)      // test if result type char == 'F'
+    je return_float_quick
     ret
 return_double_quick:
-return_float_quick:
     movsd %xmm0, (%ecx)           // store the floating point result
     ret
+return_float_quick:
+    movss %xmm0, (%ecx)           // store the floating point result
+    ret
 END_FUNCTION art_quick_invoke_stub
 
 MACRO3(NO_ARG_DOWNCALL, c_name, cxx_name, return_macro)
diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
index e01a31b..44bc7a2 100644
--- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
@@ -149,6 +149,14 @@
 
     /*
      * Quick invocation stub.
+     * On entry:
+     *   [sp] = return address
+     *   rdi = method pointer
+     *   rsi = argument array or NULL for no argument methods
+     *   rdx = size of argument array in bytes
+     *   rcx = (managed) thread pointer
+     *   r8 = JValue* result
+     *   r9 = char* shorty
      */
 DEFINE_FUNCTION art_quick_invoke_stub
     int3
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 5acef70..fac1e14 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -3154,7 +3154,7 @@
     CHECK(can_init_statics);
     if (LIKELY(Runtime::Current()->IsStarted())) {
       JValue result;
-      clinit->Invoke(self, NULL, 0, &result, 'V');
+      clinit->Invoke(self, NULL, 0, &result, "V");
     } else {
       art::interpreter::EnterInterpreterFromInvoke(self, clinit, NULL, NULL, NULL);
     }
diff --git a/runtime/common_test.h b/runtime/common_test.h
index af7e8ae..f7859ea 100644
--- a/runtime/common_test.h
+++ b/runtime/common_test.h
@@ -268,7 +268,7 @@
     MakeExecutable(&code[0], code.size());
   }
 
-  // Create an OatMethod based on pointers (for unit tests)
+  // Create an OatMethod based on pointers (for unit tests).
   OatFile::OatMethod CreateOatMethod(const void* code,
                                      const size_t frame_size_in_bytes,
                                      const uint32_t core_spill_mask,
@@ -276,11 +276,23 @@
                                      const uint8_t* mapping_table,
                                      const uint8_t* vmap_table,
                                      const uint8_t* gc_map) {
-    const byte* base = nullptr;  // Base of data in oat file, ie 0.
-    uint32_t code_offset = PointerToLowMemUInt32(code);
-    uint32_t mapping_table_offset = PointerToLowMemUInt32(mapping_table);
-    uint32_t vmap_table_offset = PointerToLowMemUInt32(vmap_table);
-    uint32_t gc_map_offset = PointerToLowMemUInt32(gc_map);
+    const byte* base;
+    uint32_t code_offset, mapping_table_offset, vmap_table_offset, gc_map_offset;
+    if (mapping_table == nullptr && vmap_table == nullptr && gc_map == nullptr) {
+      base = reinterpret_cast<const byte*>(code);  // Base of data points at code.
+      base -= kPointerSize;  // Move backward so that code_offset != 0.
+      code_offset = kPointerSize;
+      mapping_table_offset = 0;
+      vmap_table_offset = 0;
+      gc_map_offset = 0;
+    } else {
+      // TODO: 64bit support.
+      base = nullptr;  // Base of data in oat file, ie 0.
+      code_offset = PointerToLowMemUInt32(code);
+      mapping_table_offset = PointerToLowMemUInt32(mapping_table);
+      vmap_table_offset = PointerToLowMemUInt32(vmap_table);
+      gc_map_offset = PointerToLowMemUInt32(gc_map);
+    }
     return OatFile::OatMethod(base,
                               code_offset,
                               frame_size_in_bytes,
@@ -470,6 +482,8 @@
       instruction_set = kX86;
 #elif defined(__x86_64__)
       instruction_set = kX86_64;
+      // TODO: x86_64 compilation support.
+      runtime_->SetCompilerFilter(Runtime::kInterpretOnly);
 #endif
 
       for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) {
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 67db2ab..733e843 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -3019,7 +3019,7 @@
   MethodHelper mh(m.get());
   ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
   arg_array.BuildArgArray(soa, pReq->receiver, reinterpret_cast<jvalue*>(pReq->arg_values));
-  InvokeWithArgArray(soa, m.get(), &arg_array, &pReq->result_value, mh.GetShorty()[0]);
+  InvokeWithArgArray(soa, m.get(), &arg_array, &pReq->result_value, mh.GetShorty());
 
   mirror::Throwable* exception = soa.Self()->GetException(NULL);
   soa.Self()->ClearException();
diff --git a/runtime/entrypoints/interpreter/interpreter_entrypoints.cc b/runtime/entrypoints/interpreter/interpreter_entrypoints.cc
index 8a2ce51..2067a45 100644
--- a/runtime/entrypoints/interpreter/interpreter_entrypoints.cc
+++ b/runtime/entrypoints/interpreter/interpreter_entrypoints.cc
@@ -48,11 +48,11 @@
   if (kUsePortableCompiler) {
     ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
     arg_array.BuildArgArrayFromFrame(shadow_frame, arg_offset);
-    method->Invoke(self, arg_array.GetArray(), arg_array.GetNumBytes(), result, mh.GetShorty()[0]);
+    method->Invoke(self, arg_array.GetArray(), arg_array.GetNumBytes(), result, mh.GetShorty());
   } else {
     method->Invoke(self, shadow_frame->GetVRegArgs(arg_offset),
                    (shadow_frame->NumberOfVRegs() - arg_offset) * sizeof(uint32_t),
-                   result, mh.GetShorty()[0]);
+                   result, mh.GetShorty());
   }
 }
 
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 9f30190..f9486c3 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -561,9 +561,11 @@
         caller->GetDexCacheResolvedMethods()->Set(called->GetDexMethodIndex(), called);
       } else {
         // Calling from one dex file to another, need to compute the method index appropriate to
-        // the caller's dex file.
+        // the caller's dex file. Since we get here only if the original called was a runtime
+        // method, we've got the correct dex_file and a dex_method_idx from above.
+        DCHECK(&MethodHelper(caller).GetDexFile() == dex_file);
         uint32_t method_index =
-            MethodHelper(called).FindDexMethodIndexInOtherDexFile(MethodHelper(caller).GetDexFile());
+            MethodHelper(called).FindDexMethodIndexInOtherDexFile(*dex_file, dex_method_idx);
         if (method_index != DexFile::kDexNoIndex) {
           caller->GetDexCacheResolvedMethods()->Set(method_index, called);
         }
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index d98fe37..a324925 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -2319,10 +2319,10 @@
 void Heap::AddFinalizerReference(Thread* self, mirror::Object* object) {
   ScopedObjectAccess soa(self);
   JValue result;
-  ArgArray arg_array(NULL, 0);
+  ArgArray arg_array("VL", 2);
   arg_array.Append(object);
   soa.DecodeMethod(WellKnownClasses::java_lang_ref_FinalizerReference_add)->Invoke(self,
-      arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'V');
+      arg_array.GetArray(), arg_array.GetNumBytes(), &result, "VL");
 }
 
 void Heap::EnqueueClearedReferences() {
@@ -2333,10 +2333,10 @@
     if (LIKELY(Runtime::Current()->IsStarted())) {
       ScopedObjectAccess soa(self);
       JValue result;
-      ArgArray arg_array(NULL, 0);
+      ArgArray arg_array("VL", 2);
       arg_array.Append(cleared_references_.GetList());
       soa.DecodeMethod(WellKnownClasses::java_lang_ref_ReferenceQueue_add)->Invoke(soa.Self(),
-          arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'V');
+          arg_array.GetArray(), arg_array.GetNumBytes(), &result, "VL");
     }
     cleared_references_.Clear();
   }
diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc
index fbaadfb..6f31ca7 100644
--- a/runtime/jni_internal.cc
+++ b/runtime/jni_internal.cc
@@ -139,13 +139,13 @@
 }
 
 void InvokeWithArgArray(const ScopedObjectAccess& soa, ArtMethod* method,
-                        ArgArray* arg_array, JValue* result, char result_type)
+                        ArgArray* arg_array, JValue* result, const char* shorty)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   uint32_t* args = arg_array->GetArray();
   if (UNLIKELY(soa.Env()->check_jni)) {
     CheckMethodArguments(method, args);
   }
-  method->Invoke(soa.Self(), args, arg_array->GetNumBytes(), result, result_type);
+  method->Invoke(soa.Self(), args, arg_array->GetNumBytes(), result, shorty);
 }
 
 static JValue InvokeWithVarArgs(const ScopedObjectAccess& soa, jobject obj,
@@ -157,7 +157,7 @@
   JValue result;
   ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
   arg_array.BuildArgArray(soa, receiver, args);
-  InvokeWithArgArray(soa, method, &arg_array, &result, mh.GetShorty()[0]);
+  InvokeWithArgArray(soa, method, &arg_array, &result, mh.GetShorty());
   return result;
 }
 
@@ -175,7 +175,7 @@
   JValue result;
   ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
   arg_array.BuildArgArray(soa, receiver, args);
-  InvokeWithArgArray(soa, method, &arg_array, &result, mh.GetShorty()[0]);
+  InvokeWithArgArray(soa, method, &arg_array, &result, mh.GetShorty());
   return result;
 }
 
@@ -188,7 +188,7 @@
   JValue result;
   ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
   arg_array.BuildArgArray(soa, receiver, args);
-  InvokeWithArgArray(soa, method, &arg_array, &result, mh.GetShorty()[0]);
+  InvokeWithArgArray(soa, method, &arg_array, &result, mh.GetShorty());
   return result;
 }
 
@@ -637,7 +637,7 @@
   JValue result;
   ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
   arg_array.BuildArgArray(soa, receiver, args);
-  InvokeWithArgArray(soa, method, &arg_array, &result, mh.GetShorty()[0]);
+  InvokeWithArgArray(soa, method, &arg_array, &result, mh.GetShorty());
   return result;
 }
 
@@ -2437,8 +2437,10 @@
         m = c->FindVirtualMethod(name, sig);
       }
       if (m == NULL) {
+        c->DumpClass(LOG(ERROR), mirror::Class::kDumpClassFullDetail);
         LOG(return_errors ? ERROR : FATAL) << "Failed to register native method "
-            << PrettyDescriptor(c) << "." << name << sig;
+            << PrettyDescriptor(c) << "." << name << sig << " in "
+            << c->GetDexCache()->GetLocation()->ToModifiedUtf8();
         ThrowNoSuchMethodError(soa, c, name, sig, "static or non-static");
         return JNI_ERR;
       } else if (!m->IsNative()) {
diff --git a/runtime/jni_internal.h b/runtime/jni_internal.h
index 26905c7..9e10987 100644
--- a/runtime/jni_internal.h
+++ b/runtime/jni_internal.h
@@ -57,7 +57,7 @@
 JValue InvokeWithJValues(const ScopedObjectAccess&, jobject obj, jmethodID mid, jvalue* args)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 void InvokeWithArgArray(const ScopedObjectAccess& soa, mirror::ArtMethod* method,
-                        ArgArray *arg_array, JValue* result, char result_type)
+                        ArgArray *arg_array, JValue* result, const char* shorty)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
 int ThrowNewException(JNIEnv* env, jclass exception_class, const char* msg, jobject cause);
diff --git a/runtime/jni_internal_test.cc b/runtime/jni_internal_test.cc
index fed734e..4c58c84 100644
--- a/runtime/jni_internal_test.cc
+++ b/runtime/jni_internal_test.cc
@@ -134,14 +134,14 @@
       arg_array.Append(receiver);
     }
 
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'V');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "V");
   }
 
   void InvokeIdentityByteMethod(bool is_static)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     mirror::ArtMethod* method;
     mirror::Object* receiver;
-    JniInternalTestMakeExecutable(&method, &receiver, is_static, "identity", "(I)I");
+    JniInternalTestMakeExecutable(&method, &receiver, is_static, "identity", "(B)B");
 
     ArgArray arg_array(NULL, 0);
     uint32_t* args = arg_array.GetArray();
@@ -154,22 +154,22 @@
 
     arg_array.Append(0U);
     result.SetB(-1);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'B');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "BB");
     EXPECT_EQ(0, result.GetB());
 
     args[0] = -1;
     result.SetB(0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'B');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "BB");
     EXPECT_EQ(-1, result.GetB());
 
     args[0] = SCHAR_MAX;
     result.SetB(0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'B');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "BB");
     EXPECT_EQ(SCHAR_MAX, result.GetB());
 
     args[0] = (SCHAR_MIN << 24) >> 24;
     result.SetB(0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'B');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "BB");
     EXPECT_EQ(SCHAR_MIN, result.GetB());
   }
 
@@ -190,22 +190,22 @@
 
     arg_array.Append(0U);
     result.SetI(-1);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "II");
     EXPECT_EQ(0, result.GetI());
 
     args[0] = -1;
     result.SetI(0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "II");
     EXPECT_EQ(-1, result.GetI());
 
     args[0] = INT_MAX;
     result.SetI(0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "II");
     EXPECT_EQ(INT_MAX, result.GetI());
 
     args[0] = INT_MIN;
     result.SetI(0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "II");
     EXPECT_EQ(INT_MIN, result.GetI());
   }
 
@@ -228,28 +228,28 @@
     value.SetD(0.0);
     arg_array.AppendWide(value.GetJ());
     result.SetD(-1.0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'D');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "DD");
     EXPECT_EQ(0.0, result.GetD());
 
     value.SetD(-1.0);
     args[0] = value.GetJ();
     args[1] = value.GetJ() >> 32;
     result.SetD(0.0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'D');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "DD");
     EXPECT_EQ(-1.0, result.GetD());
 
     value.SetD(DBL_MAX);
     args[0] = value.GetJ();
     args[1] = value.GetJ() >> 32;
     result.SetD(0.0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'D');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "DD");
     EXPECT_EQ(DBL_MAX, result.GetD());
 
     value.SetD(DBL_MIN);
     args[0] = value.GetJ();
     args[1] = value.GetJ() >> 32;
     result.SetD(0.0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'D');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "DD");
     EXPECT_EQ(DBL_MIN, result.GetD());
   }
 
@@ -271,31 +271,31 @@
     arg_array.Append(0U);
     arg_array.Append(0U);
     result.SetI(-1);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "III");
     EXPECT_EQ(0, result.GetI());
 
     args[0] = 1;
     args[1] = 2;
     result.SetI(0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "III");
     EXPECT_EQ(3, result.GetI());
 
     args[0] = -2;
     args[1] = 5;
     result.SetI(0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "III");
     EXPECT_EQ(3, result.GetI());
 
     args[0] = INT_MAX;
     args[1] = INT_MIN;
     result.SetI(1234);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "III");
     EXPECT_EQ(-1, result.GetI());
 
     args[0] = INT_MAX;
     args[1] = INT_MAX;
     result.SetI(INT_MIN);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "III");
     EXPECT_EQ(-2, result.GetI());
   }
 
@@ -318,35 +318,40 @@
     arg_array.Append(0U);
     arg_array.Append(0U);
     result.SetI(-1);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "IIII");
     EXPECT_EQ(0, result.GetI());
 
     args[0] = 1;
     args[1] = 2;
     args[2] = 3;
     result.SetI(0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "IIII");
     EXPECT_EQ(6, result.GetI());
 
     args[0] = -1;
     args[1] = 2;
     args[2] = -3;
     result.SetI(0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "IIII");
     EXPECT_EQ(-2, result.GetI());
 
     args[0] = INT_MAX;
     args[1] = INT_MIN;
     args[2] = INT_MAX;
     result.SetI(1234);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "IIII");
     EXPECT_EQ(2147483646, result.GetI());
 
     args[0] = INT_MAX;
     args[1] = INT_MAX;
     args[2] = INT_MAX;
     result.SetI(INT_MIN);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "IIII");
     EXPECT_EQ(2147483645, result.GetI());
   }
 
@@ -370,7 +375,8 @@
     arg_array.Append(0U);
     arg_array.Append(0U);
     result.SetI(-1);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "IIIII");
     EXPECT_EQ(0, result.GetI());
 
     args[0] = 1;
@@ -378,7 +384,8 @@
     args[2] = 3;
     args[3] = 4;
     result.SetI(0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "IIIII");
     EXPECT_EQ(10, result.GetI());
 
     args[0] = -1;
@@ -386,7 +393,8 @@
     args[2] = -3;
     args[3] = 4;
     result.SetI(0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "IIIII");
     EXPECT_EQ(2, result.GetI());
 
     args[0] = INT_MAX;
@@ -394,7 +402,8 @@
     args[2] = INT_MAX;
     args[3] = INT_MIN;
     result.SetI(1234);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "IIIII");
     EXPECT_EQ(-2, result.GetI());
 
     args[0] = INT_MAX;
@@ -402,7 +411,8 @@
     args[2] = INT_MAX;
     args[3] = INT_MAX;
     result.SetI(INT_MIN);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "IIIII");
     EXPECT_EQ(-4, result.GetI());
   }
 
@@ -427,7 +437,8 @@
     arg_array.Append(0U);
     arg_array.Append(0U);
     result.SetI(-1.0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "IIIIII");
     EXPECT_EQ(0, result.GetI());
 
     args[0] = 1;
@@ -436,7 +447,8 @@
     args[3] = 4;
     args[4] = 5;
     result.SetI(0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "IIIIII");
     EXPECT_EQ(15, result.GetI());
 
     args[0] = -1;
@@ -445,7 +457,8 @@
     args[3] = 4;
     args[4] = -5;
     result.SetI(0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "IIIIII");
     EXPECT_EQ(-3, result.GetI());
 
     args[0] = INT_MAX;
@@ -454,7 +467,8 @@
     args[3] = INT_MIN;
     args[4] = INT_MAX;
     result.SetI(1234);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "IIIIII");
     EXPECT_EQ(2147483645, result.GetI());
 
     args[0] = INT_MAX;
@@ -463,7 +477,8 @@
     args[3] = INT_MAX;
     args[4] = INT_MAX;
     result.SetI(INT_MIN);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "IIIIII");
     EXPECT_EQ(2147483643, result.GetI());
   }
 
@@ -489,7 +504,8 @@
     arg_array.AppendWide(value.GetJ());
     arg_array.AppendWide(value2.GetJ());
     result.SetD(-1.0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'D');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "DDD");
     EXPECT_EQ(0.0, result.GetD());
 
     value.SetD(1.0);
@@ -499,7 +515,8 @@
     args[2] = value2.GetJ();
     args[3] = value2.GetJ() >> 32;
     result.SetD(0.0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'D');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "DDD");
     EXPECT_EQ(3.0, result.GetD());
 
     value.SetD(1.0);
@@ -509,7 +526,8 @@
     args[2] = value2.GetJ();
     args[3] = value2.GetJ() >> 32;
     result.SetD(0.0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'D');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "DDD");
     EXPECT_EQ(-1.0, result.GetD());
 
     value.SetD(DBL_MAX);
@@ -519,7 +537,8 @@
     args[2] = value2.GetJ();
     args[3] = value2.GetJ() >> 32;
     result.SetD(0.0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'D');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "DDD");
     EXPECT_EQ(1.7976931348623157e308, result.GetD());
 
     value.SetD(DBL_MAX);
@@ -529,7 +548,8 @@
     args[2] = value2.GetJ();
     args[3] = value2.GetJ() >> 32;
     result.SetD(0.0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'D');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "DDD");
     EXPECT_EQ(INFINITY, result.GetD());
   }
 
@@ -558,7 +578,8 @@
     arg_array.AppendWide(value2.GetJ());
     arg_array.AppendWide(value3.GetJ());
     result.SetD(-1.0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'D');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "DDDD");
     EXPECT_EQ(0.0, result.GetD());
 
     value.SetD(1.0);
@@ -571,7 +592,8 @@
     args[4] = value3.GetJ();
     args[5] = value3.GetJ() >> 32;
     result.SetD(0.0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'D');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "DDDD");
     EXPECT_EQ(6.0, result.GetD());
 
     value.SetD(1.0);
@@ -584,7 +606,8 @@
     args[4] = value3.GetJ();
     args[5] = value3.GetJ() >> 32;
     result.SetD(0.0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'D');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "DDDD");
     EXPECT_EQ(2.0, result.GetD());
   }
 
@@ -616,7 +639,8 @@
     arg_array.AppendWide(value3.GetJ());
     arg_array.AppendWide(value4.GetJ());
     result.SetD(-1.0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'D');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "DDDDD");
     EXPECT_EQ(0.0, result.GetD());
 
     value.SetD(1.0);
@@ -632,7 +656,8 @@
     args[6] = value4.GetJ();
     args[7] = value4.GetJ() >> 32;
     result.SetD(0.0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'D');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "DDDDD");
     EXPECT_EQ(10.0, result.GetD());
 
     value.SetD(1.0);
@@ -648,7 +673,8 @@
     args[6] = value4.GetJ();
     args[7] = value4.GetJ() >> 32;
     result.SetD(0.0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'D');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "DDDDD");
     EXPECT_EQ(-2.0, result.GetD());
   }
 
@@ -683,7 +709,8 @@
     arg_array.AppendWide(value4.GetJ());
     arg_array.AppendWide(value5.GetJ());
     result.SetD(-1.0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'D');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "DDDDDD");
     EXPECT_EQ(0.0, result.GetD());
 
     value.SetD(1.0);
@@ -702,7 +729,8 @@
     args[8] = value5.GetJ();
     args[9] = value5.GetJ() >> 32;
     result.SetD(0.0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'D');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "DDDDDD");
     EXPECT_EQ(15.0, result.GetD());
 
     value.SetD(1.0);
@@ -721,7 +749,8 @@
     args[8] = value5.GetJ();
     args[9] = value5.GetJ() >> 32;
     result.SetD(0.0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'D');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "DDDDDD");
     EXPECT_EQ(3.0, result.GetD());
   }
 
@@ -1764,7 +1793,7 @@
   CHECK(started);
   Thread::Current()->TransitionFromSuspendedToRunnable();
 
-  method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'V');
+  method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "VL");
 }
 
 TEST_F(JniInternalTest, StaticNopMethod) {
diff --git a/runtime/mirror/art_method.cc b/runtime/mirror/art_method.cc
index 3359d59..67e6c7d 100644
--- a/runtime/mirror/art_method.cc
+++ b/runtime/mirror/art_method.cc
@@ -35,7 +35,8 @@
 namespace mirror {
 
 extern "C" void art_portable_invoke_stub(ArtMethod*, uint32_t*, uint32_t, Thread*, JValue*, char);
-extern "C" void art_quick_invoke_stub(ArtMethod*, uint32_t*, uint32_t, Thread*, JValue*, char);
+extern "C" void art_quick_invoke_stub(ArtMethod*, uint32_t*, uint32_t, Thread*, JValue*,
+                                      const char*);
 
 // TODO: get global references for these
 Class* ArtMethod::java_lang_reflect_ArtMethod_ = NULL;
@@ -245,10 +246,11 @@
 }
 
 void ArtMethod::Invoke(Thread* self, uint32_t* args, uint32_t args_size, JValue* result,
-                       char result_type) {
+                       const char* shorty) {
   if (kIsDebugBuild) {
     self->AssertThreadSuspensionIsAllowable();
     CHECK_EQ(kRunnable, self->GetState());
+    CHECK_STREQ(MethodHelper(this).GetShorty(), shorty);
   }
 
   // Push a transition back into managed code onto the linked list in thread.
@@ -274,9 +276,9 @@
                                                   : GetEntryPointFromPortableCompiledCode());
       }
       if (!IsPortableCompiled()) {
-        (*art_quick_invoke_stub)(this, args, args_size, self, result, result_type);
+        (*art_quick_invoke_stub)(this, args, args_size, self, result, shorty);
       } else {
-        (*art_portable_invoke_stub)(this, args, args_size, self, result, result_type);
+        (*art_portable_invoke_stub)(this, args, args_size, self, result, shorty[0]);
       }
       if (UNLIKELY(reinterpret_cast<intptr_t>(self->GetException(NULL)) == -1)) {
         // Unusual case where we were running LLVM generated code and an
diff --git a/runtime/mirror/art_method.h b/runtime/mirror/art_method.h
index dfaf063..e678503 100644
--- a/runtime/mirror/art_method.h
+++ b/runtime/mirror/art_method.h
@@ -207,8 +207,8 @@
   // Find the method that this method overrides
   ArtMethod* FindOverriddenMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  void Invoke(Thread* self, uint32_t* args, uint32_t args_size, JValue* result, char result_type)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void Invoke(Thread* self, uint32_t* args, uint32_t args_size, JValue* result,
+              const char* shorty) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   EntryPointFromInterpreter* GetEntryPointFromInterpreter() {
     return GetFieldPtr<EntryPointFromInterpreter*>(
diff --git a/runtime/object_utils.h b/runtime/object_utils.h
index 0451f5d..a981fab 100644
--- a/runtime/object_utils.h
+++ b/runtime/object_utils.h
@@ -607,6 +607,37 @@
     return DexFile::kDexNoIndex;
   }
 
+  // The name_and_signature_idx MUST point to a MethodId with the same name and signature in the
+  // other_dexfile, such as the method index used to resolve this method in the other_dexfile.
+  uint32_t FindDexMethodIndexInOtherDexFile(const DexFile& other_dexfile,
+                                            uint32_t name_and_signature_idx)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    const DexFile& dexfile = GetDexFile();
+    const DexFile::MethodId& mid = dexfile.GetMethodId(method_->GetDexMethodIndex());
+    const DexFile::MethodId& name_and_sig_mid = other_dexfile.GetMethodId(name_and_signature_idx);
+    DCHECK_STREQ(dexfile.GetMethodName(mid), other_dexfile.GetMethodName(name_and_sig_mid));
+    DCHECK_EQ(dexfile.GetMethodSignature(mid), other_dexfile.GetMethodSignature(name_and_sig_mid));
+    if (&dexfile == &other_dexfile) {
+      return method_->GetDexMethodIndex();
+    }
+    const char* mid_declaring_class_descriptor = dexfile.StringByTypeIdx(mid.class_idx_);
+    const DexFile::StringId* other_descriptor =
+        other_dexfile.FindStringId(mid_declaring_class_descriptor);
+    if (other_descriptor != nullptr) {
+      const DexFile::TypeId* other_type_id =
+          other_dexfile.FindTypeId(other_dexfile.GetIndexForStringId(*other_descriptor));
+      if (other_type_id != nullptr) {
+        const DexFile::MethodId* other_mid = other_dexfile.FindMethodId(
+            *other_type_id, other_dexfile.GetStringId(name_and_sig_mid.name_idx_),
+            other_dexfile.GetProtoId(name_and_sig_mid.proto_idx_));
+        if (other_mid != nullptr) {
+          return other_dexfile.GetIndexForMethodId(*other_mid);
+        }
+      }
+    }
+    return DexFile::kDexNoIndex;
+  }
+
  private:
   // Set the method_ field, for proxy methods looking up the interface method via the resolved
   // methods table.
diff --git a/runtime/reflection.cc b/runtime/reflection.cc
index ac8f5ef..0bfa70f 100644
--- a/runtime/reflection.cc
+++ b/runtime/reflection.cc
@@ -220,36 +220,46 @@
   }
 
   jmethodID m = NULL;
+  const char* shorty;
   switch (src_class) {
   case Primitive::kPrimBoolean:
     m = WellKnownClasses::java_lang_Boolean_valueOf;
+    shorty = "LZ";
     break;
   case Primitive::kPrimByte:
     m = WellKnownClasses::java_lang_Byte_valueOf;
+    shorty = "LB";
     break;
   case Primitive::kPrimChar:
     m = WellKnownClasses::java_lang_Character_valueOf;
+    shorty = "LC";
     break;
   case Primitive::kPrimDouble:
     m = WellKnownClasses::java_lang_Double_valueOf;
+    shorty = "LD";
     break;
   case Primitive::kPrimFloat:
     m = WellKnownClasses::java_lang_Float_valueOf;
+    shorty = "LF";
     break;
   case Primitive::kPrimInt:
     m = WellKnownClasses::java_lang_Integer_valueOf;
+    shorty = "LI";
     break;
   case Primitive::kPrimLong:
     m = WellKnownClasses::java_lang_Long_valueOf;
+    shorty = "LJ";
     break;
   case Primitive::kPrimShort:
     m = WellKnownClasses::java_lang_Short_valueOf;
+    shorty = "LS";
     break;
   case Primitive::kPrimVoid:
     // There's no such thing as a void field, and void methods invoked via reflection return null.
-    return NULL;
+    return nullptr;
   default:
     LOG(FATAL) << static_cast<int>(src_class);
+    shorty = nullptr;
   }
 
   ScopedObjectAccessUnchecked soa(Thread::Current());
@@ -257,7 +267,7 @@
     CHECK_EQ(soa.Self()->GetState(), kRunnable);
   }
 
-  ArgArray arg_array(NULL, 0);
+  ArgArray arg_array(nullptr, 0);
   JValue result;
   if (src_class == Primitive::kPrimDouble || src_class == Primitive::kPrimLong) {
     arg_array.AppendWide(value.GetJ());
@@ -266,7 +276,7 @@
   }
 
   soa.DecodeMethod(m)->Invoke(soa.Self(), arg_array.GetArray(), arg_array.GetNumBytes(),
-                              &result, 'L');
+                              &result, shorty);
   return result.GetL();
 }
 
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 9193be5..d8f9ca3 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -765,6 +765,12 @@
     parsed->image_ += GetAndroidRoot();
     parsed->image_ += "/framework/boot.art";
   }
+  if (!kIsTargetBuild && parsed->host_prefix_.empty()) {
+    const char* build_top = getenv("ANDROID_BUILD_TOP");
+    if (build_top != NULL) {
+      parsed->host_prefix_ = build_top;
+    }
+  }
   if (parsed->heap_growth_limit_ == 0) {
     parsed->heap_growth_limit_ = parsed->heap_maximum_size_;
   }
@@ -807,7 +813,7 @@
 
   JValue result;
   ArgArray arg_array(nullptr, 0);
-  InvokeWithArgArray(soa, getSystemClassLoader, &arg_array, &result, 'L');
+  InvokeWithArgArray(soa, getSystemClassLoader, &arg_array, &result, "L");
   SirtRef<mirror::ClassLoader> class_loader(soa.Self(),
                                             down_cast<mirror::ClassLoader*>(result.GetL()));
   CHECK(class_loader.get() != nullptr);
@@ -834,7 +840,7 @@
 bool Runtime::Start() {
   VLOG(startup) << "Runtime::Start entering";
 
-  CHECK(host_prefix_.empty()) << host_prefix_;
+  CHECK(!kIsTargetBuild || host_prefix_.empty()) << host_prefix_;
 
   // Restore main thread state to kNative as expected by native code.
   Thread* self = Thread::Current();
@@ -1476,12 +1482,11 @@
     method->SetFpSpillMask(0);
   } else if (instruction_set == kX86_64) {
     uint32_t ref_spills =
-        (1 << art::x86_64::RBP) | (1 << art::x86_64::RSI) | (1 << art::x86_64::RDI) |
-        (1 << art::x86_64::R8)  | (1 << art::x86_64::R9)  | (1 << art::x86_64::R10) |
-        (1 << art::x86_64::R11) | (1 << art::x86_64::R12) | (1 << art::x86_64::R13) |
-        (1 << art::x86_64::R14) | (1 << art::x86_64::R15);
+        (1 << art::x86_64::RBX) | (1 << art::x86_64::RBP) | (1 << art::x86_64::R12) |
+        (1 << art::x86_64::R13) | (1 << art::x86_64::R14) | (1 << art::x86_64::R15);
     uint32_t arg_spills =
-        (1 << art::x86_64::RCX) | (1 << art::x86_64::RDX) | (1 << art::x86_64::RBX);
+        (1 << art::x86_64::RSI) | (1 << art::x86_64::RDX) | (1 << art::x86_64::RCX) |
+        (1 << art::x86_64::R8) | (1 << art::x86_64::R9);
     uint32_t core_spills = ref_spills | (type == kRefsAndArgs ? arg_spills : 0) |
                          (1 << art::x86::kNumberOfCpuRegisters);  // fake return address callee save
     size_t frame_size = RoundUp((__builtin_popcount(core_spills) /* gprs */ +
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 6da9c1c..9797a48 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -179,7 +179,7 @@
     JValue result;
     ArgArray arg_array(nullptr, 0);
     arg_array.Append(receiver);
-    m->Invoke(self, arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'V');
+    m->Invoke(self, arg_array.GetArray(), arg_array.GetNumBytes(), &result, "V");
   }
   // Detach and delete self.
   Runtime::Current()->GetThreadList()->Unregister(self);
@@ -1531,6 +1531,7 @@
 
   // Choose an appropriate constructor and set up the arguments.
   const char* signature;
+  const char* shorty;
   SirtRef<mirror::String> msg_string(this, nullptr);
   if (msg != nullptr) {
     // Ensure we remember this and the method over the String allocation.
@@ -1540,14 +1541,18 @@
       return;
     }
     if (cause.get() == nullptr) {
+      shorty = "VL";
       signature = "(Ljava/lang/String;)V";
     } else {
+      shorty = "VLL";
       signature = "(Ljava/lang/String;Ljava/lang/Throwable;)V";
     }
   } else {
     if (cause.get() == nullptr) {
+      shorty = "V";
       signature = "()V";
     } else {
+      shorty = "VL";
       signature = "(Ljava/lang/Throwable;)V";
     }
   }
@@ -1571,7 +1576,7 @@
                                          throw_location.GetDexPc());
     SetException(gc_safe_throw_location, exception.get());
   } else {
-    ArgArray args("VLL", 3);
+    ArgArray args(shorty, strlen(shorty));
     args.Append(exception.get());
     if (msg != nullptr) {
       args.Append(msg_string.get());
@@ -1580,7 +1585,7 @@
       args.Append(cause.get());
     }
     JValue result;
-    exception_init_method->Invoke(this, args.GetArray(), args.GetNumBytes(), &result, 'V');
+    exception_init_method->Invoke(this, args.GetArray(), args.GetNumBytes(), &result, shorty);
     if (LIKELY(!IsExceptionPending())) {
       ThrowLocation gc_safe_throw_location(saved_throw_this.get(), saved_throw_method.get(),
                                            throw_location.GetDexPc());
diff --git a/tools/Android.mk b/tools/Android.mk
new file mode 100644
index 0000000..6c385dc
--- /dev/null
+++ b/tools/Android.mk
@@ -0,0 +1,32 @@
+#
+# Copyright (C) 2014 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+ifeq ($(WITH_HOST_DALVIK),true)
+# Copy the art shell script to the host's bin directory
+include $(CLEAR_VARS)
+LOCAL_IS_HOST_MODULE := true
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_MODULE := art
+include $(BUILD_SYSTEM)/base_rules.mk
+$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/art $(ACP)
+	@echo "Copy: $(PRIVATE_MODULE) ($@)"
+	$(copy-file-to-new-target)
+	$(hide) chmod 755 $@
+
+endif
diff --git a/tools/art b/tools/art
index 0a6c941..2e3a46e 100755
--- a/tools/art
+++ b/tools/art
@@ -34,8 +34,22 @@
 done
 
 unset ANDROID_PRODUCT_OUT # avoid defaulting dex2oat --host-prefix to target output
+
+function follow_links() {
+  file="$1"
+  while [ -h "$file" ]; do
+    # On Mac OS, readlink -f doesn't work.
+    file="$(readlink "$file")"
+  done
+  echo "$file"
+}
+
+PROG_NAME="$(follow_links "$BASH_SOURCE")"
+PROG_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
+ANDROID_BUILD_TOP="$(cd "${PROG_DIR}/../../../../" ; pwd -P)/"
+ANDROID_HOST_OUT=$PROG_DIR/..
+
 mkdir -p /tmp/android-data/dalvik-cache
-cd $ANDROID_BUILD_TOP
 ANDROID_DATA=/tmp/android-data \
   ANDROID_ROOT=$ANDROID_HOST_OUT \
   LD_LIBRARY_PATH=$ANDROID_HOST_OUT/lib \