Merge "Add root types and thread id to root visiting."
diff --git a/compiler/dex/frontend.cc b/compiler/dex/frontend.cc
index c2016d0..8f83cd0 100644
--- a/compiler/dex/frontend.cc
+++ b/compiler/dex/frontend.cc
@@ -140,24 +140,25 @@
CompilationUnit::~CompilationUnit() {
}
-// TODO: Add a cumulative version of logging, and combine with dex2oat --dump-timing
void CompilationUnit::StartTimingSplit(const char* label) {
- if (enable_debug & (1 << kDebugTimings)) {
+ if (compiler_driver->GetDumpPasses()) {
timings.StartSplit(label);
}
}
void CompilationUnit::NewTimingSplit(const char* label) {
- if (enable_debug & (1 << kDebugTimings)) {
+ if (compiler_driver->GetDumpPasses()) {
timings.NewSplit(label);
}
}
void CompilationUnit::EndTiming() {
- if (enable_debug & (1 << kDebugTimings)) {
+ if (compiler_driver->GetDumpPasses()) {
timings.EndSplit();
- LOG(INFO) << "TIMINGS " << PrettyMethod(method_idx, *dex_file);
- LOG(INFO) << Dumpable<TimingLogger>(timings);
+ if (enable_debug & (1 << kDebugTimings)) {
+ LOG(INFO) << "TIMINGS " << PrettyMethod(method_idx, *dex_file);
+ LOG(INFO) << Dumpable<TimingLogger>(timings);
+ }
}
}
@@ -330,6 +331,9 @@
}
cu.EndTiming();
+ compiler.GetTimingsLogger().Start();
+ compiler.GetTimingsLogger().AddLogger(cu.timings);
+ compiler.GetTimingsLogger().End();
return result;
}
diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc
index 5e0fed7..05eb360 100644
--- a/compiler/dex/quick/codegen_util.cc
+++ b/compiler/dex/quick/codegen_util.cc
@@ -1186,4 +1186,37 @@
void Mir2Lir::AddSlowPath(LIRSlowPath* slowpath) {
slow_paths_.Insert(slowpath);
}
+
+void Mir2Lir::LoadCodeAddress(int dex_method_index, InvokeType type, SpecialTargetRegister symbolic_reg) {
+ LIR* data_target = ScanLiteralPool(code_literal_list_, dex_method_index, 0);
+ if (data_target == NULL) {
+ data_target = AddWordData(&code_literal_list_, dex_method_index);
+ data_target->operands[1] = type;
+ }
+ LIR* load_pc_rel = OpPcRelLoad(TargetReg(symbolic_reg), data_target);
+ AppendLIR(load_pc_rel);
+ DCHECK_NE(cu_->instruction_set, kMips) << reinterpret_cast<void*>(data_target);
+}
+
+void Mir2Lir::LoadMethodAddress(int dex_method_index, InvokeType type, SpecialTargetRegister symbolic_reg) {
+ LIR* data_target = ScanLiteralPool(method_literal_list_, dex_method_index, 0);
+ if (data_target == NULL) {
+ data_target = AddWordData(&method_literal_list_, dex_method_index);
+ data_target->operands[1] = type;
+ }
+ LIR* load_pc_rel = OpPcRelLoad(TargetReg(symbolic_reg), data_target);
+ AppendLIR(load_pc_rel);
+ DCHECK_NE(cu_->instruction_set, kMips) << reinterpret_cast<void*>(data_target);
+}
+
+void Mir2Lir::LoadClassType(uint32_t type_idx, SpecialTargetRegister symbolic_reg) {
+ // Use the literal pool and a PC-relative load from a data word.
+ LIR* data_target = ScanLiteralPool(class_literal_list_, type_idx, 0);
+ if (data_target == nullptr) {
+ data_target = AddWordData(&class_literal_list_, type_idx);
+ }
+ LIR* load_pc_rel = OpPcRelLoad(TargetReg(symbolic_reg), data_target);
+ AppendLIR(load_pc_rel);
+}
+
} // namespace art
diff --git a/compiler/dex/quick/dex_file_method_inliner.cc b/compiler/dex/quick/dex_file_method_inliner.cc
index 0ad8abf..389dd9a 100644
--- a/compiler/dex/quick/dex_file_method_inliner.cc
+++ b/compiler/dex/quick/dex_file_method_inliner.cc
@@ -123,6 +123,8 @@
{ kClassCacheShort, 1, { kClassCacheShort } },
// kProtoCacheD_D
{ kClassCacheDouble, 1, { kClassCacheDouble } },
+ // kProtoCacheF_F
+ { kClassCacheFloat, 1, { kClassCacheFloat } },
// kProtoCacheD_J
{ kClassCacheLong, 1, { kClassCacheDouble } },
// kProtoCacheJ_D
@@ -198,6 +200,10 @@
INTRINSIC(JavaLangStrictMath, Abs, I_I, kIntrinsicAbsInt, 0),
INTRINSIC(JavaLangMath, Abs, J_J, kIntrinsicAbsLong, 0),
INTRINSIC(JavaLangStrictMath, Abs, J_J, kIntrinsicAbsLong, 0),
+ INTRINSIC(JavaLangMath, Abs, F_F, kIntrinsicAbsFloat, 0),
+ INTRINSIC(JavaLangStrictMath, Abs, F_F, kIntrinsicAbsFloat, 0),
+ INTRINSIC(JavaLangMath, Abs, D_D, kIntrinsicAbsDouble, 0),
+ INTRINSIC(JavaLangStrictMath, Abs, D_D, kIntrinsicAbsDouble, 0),
INTRINSIC(JavaLangMath, Min, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMin),
INTRINSIC(JavaLangStrictMath, Min, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMin),
INTRINSIC(JavaLangMath, Max, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMax),
@@ -345,6 +351,10 @@
return backend->GenInlinedAbsInt(info);
case kIntrinsicAbsLong:
return backend->GenInlinedAbsLong(info);
+ case kIntrinsicAbsFloat:
+ return backend->GenInlinedAbsFloat(info);
+ case kIntrinsicAbsDouble:
+ return backend->GenInlinedAbsDouble(info);
case kIntrinsicMinMaxInt:
return backend->GenInlinedMinMaxInt(info, intrinsic.d.data & kIntrinsicFlagMin);
case kIntrinsicSqrt:
diff --git a/compiler/dex/quick/dex_file_method_inliner.h b/compiler/dex/quick/dex_file_method_inliner.h
index fe0824c..fb7528e 100644
--- a/compiler/dex/quick/dex_file_method_inliner.h
+++ b/compiler/dex/quick/dex_file_method_inliner.h
@@ -40,6 +40,8 @@
kIntrinsicReverseBytes,
kIntrinsicAbsInt,
kIntrinsicAbsLong,
+ kIntrinsicAbsFloat,
+ kIntrinsicAbsDouble,
kIntrinsicMinMaxInt,
kIntrinsicSqrt,
kIntrinsicCharAt,
@@ -268,6 +270,7 @@
kProtoCacheJ_J,
kProtoCacheS_S,
kProtoCacheD_D,
+ kProtoCacheF_F,
kProtoCacheD_J,
kProtoCacheJ_D,
kProtoCacheF_I,
diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc
index c59f3b8..0533fbf 100644
--- a/compiler/dex/quick/gen_common.cc
+++ b/compiler/dex/quick/gen_common.cc
@@ -220,13 +220,7 @@
&is_type_initialized, &use_direct_type_ptr, &direct_type_ptr)) {
// The fast path.
if (!use_direct_type_ptr) {
- // Use the literal pool and a PC-relative load from a data word.
- LIR* data_target = ScanLiteralPool(class_literal_list_, type_idx, 0);
- if (data_target == nullptr) {
- data_target = AddWordData(&class_literal_list_, type_idx);
- }
- LIR* load_pc_rel = OpPcRelLoad(TargetReg(kArg0), data_target);
- AppendLIR(load_pc_rel);
+ LoadClassType(type_idx, kArg0);
func_offset = QUICK_ENTRYPOINT_OFFSET(pAllocArrayResolved);
CallRuntimeHelperRegMethodRegLocation(func_offset, TargetReg(kArg0), rl_src, true);
} else {
@@ -994,13 +988,7 @@
&is_type_initialized, &use_direct_type_ptr, &direct_type_ptr)) {
// The fast path.
if (!use_direct_type_ptr) {
- // Use the literal pool and a PC-relative load from a data word.
- LIR* data_target = ScanLiteralPool(class_literal_list_, type_idx, 0);
- if (data_target == nullptr) {
- data_target = AddWordData(&class_literal_list_, type_idx);
- }
- LIR* load_pc_rel = OpPcRelLoad(TargetReg(kArg0), data_target);
- AppendLIR(load_pc_rel);
+ LoadClassType(type_idx, kArg0);
if (!is_type_initialized) {
func_offset = QUICK_ENTRYPOINT_OFFSET(pAllocObjectResolved);
CallRuntimeHelperRegMethod(func_offset, TargetReg(kArg0), true);
@@ -1100,6 +1088,9 @@
bool can_assume_type_is_in_dex_cache,
uint32_t type_idx, RegLocation rl_dest,
RegLocation rl_src) {
+ // X86 has its own implementation.
+ DCHECK_NE(cu_->instruction_set, kX86);
+
FlushAllRegs();
// May generate a call - use explicit registers
LockCallTemps();
@@ -1181,15 +1172,10 @@
LoadConstant(rl_result.low_reg, 1); // assume true
branchover = OpCmpBranch(kCondEq, TargetReg(kArg1), TargetReg(kArg2), NULL);
}
- if (cu_->instruction_set != kX86) {
- int r_tgt = LoadHelper(QUICK_ENTRYPOINT_OFFSET(pInstanceofNonTrivial));
- OpRegCopy(TargetReg(kArg0), TargetReg(kArg2)); // .ne case - arg0 <= class
- OpReg(kOpBlx, r_tgt); // .ne case: helper(class, ref->class)
- FreeTemp(r_tgt);
- } else {
- OpRegCopy(TargetReg(kArg0), TargetReg(kArg2));
- OpThreadMem(kOpBlx, QUICK_ENTRYPOINT_OFFSET(pInstanceofNonTrivial));
- }
+ int r_tgt = LoadHelper(QUICK_ENTRYPOINT_OFFSET(pInstanceofNonTrivial));
+ OpRegCopy(TargetReg(kArg0), TargetReg(kArg2)); // .ne case - arg0 <= class
+ OpReg(kOpBlx, r_tgt); // .ne case: helper(class, ref->class)
+ FreeTemp(r_tgt);
}
}
// TODO: only clobber when type isn't final?
diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc
index 6aaad66..ee61c8b 100644
--- a/compiler/dex/quick/gen_invoke.cc
+++ b/compiler/dex/quick/gen_invoke.cc
@@ -384,31 +384,15 @@
if (cu->instruction_set != kX86) {
cg->LoadConstant(cg->TargetReg(kInvokeTgt), direct_code);
}
- } else {
+ } else if (cu->instruction_set != kX86) {
CHECK_EQ(cu->dex_file, target_method.dex_file);
- LIR* data_target = cg->ScanLiteralPool(cg->code_literal_list_,
- target_method.dex_method_index, 0);
- if (data_target == NULL) {
- data_target = cg->AddWordData(&cg->code_literal_list_, target_method.dex_method_index);
- data_target->operands[1] = type;
- }
- LIR* load_pc_rel = cg->OpPcRelLoad(cg->TargetReg(kInvokeTgt), data_target);
- cg->AppendLIR(load_pc_rel);
- DCHECK_EQ(cu->instruction_set, kThumb2) << reinterpret_cast<void*>(data_target);
+ cg->LoadCodeAddress(target_method.dex_method_index, type, kInvokeTgt);
}
if (direct_method != static_cast<unsigned int>(-1)) {
cg->LoadConstant(cg->TargetReg(kArg0), direct_method);
} else {
CHECK_EQ(cu->dex_file, target_method.dex_file);
- LIR* data_target = cg->ScanLiteralPool(cg->method_literal_list_,
- target_method.dex_method_index, 0);
- if (data_target == NULL) {
- data_target = cg->AddWordData(&cg->method_literal_list_, target_method.dex_method_index);
- data_target->operands[1] = type;
- }
- LIR* load_pc_rel = cg->OpPcRelLoad(cg->TargetReg(kArg0), data_target);
- cg->AppendLIR(load_pc_rel);
- DCHECK_EQ(cu->instruction_set, kThumb2) << reinterpret_cast<void*>(data_target);
+ cg->LoadMethodAddress(target_method.dex_method_index, type, kArg0);
}
break;
default:
@@ -427,18 +411,10 @@
if (direct_code != 0) {
if (direct_code != static_cast<unsigned int>(-1)) {
cg->LoadConstant(cg->TargetReg(kInvokeTgt), direct_code);
- } else {
+ } else if (cu->instruction_set != kX86) {
CHECK_EQ(cu->dex_file, target_method.dex_file);
CHECK_LT(target_method.dex_method_index, target_method.dex_file->NumMethodIds());
- LIR* data_target = cg->ScanLiteralPool(cg->code_literal_list_,
- target_method.dex_method_index, 0);
- if (data_target == NULL) {
- data_target = cg->AddWordData(&cg->code_literal_list_, target_method.dex_method_index);
- data_target->operands[1] = type;
- }
- LIR* load_pc_rel = cg->OpPcRelLoad(cg->TargetReg(kInvokeTgt), data_target);
- cg->AppendLIR(load_pc_rel);
- DCHECK_EQ(cu->instruction_set, kThumb2) << reinterpret_cast<void*>(data_target);
+ cg->LoadCodeAddress(target_method.dex_method_index, type, kInvokeTgt);
}
}
break;
@@ -1001,7 +977,10 @@
RegLocation rl_obj = info->args[0];
RegLocation rl_idx = info->args[1];
rl_obj = LoadValue(rl_obj, kCoreReg);
- rl_idx = LoadValue(rl_idx, kCoreReg);
+ // X86 wants to avoid putting a constant index into a register.
+ if (!(cu_->instruction_set == kX86 && rl_idx.is_const)) {
+ rl_idx = LoadValue(rl_idx, kCoreReg);
+ }
int reg_max;
GenNullCheck(rl_obj.s_reg_low, rl_obj.low_reg, info->opt_flags);
bool range_check = (!(info->opt_flags & MIR_IGNORE_RANGE_CHECK));
@@ -1025,29 +1004,43 @@
FreeTemp(reg_max);
OpCondBranch(kCondUge, launch_pad);
}
+ OpRegImm(kOpAdd, reg_ptr, data_offset);
} else {
if (range_check) {
- reg_max = AllocTemp();
- LoadWordDisp(rl_obj.low_reg, count_offset, reg_max);
+ // On x86, we can compare to memory directly
// Set up a launch pad to allow retry in case of bounds violation */
launch_pad = RawLIR(0, kPseudoIntrinsicRetry, WrapPointer(info));
intrinsic_launchpads_.Insert(launch_pad);
- OpRegReg(kOpCmp, rl_idx.low_reg, reg_max);
- FreeTemp(reg_max);
- OpCondBranch(kCondUge, launch_pad);
+ if (rl_idx.is_const) {
+ OpCmpMemImmBranch(kCondUlt, INVALID_REG, rl_obj.low_reg, count_offset,
+ mir_graph_->ConstantValue(rl_idx.orig_sreg), launch_pad);
+ } else {
+ OpRegMem(kOpCmp, rl_idx.low_reg, rl_obj.low_reg, count_offset);
+ OpCondBranch(kCondUge, launch_pad);
+ }
}
reg_off = AllocTemp();
reg_ptr = AllocTemp();
LoadWordDisp(rl_obj.low_reg, offset_offset, reg_off);
LoadWordDisp(rl_obj.low_reg, value_offset, reg_ptr);
}
- OpRegImm(kOpAdd, reg_ptr, data_offset);
- OpRegReg(kOpAdd, reg_off, rl_idx.low_reg);
+ if (rl_idx.is_const) {
+ OpRegImm(kOpAdd, reg_off, mir_graph_->ConstantValue(rl_idx.orig_sreg));
+ } else {
+ OpRegReg(kOpAdd, reg_off, rl_idx.low_reg);
+ }
FreeTemp(rl_obj.low_reg);
- FreeTemp(rl_idx.low_reg);
+ if (rl_idx.low_reg != INVALID_REG) {
+ FreeTemp(rl_idx.low_reg);
+ }
RegLocation rl_dest = InlineTarget(info);
RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
- LoadBaseIndexed(reg_ptr, reg_off, rl_result.low_reg, 1, kUnsignedHalf);
+ if (cu_->instruction_set != kX86) {
+ LoadBaseIndexed(reg_ptr, reg_off, rl_result.low_reg, 1, kUnsignedHalf);
+ } else {
+ LoadBaseIndexedDisp(reg_ptr, reg_off, 1, data_offset, rl_result.low_reg,
+ INVALID_REG, kUnsignedHalf, INVALID_SREG);
+ }
FreeTemp(reg_off);
FreeTemp(reg_ptr);
StoreValue(rl_dest, rl_result);
@@ -1094,7 +1087,7 @@
return false;
}
RegLocation rl_src_i = info->args[0];
- RegLocation rl_dest = InlineTarget(info); // result reg
+ RegLocation rl_dest = (size == kLong) ? InlineTargetWide(info) : InlineTarget(info); // result reg
RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
if (size == kLong) {
RegLocation rl_i = LoadValueWide(rl_src_i, kCoreReg);
@@ -1179,6 +1172,43 @@
}
}
+bool Mir2Lir::GenInlinedAbsFloat(CallInfo* info) {
+ if (cu_->instruction_set == kMips) {
+ // TODO - add Mips implementation
+ return false;
+ }
+ RegLocation rl_src = info->args[0];
+ rl_src = LoadValue(rl_src, kCoreReg);
+ RegLocation rl_dest = InlineTarget(info);
+ RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
+ int signMask = AllocTemp();
+ LoadConstant(signMask, 0x7fffffff);
+ OpRegRegReg(kOpAnd, rl_result.low_reg, rl_src.low_reg, signMask);
+ FreeTemp(signMask);
+ StoreValue(rl_dest, rl_result);
+ return true;
+}
+
+bool Mir2Lir::GenInlinedAbsDouble(CallInfo* info) {
+ if (cu_->instruction_set == kMips) {
+ // TODO - add Mips implementation
+ return false;
+ }
+ RegLocation rl_src = info->args[0];
+ rl_src = LoadValueWide(rl_src, kCoreReg);
+ RegLocation rl_dest = InlineTargetWide(info);
+ RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
+ OpRegCopyWide(rl_result.low_reg, rl_result.high_reg, rl_src.low_reg, rl_src.high_reg);
+ FreeTemp(rl_src.low_reg);
+ FreeTemp(rl_src.high_reg);
+ int signMask = AllocTemp();
+ LoadConstant(signMask, 0x7fffffff);
+ OpRegReg(kOpAnd, rl_result.high_reg, signMask);
+ FreeTemp(signMask);
+ StoreValueWide(rl_dest, rl_result);
+ return true;
+}
+
bool Mir2Lir::GenInlinedFloatCvt(CallInfo* info) {
if (cu_->instruction_set == kMips) {
// TODO - add Mips implementation
@@ -1308,7 +1338,7 @@
RegLocation rl_src_obj = info->args[1]; // Object
RegLocation rl_src_offset = info->args[2]; // long low
rl_src_offset.wide = 0; // ignore high half in info->args[3]
- RegLocation rl_dest = InlineTarget(info); // result reg
+ RegLocation rl_dest = is_long ? InlineTargetWide(info) : InlineTarget(info); // result reg
if (is_volatile) {
GenMemBarrier(kLoadLoad);
}
@@ -1436,8 +1466,15 @@
call_inst = OpReg(kOpBlx, TargetReg(kInvokeTgt));
} else {
if (fast_path) {
- call_inst = OpMem(kOpBlx, TargetReg(kArg0),
- mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value());
+ if (direct_code == static_cast<unsigned int>(-1)) {
+ // We can have the linker fixup a call relative.
+ call_inst =
+ reinterpret_cast<X86Mir2Lir*>(this)->CallWithLinkerFixup(
+ target_method.dex_method_index, info->type);
+ } else {
+ call_inst = OpMem(kOpBlx, TargetReg(kArg0),
+ mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value());
+ }
} else {
ThreadOffset trampoline(-1);
switch (info->type) {
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index 3a68044..6115953 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -417,7 +417,7 @@
bool EvaluateBranch(Instruction::Code opcode, int src1, int src2);
bool IsInexpensiveConstant(RegLocation rl_src);
ConditionCode FlipComparisonOrder(ConditionCode before);
- void InstallLiteralPools();
+ virtual void InstallLiteralPools();
void InstallSwitchTables();
void InstallFillArrayData();
bool VerifyCatchEntries();
@@ -663,6 +663,8 @@
bool GenInlinedReverseBytes(CallInfo* info, OpSize size);
bool GenInlinedAbsInt(CallInfo* info);
bool GenInlinedAbsLong(CallInfo* info);
+ bool GenInlinedAbsFloat(CallInfo* info);
+ bool GenInlinedAbsDouble(CallInfo* info);
bool GenInlinedFloatCvt(CallInfo* info);
bool GenInlinedDoubleCvt(CallInfo* info);
bool GenInlinedIndexOf(CallInfo* info, bool zero_based);
@@ -737,6 +739,34 @@
void SpecialMIR2LIR(const InlineMethod& special);
void MethodMIR2LIR();
+ /*
+ * @brief Load the address of the dex method into the register.
+ * @param dex_method_index The index of the method to be invoked.
+ * @param type How the method will be invoked.
+ * @param register that will contain the code address.
+ * @note register will be passed to TargetReg to get physical register.
+ */
+ void LoadCodeAddress(int dex_method_index, InvokeType type,
+ SpecialTargetRegister symbolic_reg);
+
+ /*
+ * @brief Load the Method* of a dex method into the register.
+ * @param dex_method_index The index of the method to be invoked.
+ * @param type How the method will be invoked.
+ * @param register that will contain the code address.
+ * @note register will be passed to TargetReg to get physical register.
+ */
+ virtual void LoadMethodAddress(int dex_method_index, InvokeType type,
+ SpecialTargetRegister symbolic_reg);
+
+ /*
+ * @brief Load the Class* of a Dex Class type into the register.
+ * @param type How the method will be invoked.
+ * @param register that will contain the code address.
+ * @note register will be passed to TargetReg to get physical register.
+ */
+ virtual void LoadClassType(uint32_t type_idx, SpecialTargetRegister symbolic_reg);
+
// Routines that work for the generic case, but may be overriden by target.
/*
* @brief Compare memory to immediate, and branch if condition true.
@@ -1046,13 +1076,13 @@
void AddSlowPath(LIRSlowPath* slowpath);
- private:
- void GenInstanceofCallingHelper(bool needs_access_check, bool type_known_final,
- bool type_known_abstract, bool use_declaring_class,
- bool can_assume_type_is_in_dex_cache,
- uint32_t type_idx, RegLocation rl_dest,
- RegLocation rl_src);
+ virtual void GenInstanceofCallingHelper(bool needs_access_check, bool type_known_final,
+ bool type_known_abstract, bool use_declaring_class,
+ bool can_assume_type_is_in_dex_cache,
+ uint32_t type_idx, RegLocation rl_dest,
+ RegLocation rl_src);
+ private:
void ClobberBody(RegisterInfo* p);
void ResetDefBody(RegisterInfo* p) {
p->def_start = NULL;
diff --git a/compiler/dex/quick/x86/assemble_x86.cc b/compiler/dex/quick/x86/assemble_x86.cc
index ae53ddb..321c6a7 100644
--- a/compiler/dex/quick/x86/assemble_x86.cc
+++ b/compiler/dex/quick/x86/assemble_x86.cc
@@ -354,6 +354,7 @@
{ kX86CallM, kCall, IS_BINARY_OP | IS_BRANCH | IS_LOAD | REG_USE0, { 0, 0, 0xFF, 0, 0, 2, 0, 0 }, "CallM", "[!0r+!1d]" },
{ kX86CallA, kCall, IS_QUAD_OP | IS_BRANCH | IS_LOAD | REG_USE01, { 0, 0, 0xFF, 0, 0, 2, 0, 0 }, "CallA", "[!0r+!1r<<!2d+!3d]" },
{ kX86CallT, kCall, IS_UNARY_OP | IS_BRANCH | IS_LOAD, { THREAD_PREFIX, 0, 0xFF, 0, 0, 2, 0, 0 }, "CallT", "fs:[!0d]" },
+ { kX86CallI, kCall, IS_UNARY_OP | IS_BRANCH, { 0, 0, 0xE8, 0, 0, 0, 0, 4 }, "CallI", "!0d" },
{ kX86Ret, kNullary, NO_OPERAND | IS_BRANCH, { 0, 0, 0xC3, 0, 0, 0, 0, 0 }, "Ret", "" },
{ kX86StartOfMethod, kMacro, IS_UNARY_OP | SETS_CCODES, { 0, 0, 0, 0, 0, 0, 0, 0 }, "StartOfMethod", "!0r" },
@@ -494,6 +495,7 @@
}
case kCall:
switch (lir->opcode) {
+ case kX86CallI: return 5; // opcode 0:disp
case kX86CallR: return 2; // opcode modrm
case kX86CallM: // lir operands - 0: base, 1: disp
return ComputeSize(entry, lir->operands[0], lir->operands[1], false);
@@ -985,6 +987,16 @@
DCHECK_EQ(0, entry->skeleton.immediate_bytes);
}
+void X86Mir2Lir::EmitCallImmediate(const X86EncodingMap* entry, int disp) {
+ EmitPrefixAndOpcode(entry);
+ DCHECK_EQ(4, entry->skeleton.immediate_bytes);
+ code_buffer_.push_back(disp & 0xFF);
+ code_buffer_.push_back((disp >> 8) & 0xFF);
+ code_buffer_.push_back((disp >> 16) & 0xFF);
+ code_buffer_.push_back((disp >> 24) & 0xFF);
+ DCHECK_EQ(0, entry->skeleton.ax_opcode);
+}
+
void X86Mir2Lir::EmitCallThread(const X86EncodingMap* entry, int disp) {
DCHECK_NE(entry->skeleton.prefix1, 0);
EmitPrefixAndOpcode(entry);
@@ -1290,6 +1302,9 @@
break;
case kCall:
switch (entry->opcode) {
+ case kX86CallI: // lir operands - 0: disp
+ EmitCallImmediate(entry, lir->operands[0]);
+ break;
case kX86CallM: // lir operands - 0: base, 1: disp
EmitCallMem(entry, lir->operands[0], lir->operands[1]);
break;
@@ -1375,6 +1390,13 @@
*/
void X86Mir2Lir::AssembleLIR() {
cu_->NewTimingSplit("Assemble");
+
+ // We will remove the method address if we never ended up using it
+ if (store_method_addr_ && !store_method_addr_used_) {
+ setup_method_address_[0]->flags.is_nop = true;
+ setup_method_address_[1]->flags.is_nop = true;
+ }
+
AssignOffsets();
int assembler_retries = 0;
/*
diff --git a/compiler/dex/quick/x86/call_x86.cc b/compiler/dex/quick/x86/call_x86.cc
index 93875c9..7f646e0 100644
--- a/compiler/dex/quick/x86/call_x86.cc
+++ b/compiler/dex/quick/x86/call_x86.cc
@@ -93,6 +93,7 @@
RegLocation rl_method = mir_graph_->GetRegLocation(base_of_code_->s_reg_low);
rl_method = LoadValue(rl_method, kCoreReg);
start_of_method_reg = rl_method.low_reg;
+ store_method_addr_used_ = true;
} else {
start_of_method_reg = AllocTemp();
NewLIR1(kX86StartOfMethod, start_of_method_reg);
@@ -155,6 +156,7 @@
// We can use the saved value.
RegLocation rl_method = mir_graph_->GetRegLocation(base_of_code_->s_reg_low);
LoadValueDirect(rl_method, rX86_ARG2);
+ store_method_addr_used_ = true;
} else {
NewLIR1(kX86StartOfMethod, rX86_ARG2);
}
@@ -228,9 +230,9 @@
if (base_of_code_ != nullptr) {
// We have been asked to save the address of the method start for later use.
- NewLIR1(kX86StartOfMethod, rX86_ARG0);
+ setup_method_address_[0] = NewLIR1(kX86StartOfMethod, rX86_ARG0);
int displacement = SRegOffset(base_of_code_->s_reg_low);
- StoreBaseDisp(rX86_SP, displacement, rX86_ARG0, kWord);
+ setup_method_address_[1] = StoreBaseDisp(rX86_SP, displacement, rX86_ARG0, kWord);
}
FreeTemp(rX86_ARG0);
diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h
index 4c1c171..22e36d5 100644
--- a/compiler/dex/quick/x86/codegen_x86.h
+++ b/compiler/dex/quick/x86/codegen_x86.h
@@ -189,6 +189,24 @@
*/
void GenInstanceofFinal(bool use_declaring_class, uint32_t type_idx,
RegLocation rl_dest, RegLocation rl_src);
+ /*
+ *
+ * @brief Implement Set up instanceof a class with x86 specific code.
+ * @param needs_access_check 'true' if we must check the access.
+ * @param type_known_final 'true' if the type is known to be a final class.
+ * @param type_known_abstract 'true' if the type is known to be an abstract class.
+ * @param use_declaring_class 'true' if the type can be loaded off the current Method*.
+ * @param can_assume_type_is_in_dex_cache 'true' if the type is known to be in the cache.
+ * @param type_idx Type index to use if use_declaring_class is 'false'.
+ * @param rl_dest Result to be set to 0 or 1.
+ * @param rl_src Object to be tested.
+ */
+ void GenInstanceofCallingHelper(bool needs_access_check, bool type_known_final,
+ bool type_known_abstract, bool use_declaring_class,
+ bool can_assume_type_is_in_dex_cache,
+ uint32_t type_idx, RegLocation rl_dest,
+ RegLocation rl_src);
+
// Single operation generators.
LIR* OpUnconditionalBranch(LIR* target);
LIR* OpCmpBranch(ConditionCode cond, int src1, int src2, LIR* target);
@@ -245,6 +263,43 @@
void GenArithOpInt(Instruction::Code opcode, RegLocation rl_dest,
RegLocation rl_lhs, RegLocation rl_rhs);
+ /*
+ * @brief Dump a RegLocation using printf
+ * @param loc Register location to dump
+ */
+ static void DumpRegLocation(RegLocation loc);
+
+ /*
+ * @brief Load the Method* of a dex method into the register.
+ * @param dex_method_index The index of the method to be invoked.
+ * @param type How the method will be invoked.
+ * @param register that will contain the code address.
+ * @note register will be passed to TargetReg to get physical register.
+ */
+ void LoadMethodAddress(int dex_method_index, InvokeType type,
+ SpecialTargetRegister symbolic_reg);
+
+ /*
+ * @brief Load the Class* of a Dex Class type into the register.
+ * @param type How the method will be invoked.
+ * @param register that will contain the code address.
+ * @note register will be passed to TargetReg to get physical register.
+ */
+ void LoadClassType(uint32_t type_idx, SpecialTargetRegister symbolic_reg);
+
+ /*
+ * @brief Generate a relative call to the method that will be patched at link time.
+ * @param dex_method_index The index of the method to be invoked.
+ * @param type How the method will be invoked.
+ * @returns Call instruction
+ */
+ LIR * CallWithLinkerFixup(int dex_method_index, InvokeType type);
+
+ /*
+ * @brief Handle x86 specific literals
+ */
+ void InstallLiteralPools();
+
private:
void EmitPrefix(const X86EncodingMap* entry);
void EmitOpcode(const X86EncodingMap* entry);
@@ -290,6 +345,7 @@
void EmitJmp(const X86EncodingMap* entry, int rel);
void EmitJcc(const X86EncodingMap* entry, int rel, uint8_t cc);
void EmitCallMem(const X86EncodingMap* entry, uint8_t base, int disp);
+ void EmitCallImmediate(const X86EncodingMap* entry, int disp);
void EmitCallThread(const X86EncodingMap* entry, int disp);
void EmitPcRel(const X86EncodingMap* entry, uint8_t reg, int base_or_table, uint8_t index,
int scale, int table_or_disp);
@@ -330,12 +386,6 @@
*/
bool IsNoOp(Instruction::Code op, int32_t value);
- /*
- * @brief Dump a RegLocation using printf
- * @param loc Register location to dump
- */
- static void DumpRegLocation(RegLocation loc);
-
/**
* @brief Calculate magic number and shift for a given divisor
* @param divisor divisor number for calculation
@@ -459,11 +509,26 @@
// Information derived from analysis of MIR
+ // The compiler temporary for the code address of the method.
+ CompilerTemp *base_of_code_;
+
// Have we decided to compute a ptr to code and store in temporary VR?
bool store_method_addr_;
- // The compiler temporary for the code address of the method.
- CompilerTemp *base_of_code_;
+ // Have we used the stored method address?
+ bool store_method_addr_used_;
+
+ // Instructions to remove if we didn't use the stored method address.
+ LIR* setup_method_address_[2];
+
+ // Instructions needing patching with Method* values.
+ GrowableArray<LIR*> method_address_insns_;
+
+ // Instructions needing patching with Class Type* values.
+ GrowableArray<LIR*> class_type_address_insns_;
+
+ // Instructions needing patching with PC relative code addresses.
+ GrowableArray<LIR*> call_method_insns_;
};
} // namespace art
diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc
index a567a8a..9dd6116 100644
--- a/compiler/dex/quick/x86/int_x86.cc
+++ b/compiler/dex/quick/x86/int_x86.cc
@@ -670,7 +670,7 @@
bool X86Mir2Lir::GenInlinedPeek(CallInfo* info, OpSize size) {
RegLocation rl_src_address = info->args[0]; // long address
rl_src_address.wide = 0; // ignore high half in info->args[1]
- RegLocation rl_dest = InlineTarget(info);
+ RegLocation rl_dest = size == kLong ? InlineTargetWide(info) : InlineTarget(info);
RegLocation rl_address = LoadValue(rl_src_address, kCoreReg);
RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
if (size == kLong) {
@@ -780,8 +780,23 @@
}
LIR* X86Mir2Lir::OpPcRelLoad(int reg, LIR* target) {
- LOG(FATAL) << "Unexpected use of OpPcRelLoad for x86";
- return NULL;
+ CHECK(base_of_code_ != nullptr);
+
+ // Address the start of the method
+ RegLocation rl_method = mir_graph_->GetRegLocation(base_of_code_->s_reg_low);
+ LoadValueDirectFixed(rl_method, reg);
+ store_method_addr_used_ = true;
+
+ // Load the proper value from the literal area.
+ // We don't know the proper offset for the value, so pick one that will force
+ // 4 byte offset. We will fix this up in the assembler later to have the right
+ // value.
+ LIR *res = RawLIR(current_dalvik_offset_, kX86Mov32RM, reg, reg, 256, 0, 0, target);
+ res->target = target;
+ res->flags.fixup = kFixupLoad;
+ SetMemRefType(res, true, kLiteral);
+ store_method_addr_used_ = true;
+ return res;
}
LIR* X86Mir2Lir::OpVldm(int rBase, int count) {
@@ -1717,6 +1732,88 @@
StoreValue(rl_dest, rl_result);
}
+void X86Mir2Lir::GenInstanceofCallingHelper(bool needs_access_check, bool type_known_final,
+ bool type_known_abstract, bool use_declaring_class,
+ bool can_assume_type_is_in_dex_cache,
+ uint32_t type_idx, RegLocation rl_dest,
+ RegLocation rl_src) {
+ FlushAllRegs();
+ // May generate a call - use explicit registers.
+ LockCallTemps();
+ LoadCurrMethodDirect(TargetReg(kArg1)); // kArg1 gets current Method*.
+ int class_reg = TargetReg(kArg2); // kArg2 will hold the Class*.
+ // Reference must end up in kArg0.
+ if (needs_access_check) {
+ // Check we have access to type_idx and if not throw IllegalAccessError,
+ // Caller function returns Class* in kArg0.
+ CallRuntimeHelperImm(QUICK_ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccess),
+ type_idx, true);
+ OpRegCopy(class_reg, TargetReg(kRet0));
+ LoadValueDirectFixed(rl_src, TargetReg(kArg0));
+ } else if (use_declaring_class) {
+ LoadValueDirectFixed(rl_src, TargetReg(kArg0));
+ LoadWordDisp(TargetReg(kArg1),
+ mirror::ArtMethod::DeclaringClassOffset().Int32Value(), class_reg);
+ } else {
+ // Load dex cache entry into class_reg (kArg2).
+ LoadValueDirectFixed(rl_src, TargetReg(kArg0));
+ LoadWordDisp(TargetReg(kArg1),
+ mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(), class_reg);
+ int32_t offset_of_type =
+ mirror::Array::DataOffset(sizeof(mirror::Class*)).Int32Value() + (sizeof(mirror::Class*)
+ * type_idx);
+ LoadWordDisp(class_reg, offset_of_type, class_reg);
+ if (!can_assume_type_is_in_dex_cache) {
+ // Need to test presence of type in dex cache at runtime.
+ LIR* hop_branch = OpCmpImmBranch(kCondNe, class_reg, 0, NULL);
+ // Type is not resolved. Call out to helper, which will return resolved type in kRet0/kArg0.
+ CallRuntimeHelperImm(QUICK_ENTRYPOINT_OFFSET(pInitializeType), type_idx, true);
+ OpRegCopy(TargetReg(kArg2), TargetReg(kRet0)); // Align usage with fast path.
+ LoadValueDirectFixed(rl_src, TargetReg(kArg0)); /* Reload Ref. */
+ // Rejoin code paths
+ LIR* hop_target = NewLIR0(kPseudoTargetLabel);
+ hop_branch->target = hop_target;
+ }
+ }
+ /* kArg0 is ref, kArg2 is class. If ref==null, use directly as bool result. */
+ RegLocation rl_result = GetReturn(false);
+
+ // SETcc only works with EAX..EDX.
+ DCHECK_LT(rl_result.low_reg, 4);
+
+ // Is the class NULL?
+ LIR* branch1 = OpCmpImmBranch(kCondEq, TargetReg(kArg0), 0, NULL);
+
+ /* Load object->klass_. */
+ DCHECK_EQ(mirror::Object::ClassOffset().Int32Value(), 0);
+ LoadWordDisp(TargetReg(kArg0), mirror::Object::ClassOffset().Int32Value(), TargetReg(kArg1));
+ /* kArg0 is ref, kArg1 is ref->klass_, kArg2 is class. */
+ LIR* branchover = nullptr;
+ if (type_known_final) {
+ // Ensure top 3 bytes of result are 0.
+ LoadConstant(rl_result.low_reg, 0);
+ OpRegReg(kOpCmp, TargetReg(kArg1), TargetReg(kArg2));
+ // Set the low byte of the result to 0 or 1 from the compare condition code.
+ NewLIR2(kX86Set8R, rl_result.low_reg, kX86CondEq);
+ } else {
+ if (!type_known_abstract) {
+ LoadConstant(rl_result.low_reg, 1); // Assume result succeeds.
+ branchover = OpCmpBranch(kCondEq, TargetReg(kArg1), TargetReg(kArg2), NULL);
+ }
+ OpRegCopy(TargetReg(kArg0), TargetReg(kArg2));
+ OpThreadMem(kOpBlx, QUICK_ENTRYPOINT_OFFSET(pInstanceofNonTrivial));
+ }
+ // TODO: only clobber when type isn't final?
+ ClobberCallerSave();
+ /* Branch targets here. */
+ LIR* target = NewLIR0(kPseudoTargetLabel);
+ StoreValue(rl_dest, rl_result);
+ branch1->target = target;
+ if (branchover != nullptr) {
+ branchover->target = target;
+ }
+}
+
void X86Mir2Lir::GenArithOpInt(Instruction::Code opcode, RegLocation rl_dest,
RegLocation rl_lhs, RegLocation rl_rhs) {
OpKind op = kOpBkpt;
diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc
index a347d8b..1893ffc 100644
--- a/compiler/dex/quick/x86/target_x86.cc
+++ b/compiler/dex/quick/x86/target_x86.cc
@@ -510,7 +510,11 @@
}
X86Mir2Lir::X86Mir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena)
- : Mir2Lir(cu, mir_graph, arena) {
+ : Mir2Lir(cu, mir_graph, arena),
+ method_address_insns_(arena, 100, kGrowableArrayMisc),
+ class_type_address_insns_(arena, 100, kGrowableArrayMisc),
+ call_method_insns_(arena, 100, kGrowableArrayMisc) {
+ store_method_addr_used_ = false;
for (int i = 0; i < kX86Last; i++) {
if (X86Mir2Lir::EncodingMap[i].opcode != i) {
LOG(FATAL) << "Encoding order for " << X86Mir2Lir::EncodingMap[i].name
@@ -816,4 +820,104 @@
Mir2Lir::Materialize();
}
+void X86Mir2Lir::LoadMethodAddress(int dex_method_index, InvokeType type,
+ SpecialTargetRegister symbolic_reg) {
+ /*
+ * For x86, just generate a 32 bit move immediate instruction, that will be filled
+ * in at 'link time'. For now, put a unique value based on target to ensure that
+ * code deduplication works.
+ */
+ const DexFile::MethodId& id = cu_->dex_file->GetMethodId(dex_method_index);
+ uintptr_t ptr = reinterpret_cast<uintptr_t>(&id);
+
+ // Generate the move instruction with the unique pointer and save index and type.
+ LIR *move = RawLIR(current_dalvik_offset_, kX86Mov32RI, TargetReg(symbolic_reg),
+ static_cast<int>(ptr), dex_method_index, type);
+ AppendLIR(move);
+ method_address_insns_.Insert(move);
+}
+
+void X86Mir2Lir::LoadClassType(uint32_t type_idx, SpecialTargetRegister symbolic_reg) {
+ /*
+ * For x86, just generate a 32 bit move immediate instruction, that will be filled
+ * in at 'link time'. For now, put a unique value based on target to ensure that
+ * code deduplication works.
+ */
+ const DexFile::TypeId& id = cu_->dex_file->GetTypeId(type_idx);
+ uintptr_t ptr = reinterpret_cast<uintptr_t>(&id);
+
+ // Generate the move instruction with the unique pointer and save index and type.
+ LIR *move = RawLIR(current_dalvik_offset_, kX86Mov32RI, TargetReg(symbolic_reg),
+ static_cast<int>(ptr), type_idx);
+ AppendLIR(move);
+ class_type_address_insns_.Insert(move);
+}
+
+LIR *X86Mir2Lir::CallWithLinkerFixup(int dex_method_index, InvokeType type) {
+ /*
+ * For x86, just generate a 32 bit call relative instruction, that will be filled
+ * in at 'link time'. For now, put a unique value based on target to ensure that
+ * code deduplication works.
+ */
+ const DexFile::MethodId& id = cu_->dex_file->GetMethodId(dex_method_index);
+ uintptr_t ptr = reinterpret_cast<uintptr_t>(&id);
+
+ // Generate the call instruction with the unique pointer and save index and type.
+ LIR *call = RawLIR(current_dalvik_offset_, kX86CallI, static_cast<int>(ptr), dex_method_index,
+ type);
+ AppendLIR(call);
+ call_method_insns_.Insert(call);
+ return call;
+}
+
+void X86Mir2Lir::InstallLiteralPools() {
+ // These are handled differently for x86.
+ DCHECK(code_literal_list_ == nullptr);
+ DCHECK(method_literal_list_ == nullptr);
+ DCHECK(class_literal_list_ == nullptr);
+
+ // Handle the fixups for methods.
+ for (uint32_t i = 0; i < method_address_insns_.Size(); i++) {
+ LIR* p = method_address_insns_.Get(i);
+ DCHECK_EQ(p->opcode, kX86Mov32RI);
+ uint32_t target = p->operands[2];
+
+ // The offset to patch is the last 4 bytes of the instruction.
+ int patch_offset = p->offset + p->flags.size - 4;
+ cu_->compiler_driver->AddMethodPatch(cu_->dex_file, cu_->class_def_idx,
+ cu_->method_idx, cu_->invoke_type,
+ target, static_cast<InvokeType>(p->operands[3]),
+ patch_offset);
+ }
+
+ // Handle the fixups for class types.
+ for (uint32_t i = 0; i < class_type_address_insns_.Size(); i++) {
+ LIR* p = class_type_address_insns_.Get(i);
+ DCHECK_EQ(p->opcode, kX86Mov32RI);
+ uint32_t target = p->operands[2];
+
+ // The offset to patch is the last 4 bytes of the instruction.
+ int patch_offset = p->offset + p->flags.size - 4;
+ cu_->compiler_driver->AddClassPatch(cu_->dex_file, cu_->class_def_idx,
+ cu_->method_idx, target, patch_offset);
+ }
+
+ // And now the PC-relative calls to methods.
+ for (uint32_t i = 0; i < call_method_insns_.Size(); i++) {
+ LIR* p = call_method_insns_.Get(i);
+ DCHECK_EQ(p->opcode, kX86CallI);
+ uint32_t target = p->operands[1];
+
+ // The offset to patch is the last 4 bytes of the instruction.
+ int patch_offset = p->offset + p->flags.size - 4;
+ cu_->compiler_driver->AddRelativeCodePatch(cu_->dex_file, cu_->class_def_idx,
+ cu_->method_idx, cu_->invoke_type, target,
+ static_cast<InvokeType>(p->operands[2]),
+ patch_offset, -4 /* offset */);
+ }
+
+ // And do the normal processing.
+ Mir2Lir::InstallLiteralPools();
+}
+
} // namespace art
diff --git a/compiler/dex/quick/x86/utility_x86.cc b/compiler/dex/quick/x86/utility_x86.cc
index e2744d0..48a39bb 100644
--- a/compiler/dex/quick/x86/utility_x86.cc
+++ b/compiler/dex/quick/x86/utility_x86.cc
@@ -518,8 +518,7 @@
res->target = data_target;
res->flags.fixup = kFixupLoad;
SetMemRefType(res, true, kLiteral);
- // Redo after we assign target to ensure size is correct.
- SetupResourceMasks(res);
+ store_method_addr_used_ = true;
} else {
if (val_lo == 0) {
res = NewLIR2(kX86XorpsRR, r_dest_lo, r_dest_lo);
@@ -860,6 +859,7 @@
case Instruction::REM_DOUBLE_2ADDR:
AnalyzeFPInstruction(opcode, bb, mir);
break;
+
// Packed switches and array fills need a pointer to the base of the method.
case Instruction::FILL_ARRAY_DATA:
case Instruction::PACKED_SWITCH:
diff --git a/compiler/dex/quick/x86/x86_lir.h b/compiler/dex/quick/x86/x86_lir.h
index 6962ff7..c49f627 100644
--- a/compiler/dex/quick/x86/x86_lir.h
+++ b/compiler/dex/quick/x86/x86_lir.h
@@ -387,6 +387,7 @@
kX86CallA, // call [base + index * scale + disp]
// lir operands - 0: base, 1: index, 2: scale, 3: disp
kX86CallT, // call fs:[disp]; fs: is equal to Thread::Current(); lir operands - 0: disp
+ kX86CallI, // call <relative> - 0: disp; Used for core.oat linking only
kX86Ret, // ret; no lir operands
kX86StartOfMethod, // call 0; pop reg; sub reg, # - generate start of method into reg
// lir operands - 0: reg
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 5b9d66c..402d4f4 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -344,7 +344,7 @@
CompilerBackend compiler_backend, InstructionSet instruction_set,
InstructionSetFeatures instruction_set_features,
bool image, DescriptorSet* image_classes, size_t thread_count,
- bool dump_stats)
+ bool dump_stats, bool dump_passes, CumulativeLogger* timer)
: verification_results_(verification_results),
method_inliner_map_(method_inliner_map),
compiler_backend_(compiler_backend),
@@ -359,13 +359,15 @@
start_ns_(0),
stats_(new AOTCompilationStats),
dump_stats_(dump_stats),
+ dump_passes_(dump_passes),
+ timings_logger_(timer),
compiler_library_(NULL),
compiler_(NULL),
compiler_context_(NULL),
jni_compiler_(NULL),
compiler_enable_auto_elf_loading_(NULL),
compiler_get_method_code_addr_(NULL),
- support_boot_image_fixup_(instruction_set == kThumb2),
+ support_boot_image_fixup_(instruction_set != kMips),
dedupe_code_("dedupe code"),
dedupe_mapping_table_("dedupe mapping table"),
dedupe_vmap_table_("dedupe vmap table"),
@@ -1396,6 +1398,24 @@
target_invoke_type,
literal_offset));
}
+void CompilerDriver::AddRelativeCodePatch(const DexFile* dex_file,
+ uint16_t referrer_class_def_idx,
+ uint32_t referrer_method_idx,
+ InvokeType referrer_invoke_type,
+ uint32_t target_method_idx,
+ InvokeType target_invoke_type,
+ size_t literal_offset,
+ int32_t pc_relative_offset) {
+ MutexLock mu(Thread::Current(), compiled_methods_lock_);
+ code_to_patch_.push_back(new RelativeCallPatchInformation(dex_file,
+ referrer_class_def_idx,
+ referrer_method_idx,
+ referrer_invoke_type,
+ target_method_idx,
+ target_invoke_type,
+ literal_offset,
+ pc_relative_offset));
+}
void CompilerDriver::AddMethodPatch(const DexFile* dex_file,
uint16_t referrer_class_def_idx,
uint32_t referrer_method_idx,
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index ea43e4f..c4ac9db 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -22,6 +22,7 @@
#include <vector>
#include "base/mutex.h"
+#include "base/timing_logger.h"
#include "class_reference.h"
#include "compiled_class.h"
#include "compiled_method.h"
@@ -103,7 +104,8 @@
CompilerBackend compiler_backend, InstructionSet instruction_set,
InstructionSetFeatures instruction_set_features,
bool image, DescriptorSet* image_classes,
- size_t thread_count, bool dump_stats);
+ size_t thread_count, bool dump_stats, bool dump_passes,
+ CumulativeLogger* timer);
~CompilerDriver();
@@ -238,6 +240,15 @@
InvokeType target_invoke_type,
size_t literal_offset)
LOCKS_EXCLUDED(compiled_methods_lock_);
+ void AddRelativeCodePatch(const DexFile* dex_file,
+ uint16_t referrer_class_def_idx,
+ uint32_t referrer_method_idx,
+ InvokeType referrer_invoke_type,
+ uint32_t target_method_idx,
+ InvokeType target_invoke_type,
+ size_t literal_offset,
+ int32_t pc_relative_offset)
+ LOCKS_EXCLUDED(compiled_methods_lock_);
void AddMethodPatch(const DexFile* dex_file,
uint16_t referrer_class_def_idx,
uint32_t referrer_method_idx,
@@ -293,6 +304,15 @@
class CallPatchInformation;
class TypePatchInformation;
+
+ bool GetDumpPasses() const {
+ return dump_passes_;
+ }
+
+ CumulativeLogger& GetTimingsLogger() const {
+ return *timings_logger_;
+ }
+
class PatchInformation {
public:
const DexFile& GetDexFile() const {
@@ -362,8 +382,14 @@
bool IsCall() const {
return true;
}
+ virtual bool IsRelative() const {
+ return false;
+ }
+ virtual int RelativeOffset() const {
+ return 0;
+ }
- private:
+ protected:
CallPatchInformation(const DexFile* dex_file,
uint16_t referrer_class_def_idx,
uint32_t referrer_method_idx,
@@ -378,6 +404,7 @@
target_invoke_type_(target_invoke_type) {
}
+ private:
const InvokeType referrer_invoke_type_;
const uint32_t target_method_idx_;
const InvokeType target_invoke_type_;
@@ -386,6 +413,36 @@
DISALLOW_COPY_AND_ASSIGN(CallPatchInformation);
};
+ class RelativeCallPatchInformation : public CallPatchInformation {
+ public:
+ bool IsRelative() const {
+ return true;
+ }
+ int RelativeOffset() const {
+ return offset_;
+ }
+
+ private:
+ RelativeCallPatchInformation(const DexFile* dex_file,
+ uint16_t referrer_class_def_idx,
+ uint32_t referrer_method_idx,
+ InvokeType referrer_invoke_type,
+ uint32_t target_method_idx,
+ InvokeType target_invoke_type,
+ size_t literal_offset,
+ int32_t pc_relative_offset)
+ : CallPatchInformation(dex_file, referrer_class_def_idx,
+ referrer_method_idx, referrer_invoke_type,
+ target_method_idx, target_invoke_type, literal_offset),
+ offset_(pc_relative_offset) {
+ }
+
+ const int offset_;
+
+ friend class CompilerDriver;
+ DISALLOW_COPY_AND_ASSIGN(RelativeCallPatchInformation);
+ };
+
class TypePatchInformation : public PatchInformation {
public:
uint32_t GetTargetTypeIdx() const {
@@ -535,6 +592,9 @@
UniquePtr<AOTCompilationStats> stats_;
bool dump_stats_;
+ const bool dump_passes_;
+
+ CumulativeLogger* const timings_logger_;
typedef void (*CompilerCallbackFn)(CompilerDriver& driver);
typedef MutexLock* (*CompilerMutexLockFn)(CompilerDriver& driver);
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index 67cd51b..e5dfb9d 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -785,7 +785,19 @@
uintptr_t quick_code = reinterpret_cast<uintptr_t>(class_linker->GetQuickOatCodeFor(target));
uintptr_t code_base = reinterpret_cast<uintptr_t>(&oat_file_->GetOatHeader());
uintptr_t code_offset = quick_code - code_base;
- SetPatchLocation(patch, PointerToLowMemUInt32(GetOatAddress(code_offset)));
+ if (patch->IsRelative()) {
+ // value to patch is relative to the location being patched
+ const void* quick_oat_code =
+ class_linker->GetQuickOatCodeFor(patch->GetDexFile(),
+ patch->GetReferrerClassDefIdx(),
+ patch->GetReferrerMethodIdx());
+ uintptr_t base = reinterpret_cast<uintptr_t>(quick_oat_code);
+ uintptr_t patch_location = base + patch->GetLiteralOffset();
+ uintptr_t value = quick_code - patch_location + patch->RelativeOffset();
+ SetPatchLocation(patch, value);
+ } else {
+ SetPatchLocation(patch, PointerToLowMemUInt32(GetOatAddress(code_offset)));
+ }
}
const CallPatches& methods_to_patch = compiler_driver_.GetMethodsToPatch();
diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc
index b3070b6..f6b511c 100644
--- a/compiler/oat_test.cc
+++ b/compiler/oat_test.cc
@@ -91,10 +91,12 @@
verification_results_.reset(new VerificationResults);
method_inliner_map_.reset(compiler_backend == kQuick ? new DexFileToMethodInlinerMap : nullptr);
callbacks_.Reset(verification_results_.get(), method_inliner_map_.get());
+ timer_.reset(new CumulativeLogger("Compilation times"));
compiler_driver_.reset(new CompilerDriver(verification_results_.get(),
method_inliner_map_.get(),
compiler_backend, insn_set,
- insn_features, false, NULL, 2, true));
+ insn_features, false, NULL, 2, true, true,
+ timer_.get()));
jobject class_loader = NULL;
if (kCompile) {
TimingLogger timings("OatTest::WriteRead", false, false);
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 90eea5e..98c64aa 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -253,7 +253,9 @@
bool image,
UniquePtr<CompilerDriver::DescriptorSet>& image_classes,
bool dump_stats,
- TimingLogger& timings) {
+ bool dump_passes,
+ TimingLogger& timings,
+ CumulativeLogger& compiler_phases_timings) {
// SirtRef and ClassLoader creation needs to come after Runtime::Create
jobject class_loader = NULL;
Thread* self = Thread::Current();
@@ -280,7 +282,9 @@
image,
image_classes.release(),
thread_count_,
- dump_stats));
+ dump_stats,
+ dump_passes,
+ &compiler_phases_timings));
if (compiler_backend_ == kPortable) {
driver->SetBitcodeFileName(bitcode_filename);
@@ -654,6 +658,7 @@
static int dex2oat(int argc, char** argv) {
TimingLogger timings("compiler", false, false);
+ CumulativeLogger compiler_phases_timings("compilation times");
InitLogging(argv);
@@ -703,6 +708,7 @@
bool is_host = false;
bool dump_stats = false;
bool dump_timing = false;
+ bool dump_passes = false;
bool dump_slow_timing = kIsDebugBuild;
bool watch_dog_enabled = !kIsTargetBuild;
@@ -798,6 +804,8 @@
runtime_args.push_back(argv[i]);
} else if (option == "--dump-timing") {
dump_timing = true;
+ } else if (option == "--dump-passes") {
+ dump_passes = true;
} else if (option == "--dump-stats") {
dump_stats = true;
} else {
@@ -1069,7 +1077,9 @@
image,
image_classes,
dump_stats,
- timings));
+ dump_passes,
+ timings,
+ compiler_phases_timings));
if (compiler.get() == NULL) {
LOG(ERROR) << "Failed to create oat file: " << oat_location;
@@ -1145,6 +1155,9 @@
if (dump_timing || (dump_slow_timing && timings.GetTotalNs() > MsToNs(1000))) {
LOG(INFO) << Dumpable<TimingLogger>(timings);
}
+ if (dump_passes) {
+ LOG(INFO) << Dumpable<CumulativeLogger>(compiler.get()->GetTimingsLogger());
+ }
return EXIT_SUCCESS;
}
@@ -1187,6 +1200,9 @@
if (dump_timing || (dump_slow_timing && timings.GetTotalNs() > MsToNs(1000))) {
LOG(INFO) << Dumpable<TimingLogger>(timings);
}
+ if (dump_passes) {
+ LOG(INFO) << Dumpable<CumulativeLogger>(compiler_phases_timings);
+ }
// Everything was successfully written, do an explicit exit here to avoid running Runtime
// destructors that take time (bug 10645725) unless we're a debug build or running on valgrind.
diff --git a/runtime/common_test.h b/runtime/common_test.h
index daa2ff1..af7e8ae 100644
--- a/runtime/common_test.h
+++ b/runtime/common_test.h
@@ -480,12 +480,13 @@
}
}
class_linker_->FixupDexCaches(runtime_->GetResolutionMethod());
+ timer_.reset(new CumulativeLogger("Compilation times"));
compiler_driver_.reset(new CompilerDriver(verification_results_.get(),
method_inliner_map_.get(),
compiler_backend, instruction_set,
instruction_set_features,
true, new CompilerDriver::DescriptorSet,
- 2, true));
+ 2, true, true, timer_.get()));
}
// We typically don't generate an image in unit tests, disable this optimization by default.
compiler_driver_->SetSupportBootImageFixup(false);
@@ -530,6 +531,7 @@
(*icu_cleanup_fn)();
compiler_driver_.reset();
+ timer_.reset();
callbacks_.Reset(nullptr, nullptr);
method_inliner_map_.reset();
verification_results_.reset();
@@ -662,7 +664,7 @@
class TestCompilerCallbacks : public CompilerCallbacks {
public:
- TestCompilerCallbacks() : verification_results_(nullptr), method_inliner_map_(nullptr) { }
+ TestCompilerCallbacks() : verification_results_(nullptr), method_inliner_map_(nullptr) {}
void Reset(VerificationResults* verification_results,
DexFileToMethodInlinerMap* method_inliner_map) {
@@ -701,6 +703,7 @@
UniquePtr<DexFileToMethodInlinerMap> method_inliner_map_;
TestCompilerCallbacks callbacks_;
UniquePtr<CompilerDriver> compiler_driver_;
+ UniquePtr<CumulativeLogger> timer_;
private:
std::vector<const DexFile*> opened_dex_files_;
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index 0f380ad..00a8506 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -226,7 +226,7 @@
}
for (size_t i = 0; i < GetOatHeader().GetDexFileCount(); i++) {
- size_t dex_file_location_size = *reinterpret_cast<const uint32_t*>(oat);
+ uint32_t dex_file_location_size = *reinterpret_cast<const uint32_t*>(oat);
if (UNLIKELY(dex_file_location_size == 0U)) {
*error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd with empty location name",
GetLocation().c_str(), i);
diff --git a/runtime/runtime_linux.cc b/runtime/runtime_linux.cc
index d8f408a..73ac034 100644
--- a/runtime/runtime_linux.cc
+++ b/runtime/runtime_linux.cc
@@ -19,6 +19,7 @@
#include <signal.h>
#include <string.h>
#include <sys/utsname.h>
+#include <inttypes.h>
#include "base/logging.h"
#include "base/mutex.h"
@@ -185,6 +186,41 @@
os << '\n';
DumpRegister32(os, "gs", context.gregs[REG_GS]);
DumpRegister32(os, "ss", context.gregs[REG_SS]);
+#elif defined(__linux__) && defined(__x86_64__)
+ DumpRegister64(os, "rax", context.gregs[REG_RAX]);
+ DumpRegister64(os, "rbx", context.gregs[REG_RBX]);
+ DumpRegister64(os, "rcx", context.gregs[REG_RCX]);
+ DumpRegister64(os, "rdx", context.gregs[REG_RDX]);
+ os << '\n';
+
+ DumpRegister64(os, "rdi", context.gregs[REG_RDI]);
+ DumpRegister64(os, "rsi", context.gregs[REG_RSI]);
+ DumpRegister64(os, "rbp", context.gregs[REG_RBP]);
+ DumpRegister64(os, "rsp", context.gregs[REG_RSP]);
+ os << '\n';
+
+ DumpRegister64(os, "r8 ", context.gregs[REG_R8]);
+ DumpRegister64(os, "r9 ", context.gregs[REG_R9]);
+ DumpRegister64(os, "r10", context.gregs[REG_R10]);
+ DumpRegister64(os, "r11", context.gregs[REG_R11]);
+ os << '\n';
+
+ DumpRegister64(os, "r12", context.gregs[REG_R12]);
+ DumpRegister64(os, "r13", context.gregs[REG_R13]);
+ DumpRegister64(os, "r14", context.gregs[REG_R14]);
+ DumpRegister64(os, "r15", context.gregs[REG_R15]);
+ os << '\n';
+
+ DumpRegister64(os, "rip", context.gregs[REG_RIP]);
+ os << " ";
+ DumpRegister32(os, "eflags", context.gregs[REG_EFL]);
+ DumpX86Flags(os, context.gregs[REG_EFL]);
+ os << '\n';
+
+ DumpRegister32(os, "cs", (context.gregs[REG_CSGSFS]) & 0x0FFFF);
+ DumpRegister32(os, "gs", (context.gregs[REG_CSGSFS] >> 16) & 0x0FFFF);
+ DumpRegister32(os, "fs", (context.gregs[REG_CSGSFS] >> 32) & 0x0FFFF);
+ os << '\n';
#else
os << "Unknown architecture/word size/OS in ucontext dump";
#endif
@@ -194,6 +230,10 @@
os << StringPrintf(" %6s: 0x%08x", name, value);
}
+ void DumpRegister64(std::ostream& os, const char* name, uint64_t value) {
+ os << StringPrintf(" %6s: 0x%016" PRIx64, name, value);
+ }
+
void DumpX86Flags(std::ostream& os, uint32_t flags) {
os << " [";
if ((flags & (1 << 0)) != 0) {
diff --git a/test/051-thread/expected.txt b/test/051-thread/expected.txt
index 8e6b153..7139b7f 100644
--- a/test/051-thread/expected.txt
+++ b/test/051-thread/expected.txt
@@ -1,8 +1,9 @@
-Initializing System.out...
-Thread count: 512
-Starting thread 'Thready'
-@ Thread running
-@ Got expected setDaemon exception
-@ Thread bailing
-Thread starter returning
+thread test starting
+testThreadCapacity thread count: 512
+testThreadDaemons starting thread 'TestDaemonThread'
+testThreadDaemons @ Thread running
+testThreadDaemons @ Got expected setDaemon exception
+testThreadDaemons @ Thread bailing
+testThreadDaemons finished
+testSleepZero finished
thread test done
diff --git a/test/051-thread/src/Main.java b/test/051-thread/src/Main.java
index 911c739..608b7e0 100644
--- a/test/051-thread/src/Main.java
+++ b/test/051-thread/src/Main.java
@@ -21,50 +21,36 @@
*/
public class Main {
public static void main(String[] args) throws Exception {
- System.out.println("Initializing System.out...");
-
- MyThread[] threads = new MyThread[512];
- for (int i = 0; i < 512; i++) {
- threads[i] = new MyThread();
- }
-
- for (MyThread thread : threads) {
- thread.start();
- }
- for (MyThread thread : threads) {
- thread.join();
- }
-
- System.out.println("Thread count: " + MyThread.mCount);
-
- go();
+ System.out.println("thread test starting");
+ testThreadCapacity();
+ testThreadDaemons();
+ testSleepZero();
System.out.println("thread test done");
}
- public static void go() {
- Thread t = new Thread(null, new ThreadTestSub(), "Thready", 7168);
-
- t.setDaemon(false);
-
- System.out.print("Starting thread '" + t.getName() + "'\n");
- t.start();
-
- try {
- t.join();
- } catch (InterruptedException ex) {
- ex.printStackTrace();
- }
-
- System.out.print("Thread starter returning\n");
- }
-
/*
* Simple thread capacity test.
*/
- static class MyThread extends Thread {
+ private static void testThreadCapacity() throws Exception {
+ TestCapacityThread[] threads = new TestCapacityThread[512];
+ for (int i = 0; i < 512; i++) {
+ threads[i] = new TestCapacityThread();
+ }
+
+ for (TestCapacityThread thread : threads) {
+ thread.start();
+ }
+ for (TestCapacityThread thread : threads) {
+ thread.join();
+ }
+
+ System.out.println("testThreadCapacity thread count: " + TestCapacityThread.mCount);
+ }
+
+ private static class TestCapacityThread extends Thread {
static int mCount = 0;
public void run() {
- synchronized (MyThread.class) {
+ synchronized (TestCapacityThread.class) {
++mCount;
}
try {
@@ -73,29 +59,57 @@
}
}
}
-}
-class ThreadTestSub implements Runnable {
- public void run() {
- System.out.print("@ Thread running\n");
+ private static void testThreadDaemons() {
+ Thread t = new Thread(null, new TestDaemonThread(), "TestDaemonThread", 7168);
+
+ t.setDaemon(false);
+
+ System.out.print("testThreadDaemons starting thread '" + t.getName() + "'\n");
+ t.start();
try {
- Thread.currentThread().setDaemon(true);
- System.out.print("@ FAILED: setDaemon() succeeded\n");
- } catch (IllegalThreadStateException itse) {
- System.out.print("@ Got expected setDaemon exception\n");
+ t.join();
+ } catch (InterruptedException ex) {
+ ex.printStackTrace();
}
- //if (true)
- // throw new NullPointerException();
+ System.out.print("testThreadDaemons finished\n");
+ }
+
+ private static class TestDaemonThread implements Runnable {
+ public void run() {
+ System.out.print("testThreadDaemons @ Thread running\n");
+
+ try {
+ Thread.currentThread().setDaemon(true);
+ System.out.print("testThreadDaemons @ FAILED: setDaemon() succeeded\n");
+ } catch (IllegalThreadStateException itse) {
+ System.out.print("testThreadDaemons @ Got expected setDaemon exception\n");
+ }
+
+ try {
+ Thread.sleep(2000);
+ }
+ catch (InterruptedException ie) {
+ System.out.print("testThreadDaemons @ Interrupted!\n");
+ }
+ finally {
+ System.out.print("testThreadDaemons @ Thread bailing\n");
+ }
+ }
+ }
+
+ private static void testSleepZero() throws Exception {
+ Thread.currentThread().interrupt();
try {
- Thread.sleep(2000);
+ Thread.sleep(0);
+ throw new AssertionError("unreachable");
+ } catch (InterruptedException e) {
+ if (Thread.currentThread().isInterrupted()) {
+ throw new AssertionError("thread is interrupted");
+ }
}
- catch (InterruptedException ie) {
- System.out.print("@ Interrupted!\n");
- }
- finally {
- System.out.print("@ Thread bailing\n");
- }
+ System.out.print("testSleepZero finished\n");
}
}