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 \