Merge "ART: Add FdFile constructors"
diff --git a/compiler/Android.mk b/compiler/Android.mk
index 02c176c..2666835 100644
--- a/compiler/Android.mk
+++ b/compiler/Android.mk
@@ -75,6 +75,7 @@
optimizing/ssa_liveness_analysis.cc \
optimizing/ssa_phi_elimination.cc \
optimizing/stack_map_stream.cc \
+ optimizing/x86_memory_gen.cc \
trampolines/trampoline_compiler.cc \
utils/assembler.cc \
utils/swap_space.cc \
diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc
index 672018b..41b1960 100644
--- a/compiler/oat_test.cc
+++ b/compiler/oat_test.cc
@@ -444,7 +444,7 @@
EXPECT_EQ(72U, sizeof(OatHeader));
EXPECT_EQ(4U, sizeof(OatMethodOffsets));
EXPECT_EQ(20U, sizeof(OatQuickMethodHeader));
- EXPECT_EQ(133 * GetInstructionSetPointerSize(kRuntimeISA), sizeof(QuickEntryPoints));
+ EXPECT_EQ(164 * GetInstructionSetPointerSize(kRuntimeISA), sizeof(QuickEntryPoints));
}
TEST_F(OatTest, OatHeaderIsValid) {
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index 4520f9b..d40e2b9 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -314,7 +314,8 @@
void CodeGenerator::CreateCommonInvokeLocationSummary(
HInvoke* invoke, InvokeDexCallingConventionVisitor* visitor) {
ArenaAllocator* allocator = invoke->GetBlock()->GetGraph()->GetArena();
- LocationSummary* locations = new (allocator) LocationSummary(invoke, LocationSummary::kCall);
+ LocationSummary* locations = new (allocator) LocationSummary(invoke,
+ LocationSummary::kCallOnMainOnly);
for (size_t i = 0; i < invoke->GetNumberOfArguments(); i++) {
HInstruction* input = invoke->InputAt(i);
@@ -378,7 +379,7 @@
ArenaAllocator* allocator = field_access->GetBlock()->GetGraph()->GetArena();
LocationSummary* locations =
- new (allocator) LocationSummary(field_access, LocationSummary::kCall);
+ new (allocator) LocationSummary(field_access, LocationSummary::kCallOnMainOnly);
locations->AddTemp(calling_convention.GetFieldIndexLocation());
@@ -499,7 +500,7 @@
bool code_generator_supports_read_barrier) {
ArenaAllocator* allocator = cls->GetBlock()->GetGraph()->GetArena();
LocationSummary::CallKind call_kind = cls->NeedsAccessCheck()
- ? LocationSummary::kCall
+ ? LocationSummary::kCallOnMainOnly
: (((code_generator_supports_read_barrier && kEmitCompilerReadBarrier) ||
cls->CanCallRuntime())
? LocationSummary::kCallOnSlowPath
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index 9364be3..b8540ba 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -350,6 +350,16 @@
// accessing the String's `value` field in String intrinsics.
static uint32_t GetArrayDataOffset(HArrayGet* array_get);
+ // Return the entry point offset for ReadBarrierMarkRegX, where X is `reg`.
+ template <size_t pointer_size>
+ static int32_t GetReadBarrierMarkEntryPointsOffset(size_t reg) {
+ DCHECK_LT(reg, 32u);
+ // The ReadBarrierMarkRegX entry points are ordered by increasing
+ // register number in Thread::tls_Ptr_.quick_entrypoints.
+ return QUICK_ENTRYPOINT_OFFSET(pointer_size, pReadBarrierMarkReg00).Int32Value()
+ + pointer_size * reg;
+ }
+
void EmitParallelMoves(Location from1,
Location to1,
Primitive::Type type1,
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 690ecc3..1aa7b54 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -412,8 +412,8 @@
// Slow path marking an object during a read barrier.
class ReadBarrierMarkSlowPathARM : public SlowPathCode {
public:
- ReadBarrierMarkSlowPathARM(HInstruction* instruction, Location out, Location obj)
- : SlowPathCode(instruction), out_(out), obj_(obj) {
+ ReadBarrierMarkSlowPathARM(HInstruction* instruction, Location obj)
+ : SlowPathCode(instruction), obj_(obj) {
DCHECK(kEmitCompilerReadBarrier);
}
@@ -421,9 +421,9 @@
void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
LocationSummary* locations = instruction_->GetLocations();
- Register reg_out = out_.AsRegister<Register>();
+ Register reg = obj_.AsRegister<Register>();
DCHECK(locations->CanCall());
- DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out));
+ DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg));
DCHECK(instruction_->IsInstanceFieldGet() ||
instruction_->IsStaticFieldGet() ||
instruction_->IsArrayGet() ||
@@ -437,24 +437,44 @@
<< instruction_->DebugName();
__ Bind(GetEntryLabel());
+ // Save live registers before the runtime call, and in particular
+ // R0 (if it is live), as it is clobbered by functions
+ // art_quick_read_barrier_mark_regX.
SaveLiveRegisters(codegen, locations);
InvokeRuntimeCallingConvention calling_convention;
CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
- arm_codegen->Move32(Location::RegisterLocation(calling_convention.GetRegisterAt(0)), obj_);
- arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pReadBarrierMark),
+ DCHECK_NE(reg, SP);
+ DCHECK_NE(reg, LR);
+ DCHECK_NE(reg, PC);
+ DCHECK(0 <= reg && reg < kNumberOfCoreRegisters) << reg;
+ // "Compact" slow path, saving two moves.
+ //
+ // Instead of using the standard runtime calling convention (input
+ // and output in R0):
+ //
+ // R0 <- obj
+ // R0 <- ReadBarrierMark(R0)
+ // obj <- R0
+ //
+ // we just use rX (the register holding `obj`) as input and output
+ // of a dedicated entrypoint:
+ //
+ // rX <- ReadBarrierMarkRegX(rX)
+ //
+ int32_t entry_point_offset =
+ CodeGenerator::GetReadBarrierMarkEntryPointsOffset<kArmWordSize>(reg);
+ // TODO: Do not emit a stack map for this runtime call.
+ arm_codegen->InvokeRuntime(entry_point_offset,
instruction_,
instruction_->GetDexPc(),
this);
- CheckEntrypointTypes<kQuickReadBarrierMark, mirror::Object*, mirror::Object*>();
- arm_codegen->Move32(out_, Location::RegisterLocation(R0));
RestoreLiveRegisters(codegen, locations);
__ b(GetExitLabel());
}
private:
- const Location out_;
const Location obj_;
DISALLOW_COPY_AND_ASSIGN(ReadBarrierMarkSlowPathARM);
@@ -2014,7 +2034,7 @@
(((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
&& result_type == Primitive::kPrimLong)
|| (input_type == Primitive::kPrimLong && result_type == Primitive::kPrimFloat))
- ? LocationSummary::kCall
+ ? LocationSummary::kCallOnMainOnly
: LocationSummary::kNoCall;
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
@@ -2833,13 +2853,13 @@
LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
if (div->GetResultType() == Primitive::kPrimLong) {
// pLdiv runtime call.
- call_kind = LocationSummary::kCall;
+ call_kind = LocationSummary::kCallOnMainOnly;
} else if (div->GetResultType() == Primitive::kPrimInt && div->InputAt(1)->IsConstant()) {
// sdiv will be replaced by other instruction sequence.
} else if (div->GetResultType() == Primitive::kPrimInt &&
!codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
// pIdivmod runtime call.
- call_kind = LocationSummary::kCall;
+ call_kind = LocationSummary::kCallOnMainOnly;
}
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
@@ -2958,7 +2978,7 @@
Primitive::Type type = rem->GetResultType();
// Most remainders are implemented in the runtime.
- LocationSummary::CallKind call_kind = LocationSummary::kCall;
+ LocationSummary::CallKind call_kind = LocationSummary::kCallOnMainOnly;
if (rem->GetResultType() == Primitive::kPrimInt && rem->InputAt(1)->IsConstant()) {
// sdiv will be replaced by other instruction sequence.
call_kind = LocationSummary::kNoCall;
@@ -3495,7 +3515,7 @@
void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) {
LocationSummary* locations =
- new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
if (instruction->IsStringAlloc()) {
locations->AddTemp(Location::RegisterLocation(kMethodRegisterArgument));
} else {
@@ -3528,7 +3548,7 @@
void LocationsBuilderARM::VisitNewArray(HNewArray* instruction) {
LocationSummary* locations =
- new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
InvokeRuntimeCallingConvention calling_convention;
locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
locations->SetOut(Location::RegisterLocation(R0));
@@ -5449,7 +5469,7 @@
void LocationsBuilderARM::VisitThrow(HThrow* instruction) {
LocationSummary* locations =
- new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
}
@@ -5850,7 +5870,7 @@
void LocationsBuilderARM::VisitMonitorOperation(HMonitorOperation* instruction) {
LocationSummary* locations =
- new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
}
@@ -6174,7 +6194,7 @@
// Slow path used to mark the GC root `root`.
SlowPathCode* slow_path =
- new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathARM(instruction, root, root);
+ new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathARM(instruction, root);
codegen_->AddSlowPath(slow_path);
// IP = Thread::Current()->GetIsGcMarking()
@@ -6277,21 +6297,12 @@
// /* LockWord */ lock_word = LockWord(monitor)
static_assert(sizeof(LockWord) == sizeof(int32_t),
"art::LockWord and int32_t have different sizes.");
- // /* uint32_t */ rb_state = lock_word.ReadBarrierState()
- __ Lsr(temp_reg, temp_reg, LockWord::kReadBarrierStateShift);
- __ and_(temp_reg, temp_reg, ShifterOperand(LockWord::kReadBarrierStateMask));
- static_assert(
- LockWord::kReadBarrierStateMask == ReadBarrier::rb_ptr_mask_,
- "art::LockWord::kReadBarrierStateMask is not equal to art::ReadBarrier::rb_ptr_mask_.");
- // Introduce a dependency on the high bits of rb_state, which shall
- // be all zeroes, to prevent load-load reordering, and without using
+ // Introduce a dependency on the lock_word including the rb_state,
+ // which shall prevent load-load reordering without using
// a memory barrier (which would be more expensive).
- // IP = rb_state & ~LockWord::kReadBarrierStateMask = 0
- __ bic(IP, temp_reg, ShifterOperand(LockWord::kReadBarrierStateMask));
- // obj is unchanged by this operation, but its value now depends on
- // IP, which depends on temp_reg.
- __ add(obj, obj, ShifterOperand(IP));
+ // obj is unchanged by this operation, but its value now depends on temp_reg.
+ __ add(obj, obj, ShifterOperand(temp_reg, LSR, 32));
// The actual reference load.
if (index.IsValid()) {
@@ -6323,13 +6334,19 @@
// Slow path used to mark the object `ref` when it is gray.
SlowPathCode* slow_path =
- new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathARM(instruction, ref, ref);
+ new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathARM(instruction, ref);
AddSlowPath(slow_path);
// if (rb_state == ReadBarrier::gray_ptr_)
// ref = ReadBarrier::Mark(ref);
- __ cmp(temp_reg, ShifterOperand(ReadBarrier::gray_ptr_));
- __ b(slow_path->GetEntryLabel(), EQ);
+ // Given the numeric representation, it's enough to check the low bit of the
+ // rb_state. We do that by shifting the bit out of the lock word with LSRS
+ // which can be a 16-bit instruction unlike the TST immediate.
+ static_assert(ReadBarrier::white_ptr_ == 0, "Expecting white to have value 0");
+ static_assert(ReadBarrier::gray_ptr_ == 1, "Expecting gray to have value 1");
+ static_assert(ReadBarrier::black_ptr_ == 2, "Expecting black to have value 2");
+ __ Lsrs(temp_reg, temp_reg, LockWord::kReadBarrierStateShift + 1);
+ __ b(slow_path->GetEntryLabel(), CS); // Carry flag is the last bit shifted out by LSRS.
__ Bind(slow_path->GetExitLabel());
}
@@ -6953,21 +6970,25 @@
void InstructionCodeGeneratorARM::VisitClassTableGet(HClassTableGet* instruction) {
LocationSummary* locations = instruction->GetLocations();
- uint32_t method_offset = 0;
if (instruction->GetTableKind() == HClassTableGet::TableKind::kVTable) {
- method_offset = mirror::Class::EmbeddedVTableEntryOffset(
+ uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
instruction->GetIndex(), kArmPointerSize).SizeValue();
+ __ LoadFromOffset(kLoadWord,
+ locations->Out().AsRegister<Register>(),
+ locations->InAt(0).AsRegister<Register>(),
+ method_offset);
} else {
- __ LoadFromOffset(kLoadWord, locations->Out().AsRegister<Register>(),
- locations->InAt(0).AsRegister<Register>(),
- mirror::Class::ImtPtrOffset(kArmPointerSize).Uint32Value());
- method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
+ uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
instruction->GetIndex() % ImTable::kSize, kArmPointerSize));
+ __ LoadFromOffset(kLoadWord,
+ locations->Out().AsRegister<Register>(),
+ locations->InAt(0).AsRegister<Register>(),
+ mirror::Class::ImtPtrOffset(kArmPointerSize).Uint32Value());
+ __ LoadFromOffset(kLoadWord,
+ locations->Out().AsRegister<Register>(),
+ locations->Out().AsRegister<Register>(),
+ method_offset);
}
- __ LoadFromOffset(kLoadWord,
- locations->Out().AsRegister<Register>(),
- locations->InAt(0).AsRegister<Register>(),
- method_offset);
}
#undef __
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index c8d33d5..d9d675e 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -580,8 +580,8 @@
// Slow path marking an object during a read barrier.
class ReadBarrierMarkSlowPathARM64 : public SlowPathCodeARM64 {
public:
- ReadBarrierMarkSlowPathARM64(HInstruction* instruction, Location out, Location obj)
- : SlowPathCodeARM64(instruction), out_(out), obj_(obj) {
+ ReadBarrierMarkSlowPathARM64(HInstruction* instruction, Location obj)
+ : SlowPathCodeARM64(instruction), obj_(obj) {
DCHECK(kEmitCompilerReadBarrier);
}
@@ -589,9 +589,8 @@
void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
LocationSummary* locations = instruction_->GetLocations();
- Primitive::Type type = Primitive::kPrimNot;
DCHECK(locations->CanCall());
- DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(out_.reg()));
+ DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(obj_.reg()));
DCHECK(instruction_->IsInstanceFieldGet() ||
instruction_->IsStaticFieldGet() ||
instruction_->IsArrayGet() ||
@@ -605,24 +604,44 @@
<< instruction_->DebugName();
__ Bind(GetEntryLabel());
+ // Save live registers before the runtime call, and in particular
+ // W0 (if it is live), as it is clobbered by functions
+ // art_quick_read_barrier_mark_regX.
SaveLiveRegisters(codegen, locations);
InvokeRuntimeCallingConvention calling_convention;
CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
- arm64_codegen->MoveLocation(LocationFrom(calling_convention.GetRegisterAt(0)), obj_, type);
- arm64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pReadBarrierMark),
+ DCHECK_NE(obj_.reg(), LR);
+ DCHECK_NE(obj_.reg(), WSP);
+ DCHECK_NE(obj_.reg(), WZR);
+ DCHECK(0 <= obj_.reg() && obj_.reg() < kNumberOfWRegisters) << obj_.reg();
+ // "Compact" slow path, saving two moves.
+ //
+ // Instead of using the standard runtime calling convention (input
+ // and output in W0):
+ //
+ // W0 <- obj
+ // W0 <- ReadBarrierMark(W0)
+ // obj <- W0
+ //
+ // we just use rX (the register holding `obj`) as input and output
+ // of a dedicated entrypoint:
+ //
+ // rX <- ReadBarrierMarkRegX(rX)
+ //
+ int32_t entry_point_offset =
+ CodeGenerator::GetReadBarrierMarkEntryPointsOffset<kArm64WordSize>(obj_.reg());
+ // TODO: Do not emit a stack map for this runtime call.
+ arm64_codegen->InvokeRuntime(entry_point_offset,
instruction_,
instruction_->GetDexPc(),
this);
- CheckEntrypointTypes<kQuickReadBarrierMark, mirror::Object*, mirror::Object*>();
- arm64_codegen->MoveLocation(out_, calling_convention.GetReturnLocation(type), type);
RestoreLiveRegisters(codegen, locations);
__ B(GetExitLabel());
}
private:
- const Location out_;
const Location obj_;
DISALLOW_COPY_AND_ASSIGN(ReadBarrierMarkSlowPathARM64);
@@ -4273,7 +4292,7 @@
void LocationsBuilderARM64::VisitMonitorOperation(HMonitorOperation* instruction) {
LocationSummary* locations =
- new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0)));
}
@@ -4371,7 +4390,7 @@
void LocationsBuilderARM64::VisitNewArray(HNewArray* instruction) {
LocationSummary* locations =
- new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
InvokeRuntimeCallingConvention calling_convention;
locations->AddTemp(LocationFrom(calling_convention.GetRegisterAt(0)));
locations->SetOut(LocationFrom(x0));
@@ -4396,7 +4415,7 @@
void LocationsBuilderARM64::VisitNewInstance(HNewInstance* instruction) {
LocationSummary* locations =
- new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
InvokeRuntimeCallingConvention calling_convention;
if (instruction->IsStringAlloc()) {
locations->AddTemp(LocationFrom(kArtMethodRegister));
@@ -4549,7 +4568,8 @@
void LocationsBuilderARM64::VisitRem(HRem* rem) {
Primitive::Type type = rem->GetResultType();
LocationSummary::CallKind call_kind =
- Primitive::IsFloatingPointType(type) ? LocationSummary::kCall : LocationSummary::kNoCall;
+ Primitive::IsFloatingPointType(type) ? LocationSummary::kCallOnMainOnly
+ : LocationSummary::kNoCall;
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
switch (type) {
@@ -4766,7 +4786,7 @@
void LocationsBuilderARM64::VisitThrow(HThrow* instruction) {
LocationSummary* locations =
- new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0)));
}
@@ -5061,7 +5081,7 @@
// Slow path used to mark the GC root `root`.
SlowPathCodeARM64* slow_path =
- new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathARM64(instruction, root, root);
+ new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathARM64(instruction, root);
codegen_->AddSlowPath(slow_path);
MacroAssembler* masm = GetVIXLAssembler();
@@ -5206,23 +5226,12 @@
// /* LockWord */ lock_word = LockWord(monitor)
static_assert(sizeof(LockWord) == sizeof(int32_t),
"art::LockWord and int32_t have different sizes.");
- // /* uint32_t */ rb_state = lock_word.ReadBarrierState()
- __ Lsr(temp, temp, LockWord::kReadBarrierStateShift);
- __ And(temp, temp, Operand(LockWord::kReadBarrierStateMask));
- static_assert(
- LockWord::kReadBarrierStateMask == ReadBarrier::rb_ptr_mask_,
- "art::LockWord::kReadBarrierStateMask is not equal to art::ReadBarrier::rb_ptr_mask_.");
- // Introduce a dependency on the high bits of rb_state, which shall
- // be all zeroes, to prevent load-load reordering, and without using
+ // Introduce a dependency on the lock_word including rb_state,
+ // to prevent load-load reordering, and without using
// a memory barrier (which would be more expensive).
- // temp2 = rb_state & ~LockWord::kReadBarrierStateMask = 0
- Register temp2 = temps.AcquireW();
- __ Bic(temp2, temp, Operand(LockWord::kReadBarrierStateMask));
- // obj is unchanged by this operation, but its value now depends on
- // temp2, which depends on temp.
- __ Add(obj, obj, Operand(temp2));
- temps.Release(temp2);
+ // obj is unchanged by this operation, but its value now depends on temp.
+ __ Add(obj.X(), obj.X(), Operand(temp.X(), LSR, 32));
// The actual reference load.
if (index.IsValid()) {
@@ -5248,7 +5257,7 @@
uint32_t computed_offset = offset + (Int64ConstantFrom(index) << scale_factor);
Load(type, ref_reg, HeapOperand(obj, computed_offset));
} else {
- temp2 = temps.AcquireW();
+ Register temp2 = temps.AcquireW();
__ Add(temp2, obj, offset);
Load(type, ref_reg, HeapOperand(temp2, XRegisterFrom(index), LSL, scale_factor));
temps.Release(temp2);
@@ -5269,13 +5278,16 @@
// Slow path used to mark the object `ref` when it is gray.
SlowPathCodeARM64* slow_path =
- new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathARM64(instruction, ref, ref);
+ new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathARM64(instruction, ref);
AddSlowPath(slow_path);
// if (rb_state == ReadBarrier::gray_ptr_)
// ref = ReadBarrier::Mark(ref);
- __ Cmp(temp, ReadBarrier::gray_ptr_);
- __ B(eq, slow_path->GetEntryLabel());
+ // Given the numeric representation, it's enough to check the low bit of the rb_state.
+ static_assert(ReadBarrier::white_ptr_ == 0, "Expecting white to have value 0");
+ static_assert(ReadBarrier::gray_ptr_ == 1, "Expecting gray to have value 1");
+ static_assert(ReadBarrier::black_ptr_ == 2, "Expecting black to have value 2");
+ __ Tbnz(temp, LockWord::kReadBarrierStateShift, slow_path->GetEntryLabel());
__ Bind(slow_path->GetExitLabel());
}
@@ -5350,18 +5362,19 @@
void InstructionCodeGeneratorARM64::VisitClassTableGet(HClassTableGet* instruction) {
LocationSummary* locations = instruction->GetLocations();
- uint32_t method_offset = 0;
if (instruction->GetTableKind() == HClassTableGet::TableKind::kVTable) {
- method_offset = mirror::Class::EmbeddedVTableEntryOffset(
+ uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
instruction->GetIndex(), kArm64PointerSize).SizeValue();
+ __ Ldr(XRegisterFrom(locations->Out()),
+ MemOperand(XRegisterFrom(locations->InAt(0)), method_offset));
} else {
+ uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
+ instruction->GetIndex() % ImTable::kSize, kArm64PointerSize));
__ Ldr(XRegisterFrom(locations->Out()), MemOperand(XRegisterFrom(locations->InAt(0)),
mirror::Class::ImtPtrOffset(kArm64PointerSize).Uint32Value()));
- method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
- instruction->GetIndex() % ImTable::kSize, kArm64PointerSize));
+ __ Ldr(XRegisterFrom(locations->Out()),
+ MemOperand(XRegisterFrom(locations->Out()), method_offset));
}
- __ Ldr(XRegisterFrom(locations->Out()),
- MemOperand(XRegisterFrom(locations->InAt(0)), method_offset));
}
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index b6dca95..2b71da0 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -1855,7 +1855,7 @@
bool needs_runtime_call = instruction->NeedsTypeCheck();
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
instruction,
- needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall);
+ needs_runtime_call ? LocationSummary::kCallOnMainOnly : LocationSummary::kNoCall);
if (needs_runtime_call) {
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
@@ -2467,7 +2467,7 @@
void LocationsBuilderMIPS::VisitDiv(HDiv* div) {
Primitive::Type type = div->GetResultType();
LocationSummary::CallKind call_kind = (type == Primitive::kPrimLong)
- ? LocationSummary::kCall
+ ? LocationSummary::kCallOnMainOnly
: LocationSummary::kNoCall;
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
@@ -3430,7 +3430,7 @@
bool is_wide = (field_type == Primitive::kPrimLong) || (field_type == Primitive::kPrimDouble);
bool generate_volatile = field_info.IsVolatile() && is_wide;
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
- instruction, generate_volatile ? LocationSummary::kCall : LocationSummary::kNoCall);
+ instruction, generate_volatile ? LocationSummary::kCallOnMainOnly : LocationSummary::kNoCall);
locations->SetInAt(0, Location::RequiresRegister());
if (generate_volatile) {
@@ -3557,7 +3557,7 @@
bool is_wide = (field_type == Primitive::kPrimLong) || (field_type == Primitive::kPrimDouble);
bool generate_volatile = field_info.IsVolatile() && is_wide;
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
- instruction, generate_volatile ? LocationSummary::kCall : LocationSummary::kNoCall);
+ instruction, generate_volatile ? LocationSummary::kCallOnMainOnly : LocationSummary::kNoCall);
locations->SetInAt(0, Location::RequiresRegister());
if (generate_volatile) {
@@ -4218,7 +4218,7 @@
void LocationsBuilderMIPS::VisitMonitorOperation(HMonitorOperation* instruction) {
LocationSummary* locations =
- new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
}
@@ -4397,7 +4397,7 @@
void LocationsBuilderMIPS::VisitNewArray(HNewArray* instruction) {
LocationSummary* locations =
- new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
InvokeRuntimeCallingConvention calling_convention;
locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
@@ -4423,7 +4423,7 @@
void LocationsBuilderMIPS::VisitNewInstance(HNewInstance* instruction) {
LocationSummary* locations =
- new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
InvokeRuntimeCallingConvention calling_convention;
if (instruction->IsStringAlloc()) {
locations->AddTemp(Location::RegisterLocation(kMethodRegisterArgument));
@@ -4593,7 +4593,7 @@
void LocationsBuilderMIPS::VisitRem(HRem* rem) {
Primitive::Type type = rem->GetResultType();
LocationSummary::CallKind call_kind =
- (type == Primitive::kPrimInt) ? LocationSummary::kNoCall : LocationSummary::kCall;
+ (type == Primitive::kPrimInt) ? LocationSummary::kNoCall : LocationSummary::kCallOnMainOnly;
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
switch (type) {
@@ -4830,7 +4830,7 @@
void LocationsBuilderMIPS::VisitThrow(HThrow* instruction) {
LocationSummary* locations =
- new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
}
@@ -4859,7 +4859,7 @@
if (!isR6 &&
((Primitive::IsFloatingPointType(result_type) && input_type == Primitive::kPrimLong) ||
(result_type == Primitive::kPrimLong && Primitive::IsFloatingPointType(input_type)))) {
- call_kind = LocationSummary::kCall;
+ call_kind = LocationSummary::kCallOnMainOnly;
}
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
@@ -5380,22 +5380,25 @@
void InstructionCodeGeneratorMIPS::VisitClassTableGet(HClassTableGet* instruction) {
LocationSummary* locations = instruction->GetLocations();
- uint32_t method_offset = 0;
if (instruction->GetTableKind() == HClassTableGet::TableKind::kVTable) {
- method_offset = mirror::Class::EmbeddedVTableEntryOffset(
+ uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
instruction->GetIndex(), kMipsPointerSize).SizeValue();
+ __ LoadFromOffset(kLoadWord,
+ locations->Out().AsRegister<Register>(),
+ locations->InAt(0).AsRegister<Register>(),
+ method_offset);
} else {
+ uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
+ instruction->GetIndex() % ImTable::kSize, kMipsPointerSize));
__ LoadFromOffset(kLoadWord,
locations->Out().AsRegister<Register>(),
locations->InAt(0).AsRegister<Register>(),
mirror::Class::ImtPtrOffset(kMipsPointerSize).Uint32Value());
- method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
- instruction->GetIndex() % ImTable::kSize, kMipsPointerSize));
+ __ LoadFromOffset(kLoadWord,
+ locations->Out().AsRegister<Register>(),
+ locations->Out().AsRegister<Register>(),
+ method_offset);
}
- __ LoadFromOffset(kLoadWord,
- locations->Out().AsRegister<Register>(),
- locations->InAt(0).AsRegister<Register>(),
- method_offset);
}
#undef __
diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc
index 9f2664c..aa1ba84 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -1436,7 +1436,7 @@
bool needs_runtime_call = instruction->NeedsTypeCheck();
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
instruction,
- needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall);
+ needs_runtime_call ? LocationSummary::kCallOnMainOnly : LocationSummary::kNoCall);
if (needs_runtime_call) {
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
@@ -3292,7 +3292,7 @@
void LocationsBuilderMIPS64::VisitMonitorOperation(HMonitorOperation* instruction) {
LocationSummary* locations =
- new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
}
@@ -3419,7 +3419,7 @@
void LocationsBuilderMIPS64::VisitNewArray(HNewArray* instruction) {
LocationSummary* locations =
- new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
InvokeRuntimeCallingConvention calling_convention;
locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimNot));
@@ -3440,7 +3440,7 @@
void LocationsBuilderMIPS64::VisitNewInstance(HNewInstance* instruction) {
LocationSummary* locations =
- new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
InvokeRuntimeCallingConvention calling_convention;
if (instruction->IsStringAlloc()) {
locations->AddTemp(Location::RegisterLocation(kMethodRegisterArgument));
@@ -3600,7 +3600,8 @@
void LocationsBuilderMIPS64::VisitRem(HRem* rem) {
Primitive::Type type = rem->GetResultType();
LocationSummary::CallKind call_kind =
- Primitive::IsFloatingPointType(type) ? LocationSummary::kCall : LocationSummary::kNoCall;
+ Primitive::IsFloatingPointType(type) ? LocationSummary::kCallOnMainOnly
+ : LocationSummary::kNoCall;
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
switch (type) {
@@ -3813,7 +3814,7 @@
void LocationsBuilderMIPS64::VisitThrow(HThrow* instruction) {
LocationSummary* locations =
- new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
}
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index be20f1f..1cc6060 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -140,12 +140,29 @@
// Live registers will be restored in the catch block if caught.
SaveLiveRegisters(codegen, instruction_->GetLocations());
}
+
+ // Are we using an array length from memory?
+ HInstruction* array_length = instruction_->InputAt(1);
+ Location length_loc = locations->InAt(1);
InvokeRuntimeCallingConvention calling_convention;
+ if (array_length->IsArrayLength() && array_length->IsEmittedAtUseSite()) {
+ // Load the array length into our temporary.
+ uint32_t len_offset = CodeGenerator::GetArrayLengthOffset(array_length->AsArrayLength());
+ Location array_loc = array_length->GetLocations()->InAt(0);
+ Address array_len(array_loc.AsRegister<Register>(), len_offset);
+ length_loc = Location::RegisterLocation(calling_convention.GetRegisterAt(1));
+ // Check for conflicts with index.
+ if (length_loc.Equals(locations->InAt(0))) {
+ // We know we aren't using parameter 2.
+ length_loc = Location::RegisterLocation(calling_convention.GetRegisterAt(2));
+ }
+ __ movl(length_loc.AsRegister<Register>(), array_len);
+ }
x86_codegen->EmitParallelMoves(
locations->InAt(0),
Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Primitive::kPrimInt,
- locations->InAt(1),
+ length_loc,
Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
Primitive::kPrimInt);
uint32_t entry_point_offset = instruction_->AsBoundsCheck()->IsStringCharAt()
@@ -430,8 +447,8 @@
// Slow path marking an object during a read barrier.
class ReadBarrierMarkSlowPathX86 : public SlowPathCode {
public:
- ReadBarrierMarkSlowPathX86(HInstruction* instruction, Location out, Location obj)
- : SlowPathCode(instruction), out_(out), obj_(obj) {
+ ReadBarrierMarkSlowPathX86(HInstruction* instruction, Location obj)
+ : SlowPathCode(instruction), obj_(obj) {
DCHECK(kEmitCompilerReadBarrier);
}
@@ -439,9 +456,9 @@
void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
LocationSummary* locations = instruction_->GetLocations();
- Register reg_out = out_.AsRegister<Register>();
+ Register reg = obj_.AsRegister<Register>();
DCHECK(locations->CanCall());
- DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out));
+ DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg));
DCHECK(instruction_->IsInstanceFieldGet() ||
instruction_->IsStaticFieldGet() ||
instruction_->IsArrayGet() ||
@@ -455,24 +472,42 @@
<< instruction_->DebugName();
__ Bind(GetEntryLabel());
+ // Save live registers before the runtime call, and in particular
+ // EAX (if it is live), as it is clobbered by functions
+ // art_quick_read_barrier_mark_regX.
SaveLiveRegisters(codegen, locations);
InvokeRuntimeCallingConvention calling_convention;
CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
- x86_codegen->Move32(Location::RegisterLocation(calling_convention.GetRegisterAt(0)), obj_);
- x86_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pReadBarrierMark),
+ DCHECK_NE(reg, ESP);
+ DCHECK(0 <= reg && reg < kNumberOfCpuRegisters) << reg;
+ // "Compact" slow path, saving two moves.
+ //
+ // Instead of using the standard runtime calling convention (input
+ // and output in EAX):
+ //
+ // EAX <- obj
+ // EAX <- ReadBarrierMark(EAX)
+ // obj <- EAX
+ //
+ // we just use rX (the register holding `obj`) as input and output
+ // of a dedicated entrypoint:
+ //
+ // rX <- ReadBarrierMarkRegX(rX)
+ //
+ int32_t entry_point_offset =
+ CodeGenerator::GetReadBarrierMarkEntryPointsOffset<kX86WordSize>(reg);
+ // TODO: Do not emit a stack map for this runtime call.
+ x86_codegen->InvokeRuntime(entry_point_offset,
instruction_,
instruction_->GetDexPc(),
this);
- CheckEntrypointTypes<kQuickReadBarrierMark, mirror::Object*, mirror::Object*>();
- x86_codegen->Move32(out_, Location::RegisterLocation(EAX));
RestoreLiveRegisters(codegen, locations);
__ jmp(GetExitLabel());
}
private:
- const Location out_;
const Location obj_;
DISALLOW_COPY_AND_ASSIGN(ReadBarrierMarkSlowPathX86);
@@ -2185,7 +2220,7 @@
LocationSummary::CallKind call_kind =
((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
&& result_type == Primitive::kPrimLong)
- ? LocationSummary::kCall
+ ? LocationSummary::kCallOnMainOnly
: LocationSummary::kNoCall;
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
@@ -3440,7 +3475,7 @@
void LocationsBuilderX86::VisitDiv(HDiv* div) {
LocationSummary::CallKind call_kind = (div->GetResultType() == Primitive::kPrimLong)
- ? LocationSummary::kCall
+ ? LocationSummary::kCallOnMainOnly
: LocationSummary::kNoCall;
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
@@ -3543,7 +3578,7 @@
Primitive::Type type = rem->GetResultType();
LocationSummary::CallKind call_kind = (rem->GetResultType() == Primitive::kPrimLong)
- ? LocationSummary::kCall
+ ? LocationSummary::kCallOnMainOnly
: LocationSummary::kNoCall;
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
@@ -3985,7 +4020,7 @@
void LocationsBuilderX86::VisitNewInstance(HNewInstance* instruction) {
LocationSummary* locations =
- new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
locations->SetOut(Location::RegisterLocation(EAX));
if (instruction->IsStringAlloc()) {
locations->AddTemp(Location::RegisterLocation(kMethodRegisterArgument));
@@ -4018,7 +4053,7 @@
void LocationsBuilderX86::VisitNewArray(HNewArray* instruction) {
LocationSummary* locations =
- new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
locations->SetOut(Location::RegisterLocation(EAX));
InvokeRuntimeCallingConvention calling_convention;
locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
@@ -4073,20 +4108,21 @@
void InstructionCodeGeneratorX86::VisitClassTableGet(HClassTableGet* instruction) {
LocationSummary* locations = instruction->GetLocations();
- uint32_t method_offset = 0;
if (instruction->GetTableKind() == HClassTableGet::TableKind::kVTable) {
- method_offset = mirror::Class::EmbeddedVTableEntryOffset(
+ uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
instruction->GetIndex(), kX86PointerSize).SizeValue();
+ __ movl(locations->Out().AsRegister<Register>(),
+ Address(locations->InAt(0).AsRegister<Register>(), method_offset));
} else {
- __ movl(locations->InAt(0).AsRegister<Register>(),
- Address(locations->InAt(0).AsRegister<Register>(),
- mirror::Class::ImtPtrOffset(kX86PointerSize).Uint32Value()));
- // temp = temp->GetImtEntryAt(method_offset);
- method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
+ uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
instruction->GetIndex() % ImTable::kSize, kX86PointerSize));
+ __ movl(locations->Out().AsRegister<Register>(),
+ Address(locations->InAt(0).AsRegister<Register>(),
+ mirror::Class::ImtPtrOffset(kX86PointerSize).Uint32Value()));
+ // temp = temp->GetImtEntryAt(method_offset);
+ __ movl(locations->Out().AsRegister<Register>(),
+ Address(locations->Out().AsRegister<Register>(), method_offset));
}
- __ movl(locations->Out().AsRegister<Register>(),
- Address(locations->InAt(0).AsRegister<Register>(), method_offset));
}
void LocationsBuilderX86::VisitNot(HNot* not_) {
@@ -5517,10 +5553,16 @@
void LocationsBuilderX86::VisitArrayLength(HArrayLength* instruction) {
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
locations->SetInAt(0, Location::RequiresRegister());
- locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+ if (!instruction->IsEmittedAtUseSite()) {
+ locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+ }
}
void InstructionCodeGeneratorX86::VisitArrayLength(HArrayLength* instruction) {
+ if (instruction->IsEmittedAtUseSite()) {
+ return;
+ }
+
LocationSummary* locations = instruction->GetLocations();
uint32_t offset = CodeGenerator::GetArrayLengthOffset(instruction);
Register obj = locations->InAt(0).AsRegister<Register>();
@@ -5535,7 +5577,10 @@
: LocationSummary::kNoCall;
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
- locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
+ HInstruction* length = instruction->InputAt(1);
+ if (!length->IsEmittedAtUseSite()) {
+ locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
+ }
if (instruction->HasUses()) {
locations->SetOut(Location::SameAsFirstInput());
}
@@ -5569,12 +5614,28 @@
codegen_->AddSlowPath(slow_path);
__ j(kAboveEqual, slow_path->GetEntryLabel());
} else {
- Register length = length_loc.AsRegister<Register>();
- if (index_loc.IsConstant()) {
- int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
- __ cmpl(length, Immediate(value));
+ HInstruction* array_length = instruction->InputAt(1);
+ if (array_length->IsEmittedAtUseSite()) {
+ // Address the length field in the array.
+ DCHECK(array_length->IsArrayLength());
+ uint32_t len_offset = CodeGenerator::GetArrayLengthOffset(array_length->AsArrayLength());
+ Location array_loc = array_length->GetLocations()->InAt(0);
+ Address array_len(array_loc.AsRegister<Register>(), len_offset);
+ if (index_loc.IsConstant()) {
+ int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
+ __ cmpl(array_len, Immediate(value));
+ } else {
+ __ cmpl(array_len, index_loc.AsRegister<Register>());
+ }
+ codegen_->MaybeRecordImplicitNullCheck(array_length);
} else {
- __ cmpl(length, index_loc.AsRegister<Register>());
+ Register length = length_loc.AsRegister<Register>();
+ if (index_loc.IsConstant()) {
+ int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
+ __ cmpl(length, Immediate(value));
+ } else {
+ __ cmpl(length, index_loc.AsRegister<Register>());
+ }
}
codegen_->AddSlowPath(slow_path);
__ j(kBelowEqual, slow_path->GetEntryLabel());
@@ -6242,7 +6303,7 @@
void LocationsBuilderX86::VisitThrow(HThrow* instruction) {
LocationSummary* locations =
- new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
}
@@ -6694,7 +6755,7 @@
void LocationsBuilderX86::VisitMonitorOperation(HMonitorOperation* instruction) {
LocationSummary* locations =
- new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
}
@@ -6933,7 +6994,7 @@
// Slow path used to mark the GC root `root`.
SlowPathCode* slow_path =
- new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathX86(instruction, root, root);
+ new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathX86(instruction, root);
codegen_->AddSlowPath(slow_path);
__ fs()->cmpl(Address::Absolute(Thread::IsGcMarkingOffset<kX86WordSize>().Int32Value()),
@@ -7063,7 +7124,7 @@
// Slow path used to mark the object `ref` when it is gray.
SlowPathCode* slow_path =
- new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathX86(instruction, ref, ref);
+ new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathX86(instruction, ref);
AddSlowPath(slow_path);
// if (rb_state == ReadBarrier::gray_ptr_)
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index cac33cd..a015893 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -194,14 +194,31 @@
// Live registers will be restored in the catch block if caught.
SaveLiveRegisters(codegen, instruction_->GetLocations());
}
+ // Are we using an array length from memory?
+ HInstruction* array_length = instruction_->InputAt(1);
+ Location length_loc = locations->InAt(1);
+ InvokeRuntimeCallingConvention calling_convention;
+ if (array_length->IsArrayLength() && array_length->IsEmittedAtUseSite()) {
+ // Load the array length into our temporary.
+ uint32_t len_offset = CodeGenerator::GetArrayLengthOffset(array_length->AsArrayLength());
+ Location array_loc = array_length->GetLocations()->InAt(0);
+ Address array_len(array_loc.AsRegister<CpuRegister>(), len_offset);
+ length_loc = Location::RegisterLocation(calling_convention.GetRegisterAt(1));
+ // Check for conflicts with index.
+ if (length_loc.Equals(locations->InAt(0))) {
+ // We know we aren't using parameter 2.
+ length_loc = Location::RegisterLocation(calling_convention.GetRegisterAt(2));
+ }
+ __ movl(length_loc.AsRegister<CpuRegister>(), array_len);
+ }
+
// We're moving two locations to locations that could overlap, so we need a parallel
// move resolver.
- InvokeRuntimeCallingConvention calling_convention;
codegen->EmitParallelMoves(
locations->InAt(0),
Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Primitive::kPrimInt,
- locations->InAt(1),
+ length_loc,
Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
Primitive::kPrimInt);
uint32_t entry_point_offset = instruction_->AsBoundsCheck()->IsStringCharAt()
@@ -451,8 +468,8 @@
// Slow path marking an object during a read barrier.
class ReadBarrierMarkSlowPathX86_64 : public SlowPathCode {
public:
- ReadBarrierMarkSlowPathX86_64(HInstruction* instruction, Location out, Location obj)
- : SlowPathCode(instruction), out_(out), obj_(obj) {
+ ReadBarrierMarkSlowPathX86_64(HInstruction* instruction, Location obj)
+ : SlowPathCode(instruction), obj_(obj) {
DCHECK(kEmitCompilerReadBarrier);
}
@@ -460,9 +477,9 @@
void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
LocationSummary* locations = instruction_->GetLocations();
- Register reg_out = out_.AsRegister<Register>();
+ Register reg = obj_.AsRegister<Register>();
DCHECK(locations->CanCall());
- DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out));
+ DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg));
DCHECK(instruction_->IsInstanceFieldGet() ||
instruction_->IsStaticFieldGet() ||
instruction_->IsArrayGet() ||
@@ -476,24 +493,42 @@
<< instruction_->DebugName();
__ Bind(GetEntryLabel());
+ // Save live registers before the runtime call, and in particular
+ // RDI and/or RAX (if they are live), as they are clobbered by
+ // functions art_quick_read_barrier_mark_regX.
SaveLiveRegisters(codegen, locations);
InvokeRuntimeCallingConvention calling_convention;
CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
- x86_64_codegen->Move(Location::RegisterLocation(calling_convention.GetRegisterAt(0)), obj_);
- x86_64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pReadBarrierMark),
- instruction_,
- instruction_->GetDexPc(),
- this);
- CheckEntrypointTypes<kQuickReadBarrierMark, mirror::Object*, mirror::Object*>();
- x86_64_codegen->Move(out_, Location::RegisterLocation(RAX));
+ DCHECK_NE(reg, RSP);
+ DCHECK(0 <= reg && reg < kNumberOfCpuRegisters) << reg;
+ // "Compact" slow path, saving two moves.
+ //
+ // Instead of using the standard runtime calling convention (input
+ // and output in R0):
+ //
+ // RDI <- obj
+ // RAX <- ReadBarrierMark(RDI)
+ // obj <- RAX
+ //
+ // we just use rX (the register holding `obj`) as input and output
+ // of a dedicated entrypoint:
+ //
+ // rX <- ReadBarrierMarkRegX(rX)
+ //
+ int32_t entry_point_offset =
+ CodeGenerator::GetReadBarrierMarkEntryPointsOffset<kX86_64WordSize>(reg);
+ // TODO: Do not emit a stack map for this runtime call.
+ x86_64_codegen->InvokeRuntime(entry_point_offset,
+ instruction_,
+ instruction_->GetDexPc(),
+ this);
RestoreLiveRegisters(codegen, locations);
__ jmp(GetExitLabel());
}
private:
- const Location out_;
const Location obj_;
DISALLOW_COPY_AND_ASSIGN(ReadBarrierMarkSlowPathX86_64);
@@ -3913,7 +3948,7 @@
void LocationsBuilderX86_64::VisitNewInstance(HNewInstance* instruction) {
LocationSummary* locations =
- new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
InvokeRuntimeCallingConvention calling_convention;
if (instruction->IsStringAlloc()) {
locations->AddTemp(Location::RegisterLocation(kMethodRegisterArgument));
@@ -3946,7 +3981,7 @@
void LocationsBuilderX86_64::VisitNewArray(HNewArray* instruction) {
LocationSummary* locations =
- new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
InvokeRuntimeCallingConvention calling_convention;
locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
locations->SetOut(Location::RegisterLocation(RAX));
@@ -4006,19 +4041,20 @@
void InstructionCodeGeneratorX86_64::VisitClassTableGet(HClassTableGet* instruction) {
LocationSummary* locations = instruction->GetLocations();
- uint32_t method_offset = 0;
if (instruction->GetTableKind() == HClassTableGet::TableKind::kVTable) {
- method_offset = mirror::Class::EmbeddedVTableEntryOffset(
+ uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
instruction->GetIndex(), kX86_64PointerSize).SizeValue();
+ __ movq(locations->Out().AsRegister<CpuRegister>(),
+ Address(locations->InAt(0).AsRegister<CpuRegister>(), method_offset));
} else {
+ uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
+ instruction->GetIndex() % ImTable::kSize, kX86_64PointerSize));
__ movq(locations->Out().AsRegister<CpuRegister>(),
Address(locations->InAt(0).AsRegister<CpuRegister>(),
mirror::Class::ImtPtrOffset(kX86_64PointerSize).Uint32Value()));
- method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
- instruction->GetIndex() % ImTable::kSize, kX86_64PointerSize));
+ __ movq(locations->Out().AsRegister<CpuRegister>(),
+ Address(locations->Out().AsRegister<CpuRegister>(), method_offset));
}
- __ movq(locations->Out().AsRegister<CpuRegister>(),
- Address(locations->InAt(0).AsRegister<CpuRegister>(), method_offset));
}
void LocationsBuilderX86_64::VisitNot(HNot* not_) {
@@ -4987,10 +5023,16 @@
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
locations->SetInAt(0, Location::RequiresRegister());
- locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+ if (!instruction->IsEmittedAtUseSite()) {
+ locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+ }
}
void InstructionCodeGeneratorX86_64::VisitArrayLength(HArrayLength* instruction) {
+ if (instruction->IsEmittedAtUseSite()) {
+ return;
+ }
+
LocationSummary* locations = instruction->GetLocations();
uint32_t offset = CodeGenerator::GetArrayLengthOffset(instruction);
CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
@@ -5005,7 +5047,10 @@
: LocationSummary::kNoCall;
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
- locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
+ HInstruction* length = instruction->InputAt(1);
+ if (!length->IsEmittedAtUseSite()) {
+ locations->SetInAt(1, Location::RegisterOrConstant(length));
+ }
if (instruction->HasUses()) {
locations->SetOut(Location::SameAsFirstInput());
}
@@ -5015,8 +5060,7 @@
LocationSummary* locations = instruction->GetLocations();
Location index_loc = locations->InAt(0);
Location length_loc = locations->InAt(1);
- SlowPathCode* slow_path =
- new (GetGraph()->GetArena()) BoundsCheckSlowPathX86_64(instruction);
+ SlowPathCode* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathX86_64(instruction);
if (length_loc.IsConstant()) {
int32_t length = CodeGenerator::GetInt32ValueOf(length_loc.GetConstant());
@@ -5039,12 +5083,28 @@
codegen_->AddSlowPath(slow_path);
__ j(kAboveEqual, slow_path->GetEntryLabel());
} else {
- CpuRegister length = length_loc.AsRegister<CpuRegister>();
- if (index_loc.IsConstant()) {
- int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
- __ cmpl(length, Immediate(value));
+ HInstruction* array_length = instruction->InputAt(1);
+ if (array_length->IsEmittedAtUseSite()) {
+ // Address the length field in the array.
+ DCHECK(array_length->IsArrayLength());
+ uint32_t len_offset = CodeGenerator::GetArrayLengthOffset(array_length->AsArrayLength());
+ Location array_loc = array_length->GetLocations()->InAt(0);
+ Address array_len(array_loc.AsRegister<CpuRegister>(), len_offset);
+ if (index_loc.IsConstant()) {
+ int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
+ __ cmpl(array_len, Immediate(value));
+ } else {
+ __ cmpl(array_len, index_loc.AsRegister<CpuRegister>());
+ }
+ codegen_->MaybeRecordImplicitNullCheck(array_length);
} else {
- __ cmpl(length, index_loc.AsRegister<CpuRegister>());
+ CpuRegister length = length_loc.AsRegister<CpuRegister>();
+ if (index_loc.IsConstant()) {
+ int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
+ __ cmpl(length, Immediate(value));
+ } else {
+ __ cmpl(length, index_loc.AsRegister<CpuRegister>());
+ }
}
codegen_->AddSlowPath(slow_path);
__ j(kBelowEqual, slow_path->GetEntryLabel());
@@ -5654,7 +5714,7 @@
void LocationsBuilderX86_64::VisitThrow(HThrow* instruction) {
LocationSummary* locations =
- new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
}
@@ -6164,7 +6224,7 @@
void LocationsBuilderX86_64::VisitMonitorOperation(HMonitorOperation* instruction) {
LocationSummary* locations =
- new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
}
@@ -6385,7 +6445,7 @@
// Slow path used to mark the GC root `root`.
SlowPathCode* slow_path =
- new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathX86_64(instruction, root, root);
+ new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathX86_64(instruction, root);
codegen_->AddSlowPath(slow_path);
__ gs()->cmpl(Address::Absolute(Thread::IsGcMarkingOffset<kX86_64WordSize>().Int32Value(),
@@ -6516,7 +6576,7 @@
// Slow path used to mark the object `ref` when it is gray.
SlowPathCode* slow_path =
- new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathX86_64(instruction, ref, ref);
+ new (GetGraph()->GetArena()) ReadBarrierMarkSlowPathX86_64(instruction, ref);
AddSlowPath(slow_path);
// if (rb_state == ReadBarrier::gray_ptr_)
diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc
index 9d67373..e14f603 100644
--- a/compiler/optimizing/graph_visualizer.cc
+++ b/compiler/optimizing/graph_visualizer.cc
@@ -401,6 +401,9 @@
void VisitArrayLength(HArrayLength* array_length) OVERRIDE {
StartAttributeStream("is_string_length") << std::boolalpha
<< array_length->IsStringLength() << std::noboolalpha;
+ if (array_length->IsEmittedAtUseSite()) {
+ StartAttributeStream("emitted_at_use") << "true";
+ }
}
void VisitBoundsCheck(HBoundsCheck* bounds_check) OVERRIDE {
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index e0410dc..4ca0600 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -920,6 +920,7 @@
void InstructionSimplifierVisitor::VisitAdd(HAdd* instruction) {
HConstant* input_cst = instruction->GetConstantRight();
HInstruction* input_other = instruction->GetLeastConstantLeft();
+ bool integral_type = Primitive::IsIntegralType(instruction->GetType());
if ((input_cst != nullptr) && input_cst->IsArithmeticZero()) {
// Replace code looking like
// ADD dst, src, 0
@@ -928,7 +929,7 @@
// Note that we cannot optimize `x + 0.0` to `x` for floating-point. When
// `x` is `-0.0`, the former expression yields `0.0`, while the later
// yields `-0.0`.
- if (Primitive::IsIntegralType(instruction->GetType())) {
+ if (integral_type) {
instruction->ReplaceWith(input_other);
instruction->GetBlock()->RemoveInstruction(instruction);
RecordSimplification();
@@ -974,10 +975,31 @@
// so no need to return.
TryHandleAssociativeAndCommutativeOperation(instruction);
- if ((instruction->GetLeft()->IsSub() || instruction->GetRight()->IsSub()) &&
+ if ((left->IsSub() || right->IsSub()) &&
TrySubtractionChainSimplification(instruction)) {
return;
}
+
+ if (integral_type) {
+ // Replace code patterns looking like
+ // SUB dst1, x, y SUB dst1, x, y
+ // ADD dst2, dst1, y ADD dst2, y, dst1
+ // with
+ // SUB dst1, x, y
+ // ADD instruction is not needed in this case, we may use
+ // one of inputs of SUB instead.
+ if (left->IsSub() && left->InputAt(1) == right) {
+ instruction->ReplaceWith(left->InputAt(0));
+ RecordSimplification();
+ instruction->GetBlock()->RemoveInstruction(instruction);
+ return;
+ } else if (right->IsSub() && right->InputAt(1) == left) {
+ instruction->ReplaceWith(right->InputAt(0));
+ RecordSimplification();
+ instruction->GetBlock()->RemoveInstruction(instruction);
+ return;
+ }
+ }
}
void InstructionSimplifierVisitor::VisitAnd(HAnd* instruction) {
@@ -1511,6 +1533,29 @@
if (TrySubtractionChainSimplification(instruction)) {
return;
}
+
+ if (left->IsAdd()) {
+ // Replace code patterns looking like
+ // ADD dst1, x, y ADD dst1, x, y
+ // SUB dst2, dst1, y SUB dst2, dst1, x
+ // with
+ // ADD dst1, x, y
+ // SUB instruction is not needed in this case, we may use
+ // one of inputs of ADD instead.
+ // It is applicable to integral types only.
+ DCHECK(Primitive::IsIntegralType(type));
+ if (left->InputAt(1) == right) {
+ instruction->ReplaceWith(left->InputAt(0));
+ RecordSimplification();
+ instruction->GetBlock()->RemoveInstruction(instruction);
+ return;
+ } else if (left->InputAt(0) == right) {
+ instruction->ReplaceWith(left->InputAt(1));
+ RecordSimplification();
+ instruction->GetBlock()->RemoveInstruction(instruction);
+ return;
+ }
+ }
}
void InstructionSimplifierVisitor::VisitUShr(HUShr* instruction) {
diff --git a/compiler/optimizing/intrinsics_arm.cc b/compiler/optimizing/intrinsics_arm.cc
index 579fb9d..bbdcee4 100644
--- a/compiler/optimizing/intrinsics_arm.cc
+++ b/compiler/optimizing/intrinsics_arm.cc
@@ -1212,7 +1212,7 @@
void IntrinsicLocationsBuilderARM::VisitStringIndexOf(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCall,
+ LocationSummary::kCallOnMainOnly,
kIntrinsified);
// We have a hand-crafted assembly stub that follows the runtime calling convention. So it's
// best to align the inputs accordingly.
@@ -1232,7 +1232,7 @@
void IntrinsicLocationsBuilderARM::VisitStringIndexOfAfter(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCall,
+ LocationSummary::kCallOnMainOnly,
kIntrinsified);
// We have a hand-crafted assembly stub that follows the runtime calling convention. So it's
// best to align the inputs accordingly.
@@ -1250,7 +1250,7 @@
void IntrinsicLocationsBuilderARM::VisitStringNewStringFromBytes(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCall,
+ LocationSummary::kCallOnMainOnly,
kIntrinsified);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
@@ -1280,7 +1280,7 @@
void IntrinsicLocationsBuilderARM::VisitStringNewStringFromChars(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCall,
+ LocationSummary::kCallOnMainOnly,
kIntrinsified);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
@@ -1307,7 +1307,7 @@
void IntrinsicLocationsBuilderARM::VisitStringNewStringFromString(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCall,
+ LocationSummary::kCallOnMainOnly,
kIntrinsified);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
@@ -1665,7 +1665,7 @@
DCHECK_EQ(invoke->GetType(), Primitive::kPrimDouble);
LocationSummary* const locations = new (arena) LocationSummary(invoke,
- LocationSummary::kCall,
+ LocationSummary::kCallOnMainOnly,
kIntrinsified);
const InvokeRuntimeCallingConvention calling_convention;
@@ -1692,7 +1692,7 @@
DCHECK_EQ(invoke->GetType(), Primitive::kPrimDouble);
LocationSummary* const locations = new (arena) LocationSummary(invoke,
- LocationSummary::kCall,
+ LocationSummary::kCallOnMainOnly,
kIntrinsified);
const InvokeRuntimeCallingConvention calling_convention;
diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc
index 1d50753..16438a7 100644
--- a/compiler/optimizing/intrinsics_arm64.cc
+++ b/compiler/optimizing/intrinsics_arm64.cc
@@ -1405,7 +1405,7 @@
void IntrinsicLocationsBuilderARM64::VisitStringIndexOf(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCall,
+ LocationSummary::kCallOnMainOnly,
kIntrinsified);
// We have a hand-crafted assembly stub that follows the runtime calling convention. So it's
// best to align the inputs accordingly.
@@ -1425,7 +1425,7 @@
void IntrinsicLocationsBuilderARM64::VisitStringIndexOfAfter(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCall,
+ LocationSummary::kCallOnMainOnly,
kIntrinsified);
// We have a hand-crafted assembly stub that follows the runtime calling convention. So it's
// best to align the inputs accordingly.
@@ -1443,7 +1443,7 @@
void IntrinsicLocationsBuilderARM64::VisitStringNewStringFromBytes(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCall,
+ LocationSummary::kCallOnMainOnly,
kIntrinsified);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0)));
@@ -1473,7 +1473,7 @@
void IntrinsicLocationsBuilderARM64::VisitStringNewStringFromChars(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCall,
+ LocationSummary::kCallOnMainOnly,
kIntrinsified);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0)));
@@ -1500,7 +1500,7 @@
void IntrinsicLocationsBuilderARM64::VisitStringNewStringFromString(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCall,
+ LocationSummary::kCallOnMainOnly,
kIntrinsified);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0)));
@@ -1531,7 +1531,7 @@
DCHECK(Primitive::IsFloatingPointType(invoke->GetType()));
LocationSummary* const locations = new (arena) LocationSummary(invoke,
- LocationSummary::kCall,
+ LocationSummary::kCallOnMainOnly,
kIntrinsified);
InvokeRuntimeCallingConvention calling_convention;
@@ -1546,7 +1546,7 @@
DCHECK(Primitive::IsFloatingPointType(invoke->GetType()));
LocationSummary* const locations = new (arena) LocationSummary(invoke,
- LocationSummary::kCall,
+ LocationSummary::kCallOnMainOnly,
kIntrinsified);
InvokeRuntimeCallingConvention calling_convention;
diff --git a/compiler/optimizing/intrinsics_mips.cc b/compiler/optimizing/intrinsics_mips.cc
index d4f44d6..0bfa025 100644
--- a/compiler/optimizing/intrinsics_mips.cc
+++ b/compiler/optimizing/intrinsics_mips.cc
@@ -1875,7 +1875,7 @@
// int java.lang.String.compareTo(String anotherString)
void IntrinsicLocationsBuilderMIPS::VisitStringCompareTo(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCall,
+ LocationSummary::kCallOnMainOnly,
kIntrinsified);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
@@ -2071,7 +2071,7 @@
// int java.lang.String.indexOf(int ch)
void IntrinsicLocationsBuilderMIPS::VisitStringIndexOf(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCall,
+ LocationSummary::kCallOnMainOnly,
kIntrinsified);
// We have a hand-crafted assembly stub that follows the runtime
// calling convention. So it's best to align the inputs accordingly.
@@ -2096,7 +2096,7 @@
// int java.lang.String.indexOf(int ch, int fromIndex)
void IntrinsicLocationsBuilderMIPS::VisitStringIndexOfAfter(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCall,
+ LocationSummary::kCallOnMainOnly,
kIntrinsified);
// We have a hand-crafted assembly stub that follows the runtime
// calling convention. So it's best to align the inputs accordingly.
@@ -2122,7 +2122,7 @@
// java.lang.StringFactory.newStringFromBytes(byte[] data, int high, int offset, int byteCount)
void IntrinsicLocationsBuilderMIPS::VisitStringNewStringFromBytes(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCall,
+ LocationSummary::kCallOnMainOnly,
kIntrinsified);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
@@ -2155,7 +2155,7 @@
// java.lang.StringFactory.newStringFromChars(int offset, int charCount, char[] data)
void IntrinsicLocationsBuilderMIPS::VisitStringNewStringFromChars(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCall,
+ LocationSummary::kCallOnMainOnly,
kIntrinsified);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
@@ -2187,7 +2187,7 @@
// java.lang.StringFactory.newStringFromString(String toCopy)
void IntrinsicLocationsBuilderMIPS::VisitStringNewStringFromString(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCall,
+ LocationSummary::kCallOnMainOnly,
kIntrinsified);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
diff --git a/compiler/optimizing/intrinsics_mips64.cc b/compiler/optimizing/intrinsics_mips64.cc
index cc4971b..a9807bd 100644
--- a/compiler/optimizing/intrinsics_mips64.cc
+++ b/compiler/optimizing/intrinsics_mips64.cc
@@ -1519,7 +1519,7 @@
// int java.lang.String.compareTo(String anotherString)
void IntrinsicLocationsBuilderMIPS64::VisitStringCompareTo(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCall,
+ LocationSummary::kCallOnMainOnly,
kIntrinsified);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
@@ -1707,7 +1707,7 @@
// int java.lang.String.indexOf(int ch)
void IntrinsicLocationsBuilderMIPS64::VisitStringIndexOf(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCall,
+ LocationSummary::kCallOnMainOnly,
kIntrinsified);
// We have a hand-crafted assembly stub that follows the runtime
// calling convention. So it's best to align the inputs accordingly.
@@ -1728,7 +1728,7 @@
// int java.lang.String.indexOf(int ch, int fromIndex)
void IntrinsicLocationsBuilderMIPS64::VisitStringIndexOfAfter(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCall,
+ LocationSummary::kCallOnMainOnly,
kIntrinsified);
// We have a hand-crafted assembly stub that follows the runtime
// calling convention. So it's best to align the inputs accordingly.
@@ -1748,7 +1748,7 @@
// java.lang.StringFactory.newStringFromBytes(byte[] data, int high, int offset, int byteCount)
void IntrinsicLocationsBuilderMIPS64::VisitStringNewStringFromBytes(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCall,
+ LocationSummary::kCallOnMainOnly,
kIntrinsified);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
@@ -1783,7 +1783,7 @@
// java.lang.StringFactory.newStringFromChars(int offset, int charCount, char[] data)
void IntrinsicLocationsBuilderMIPS64::VisitStringNewStringFromChars(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCall,
+ LocationSummary::kCallOnMainOnly,
kIntrinsified);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
@@ -1816,7 +1816,7 @@
// java.lang.StringFactory.newStringFromString(String toCopy)
void IntrinsicLocationsBuilderMIPS64::VisitStringNewStringFromString(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCall,
+ LocationSummary::kCallOnMainOnly,
kIntrinsified);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
diff --git a/compiler/optimizing/intrinsics_x86.cc b/compiler/optimizing/intrinsics_x86.cc
index 812bdf5..6c81421 100644
--- a/compiler/optimizing/intrinsics_x86.cc
+++ b/compiler/optimizing/intrinsics_x86.cc
@@ -706,7 +706,7 @@
// We have to fall back to a call to the intrinsic.
LocationSummary* locations = new (arena) LocationSummary(invoke,
- LocationSummary::kCall);
+ LocationSummary::kCallOnMainOnly);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetFpuRegisterAt(0)));
locations->SetOut(Location::FpuRegisterLocation(XMM0));
@@ -774,7 +774,7 @@
// We have to fall back to a call to the intrinsic.
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCall);
+ LocationSummary::kCallOnMainOnly);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetFpuRegisterAt(0)));
locations->SetOut(Location::RegisterLocation(EAX));
@@ -831,7 +831,7 @@
static void CreateFPToFPCallLocations(ArenaAllocator* arena,
HInvoke* invoke) {
LocationSummary* locations = new (arena) LocationSummary(invoke,
- LocationSummary::kCall,
+ LocationSummary::kCallOnMainOnly,
kIntrinsified);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
@@ -985,7 +985,7 @@
static void CreateFPFPToFPCallLocations(ArenaAllocator* arena,
HInvoke* invoke) {
LocationSummary* locations = new (arena) LocationSummary(invoke,
- LocationSummary::kCall,
+ LocationSummary::kCallOnMainOnly,
kIntrinsified);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
@@ -1216,7 +1216,7 @@
void IntrinsicLocationsBuilderX86::VisitStringCompareTo(HInvoke* invoke) {
// The inputs plus one temp.
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCall,
+ LocationSummary::kCallOnMainOnly,
kIntrinsified);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
@@ -1490,7 +1490,7 @@
void IntrinsicLocationsBuilderX86::VisitStringNewStringFromBytes(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCall,
+ LocationSummary::kCallOnMainOnly,
kIntrinsified);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
@@ -1518,7 +1518,7 @@
void IntrinsicLocationsBuilderX86::VisitStringNewStringFromChars(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCall,
+ LocationSummary::kCallOnMainOnly,
kIntrinsified);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
@@ -1543,7 +1543,7 @@
void IntrinsicLocationsBuilderX86::VisitStringNewStringFromString(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCall,
+ LocationSummary::kCallOnMainOnly,
kIntrinsified);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc
index 891aaf5..28f1f4f 100644
--- a/compiler/optimizing/intrinsics_x86_64.cc
+++ b/compiler/optimizing/intrinsics_x86_64.cc
@@ -526,7 +526,7 @@
// We have to fall back to a call to the intrinsic.
LocationSummary* locations = new (arena) LocationSummary(invoke,
- LocationSummary::kCall);
+ LocationSummary::kCallOnMainOnly);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetFpuRegisterAt(0)));
locations->SetOut(Location::FpuRegisterLocation(XMM0));
@@ -588,7 +588,7 @@
// We have to fall back to a call to the intrinsic.
LocationSummary* locations = new (arena) LocationSummary(invoke,
- LocationSummary::kCall);
+ LocationSummary::kCallOnMainOnly);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetFpuRegisterAt(0)));
locations->SetOut(Location::RegisterLocation(RAX));
@@ -699,7 +699,7 @@
static void CreateFPToFPCallLocations(ArenaAllocator* arena,
HInvoke* invoke) {
LocationSummary* locations = new (arena) LocationSummary(invoke,
- LocationSummary::kCall,
+ LocationSummary::kCallOnMainOnly,
kIntrinsified);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
@@ -839,7 +839,7 @@
static void CreateFPFPToFPCallLocations(ArenaAllocator* arena,
HInvoke* invoke) {
LocationSummary* locations = new (arena) LocationSummary(invoke,
- LocationSummary::kCall,
+ LocationSummary::kCallOnMainOnly,
kIntrinsified);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
@@ -1303,7 +1303,7 @@
void IntrinsicLocationsBuilderX86_64::VisitStringCompareTo(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCall,
+ LocationSummary::kCallOnMainOnly,
kIntrinsified);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
@@ -1577,7 +1577,7 @@
void IntrinsicLocationsBuilderX86_64::VisitStringNewStringFromBytes(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCall,
+ LocationSummary::kCallOnMainOnly,
kIntrinsified);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
@@ -1606,7 +1606,7 @@
void IntrinsicLocationsBuilderX86_64::VisitStringNewStringFromChars(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCall,
+ LocationSummary::kCallOnMainOnly,
kIntrinsified);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
@@ -1632,7 +1632,7 @@
void IntrinsicLocationsBuilderX86_64::VisitStringNewStringFromString(HInvoke* invoke) {
LocationSummary* locations = new (arena_) LocationSummary(invoke,
- LocationSummary::kCall,
+ LocationSummary::kCallOnMainOnly,
kIntrinsified);
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
diff --git a/compiler/optimizing/locations.h b/compiler/optimizing/locations.h
index 3f27c91..7a78bfd 100644
--- a/compiler/optimizing/locations.h
+++ b/compiler/optimizing/locations.h
@@ -481,7 +481,7 @@
enum CallKind {
kNoCall,
kCallOnSlowPath,
- kCall
+ kCallOnMainOnly
};
LocationSummary(HInstruction* instruction,
@@ -541,7 +541,7 @@
Location Out() const { return output_; }
bool CanCall() const { return call_kind_ != kNoCall; }
- bool WillCall() const { return call_kind_ == kCall; }
+ bool WillCall() const { return call_kind_ == kCallOnMainOnly; }
bool OnlyCallsOnSlowPath() const { return call_kind_ == kCallOnSlowPath; }
bool NeedsSafepoint() const { return CanCall(); }
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index d703b0f..d6e09d7 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -37,6 +37,10 @@
#include "pc_relative_fixups_x86.h"
#endif
+#if defined(ART_ENABLE_CODEGEN_x86) || defined(ART_ENABLE_CODEGEN_x86_64)
+#include "x86_memory_gen.h"
+#endif
+
#include "art_method-inl.h"
#include "base/arena_allocator.h"
#include "base/arena_containers.h"
@@ -485,13 +489,27 @@
case kX86: {
x86::PcRelativeFixups* pc_relative_fixups =
new (arena) x86::PcRelativeFixups(graph, codegen, stats);
+ x86::X86MemoryOperandGeneration* memory_gen =
+ new(arena) x86::X86MemoryOperandGeneration(graph, stats, codegen);
HOptimization* x86_optimizations[] = {
- pc_relative_fixups
+ pc_relative_fixups,
+ memory_gen
};
RunOptimizations(x86_optimizations, arraysize(x86_optimizations), pass_observer);
break;
}
#endif
+#ifdef ART_ENABLE_CODEGEN_x86_64
+ case kX86_64: {
+ x86::X86MemoryOperandGeneration* memory_gen =
+ new(arena) x86::X86MemoryOperandGeneration(graph, stats, codegen);
+ HOptimization* x86_64_optimizations[] = {
+ memory_gen
+ };
+ RunOptimizations(x86_64_optimizations, arraysize(x86_64_optimizations), pass_observer);
+ break;
+ }
+#endif
default:
break;
}
diff --git a/compiler/optimizing/register_allocator.cc b/compiler/optimizing/register_allocator.cc
index 9d99668..1b33408 100644
--- a/compiler/optimizing/register_allocator.cc
+++ b/compiler/optimizing/register_allocator.cc
@@ -1346,9 +1346,15 @@
// Find an available spill slot.
size_t slot = 0;
for (size_t e = spill_slots->size(); slot < e; ++slot) {
- if ((*spill_slots)[slot] <= parent->GetStart()
- && (slot == (e - 1) || (*spill_slots)[slot + 1] <= parent->GetStart())) {
- break;
+ if ((*spill_slots)[slot] <= parent->GetStart()) {
+ if (!parent->NeedsTwoSpillSlots()) {
+ // One spill slot is sufficient.
+ break;
+ }
+ if (slot == e - 1 || (*spill_slots)[slot + 1] <= parent->GetStart()) {
+ // Two spill slots are available.
+ break;
+ }
}
}
diff --git a/compiler/optimizing/x86_memory_gen.cc b/compiler/optimizing/x86_memory_gen.cc
new file mode 100644
index 0000000..195159f
--- /dev/null
+++ b/compiler/optimizing/x86_memory_gen.cc
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "x86_memory_gen.h"
+#include "code_generator.h"
+
+namespace art {
+namespace x86 {
+
+/**
+ * Replace instructions with memory operand forms.
+ */
+class MemoryOperandVisitor : public HGraphVisitor {
+ public:
+ MemoryOperandVisitor(HGraph* graph, bool do_implicit_null_checks)
+ : HGraphVisitor(graph),
+ do_implicit_null_checks_(do_implicit_null_checks) {}
+
+ private:
+ void VisitBoundsCheck(HBoundsCheck* check) OVERRIDE {
+ // Replace the length by the array itself, so that we can do compares to memory.
+ HArrayLength* array_len = check->InputAt(1)->AsArrayLength();
+
+ // We only want to replace an ArrayLength.
+ if (array_len == nullptr) {
+ return;
+ }
+
+ HInstruction* array = array_len->InputAt(0);
+ DCHECK_EQ(array->GetType(), Primitive::kPrimNot);
+
+ // Don't apply this optimization when the array is nullptr.
+ if (array->IsConstant() || (array->IsNullCheck() && array->InputAt(0)->IsConstant())) {
+ return;
+ }
+
+ // Is there a null check that could be an implicit check?
+ if (array->IsNullCheck() && do_implicit_null_checks_) {
+ // The ArrayLen may generate the implicit null check. Can the
+ // bounds check do so as well?
+ if (array_len->GetNextDisregardingMoves() != check) {
+ // No, it won't. Leave as is.
+ return;
+ }
+ }
+
+ // Can we suppress the ArrayLength and generate at BoundCheck?
+ if (array_len->HasOnlyOneNonEnvironmentUse()) {
+ array_len->MarkEmittedAtUseSite();
+ // We need the ArrayLength just before the BoundsCheck.
+ array_len->MoveBefore(check);
+ }
+ }
+
+ bool do_implicit_null_checks_;
+};
+
+X86MemoryOperandGeneration::X86MemoryOperandGeneration(HGraph* graph,
+ OptimizingCompilerStats* stats,
+ CodeGenerator* codegen)
+ : HOptimization(graph, kX86MemoryOperandGenerationPassName, stats),
+ do_implicit_null_checks_(codegen->GetCompilerOptions().GetImplicitNullChecks()) {
+}
+
+void X86MemoryOperandGeneration::Run() {
+ MemoryOperandVisitor visitor(graph_, do_implicit_null_checks_);
+ visitor.VisitInsertionOrder();
+}
+
+} // namespace x86
+} // namespace art
diff --git a/compiler/optimizing/x86_memory_gen.h b/compiler/optimizing/x86_memory_gen.h
new file mode 100644
index 0000000..7e88681
--- /dev/null
+++ b/compiler/optimizing/x86_memory_gen.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#ifndef ART_COMPILER_OPTIMIZING_X86_MEMORY_GEN_H_
+#define ART_COMPILER_OPTIMIZING_X86_MEMORY_GEN_H_
+
+#include "nodes.h"
+#include "optimization.h"
+
+namespace art {
+class CodeGenerator;
+
+namespace x86 {
+
+class X86MemoryOperandGeneration : public HOptimization {
+ public:
+ X86MemoryOperandGeneration(HGraph* graph,
+ OptimizingCompilerStats* stats,
+ CodeGenerator* codegen);
+
+ void Run() OVERRIDE;
+
+ static constexpr const char* kX86MemoryOperandGenerationPassName =
+ "x86_memory_operand_generation";
+
+ private:
+ bool do_implicit_null_checks_;
+};
+
+} // namespace x86
+} // namespace art
+
+#endif // ART_COMPILER_OPTIMIZING_X86_MEMORY_GEN_H_
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index c133980..8d20e5b 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -2038,7 +2038,7 @@
location.c_str(), location.c_str(), kVerifyChecksum, &error_msg, opened_dex_files)) {
// If we fail to open the dex file because it's been stripped, try to open the dex file
// from its corresponding oat file.
- OatFileAssistant oat_file_assistant(location.c_str(), isa, false, false);
+ OatFileAssistant oat_file_assistant(location.c_str(), isa, false);
std::unique_ptr<OatFile> oat_file(oat_file_assistant.GetBestOatFile());
if (oat_file == nullptr) {
LOG(WARNING) << "Failed to open dex file and associated oat file for '" << location
diff --git a/dexdump/dexdump.cc b/dexdump/dexdump.cc
index 565a8f0..96c3267 100644
--- a/dexdump/dexdump.cc
+++ b/dexdump/dexdump.cc
@@ -118,7 +118,7 @@
* "[I" becomes "int[]". Also converts '$' to '.', which means this
* form can't be converted back to a descriptor.
*/
-static char* descriptorToDot(const char* str) {
+static std::unique_ptr<char[]> descriptorToDot(const char* str) {
int targetLen = strlen(str);
int offset = 0;
@@ -145,8 +145,7 @@
}
// Copy class name over.
- char* newStr = reinterpret_cast<char*>(
- malloc(targetLen + arrayDepth * 2 + 1));
+ std::unique_ptr<char[]> newStr(new char[targetLen + arrayDepth * 2 + 1]);
int i = 0;
for (; i < targetLen; i++) {
const char ch = str[offset + i];
@@ -165,12 +164,10 @@
/*
* Converts the class name portion of a type descriptor to human-readable
- * "dotted" form.
- *
- * Returns a newly-allocated string.
+ * "dotted" form. For example, "Ljava/lang/String;" becomes "String".
*/
-static char* descriptorClassToDot(const char* str) {
- // Reduce to just the class name, trimming trailing ';'.
+static std::unique_ptr<char[]> descriptorClassToDot(const char* str) {
+ // Reduce to just the class name prefix.
const char* lastSlash = strrchr(str, '/');
if (lastSlash == nullptr) {
lastSlash = str + 1; // start past 'L'
@@ -178,13 +175,14 @@
lastSlash++; // start past '/'
}
- char* newStr = strdup(lastSlash);
- newStr[strlen(lastSlash) - 1] = '\0';
- for (char* cp = newStr; *cp != '\0'; cp++) {
- if (*cp == '$') {
- *cp = '.';
- }
+ // Copy class name over, trimming trailing ';'.
+ const int targetLen = strlen(lastSlash);
+ std::unique_ptr<char[]> newStr(new char[targetLen]);
+ for (int i = 0; i < targetLen - 1; i++) {
+ const char ch = lastSlash[i];
+ newStr[i] = ch == '$' ? '.' : ch;
} // for
+ newStr[targetLen - 1] = '\0';
return newStr;
}
@@ -723,9 +721,8 @@
if (gOptions.outputFormat == OUTPUT_PLAIN) {
fprintf(gOutFile, " #%d : '%s'\n", i, interfaceName);
} else {
- char* dotted = descriptorToDot(interfaceName);
- fprintf(gOutFile, "<implements name=\"%s\">\n</implements>\n", dotted);
- free(dotted);
+ std::unique_ptr<char[]> dot(descriptorToDot(interfaceName));
+ fprintf(gOutFile, "<implements name=\"%s\">\n</implements>\n", dot.get());
}
}
@@ -1128,11 +1125,9 @@
const char* backDescriptor = pDexFile->StringByTypeIdx(pMethodId.class_idx_);
// Generate header.
- char* tmp = descriptorToDot(backDescriptor);
- fprintf(gOutFile, "%06x: "
- "|[%06x] %s.%s:%s\n",
- codeOffset, codeOffset, tmp, name, signature.ToString().c_str());
- free(tmp);
+ std::unique_ptr<char[]> dot(descriptorToDot(backDescriptor));
+ fprintf(gOutFile, "%06x: |[%06x] %s.%s:%s\n",
+ codeOffset, codeOffset, dot.get(), name, signature.ToString().c_str());
// Iterate over all instructions.
const u2* insns = pCode->insns_;
@@ -1211,12 +1206,10 @@
// Method name and prototype.
if (constructor) {
- char* tmp = descriptorClassToDot(backDescriptor);
- fprintf(gOutFile, "<constructor name=\"%s\"\n", tmp);
- free(tmp);
- tmp = descriptorToDot(backDescriptor);
- fprintf(gOutFile, " type=\"%s\"\n", tmp);
- free(tmp);
+ std::unique_ptr<char[]> dot(descriptorClassToDot(backDescriptor));
+ fprintf(gOutFile, "<constructor name=\"%s\"\n", dot.get());
+ dot = descriptorToDot(backDescriptor);
+ fprintf(gOutFile, " type=\"%s\"\n", dot.get());
} else {
fprintf(gOutFile, "<method name=\"%s\"\n", name);
const char* returnType = strrchr(typeDescriptor, ')');
@@ -1224,9 +1217,8 @@
fprintf(stderr, "bad method type descriptor '%s'\n", typeDescriptor);
goto bail;
}
- char* tmp = descriptorToDot(returnType+1);
- fprintf(gOutFile, " return=\"%s\"\n", tmp);
- free(tmp);
+ std::unique_ptr<char[]> dot(descriptorToDot(returnType + 1));
+ fprintf(gOutFile, " return=\"%s\"\n", dot.get());
fprintf(gOutFile, " abstract=%s\n", quotedBool((flags & kAccAbstract) != 0));
fprintf(gOutFile, " native=%s\n", quotedBool((flags & kAccNative) != 0));
fprintf(gOutFile, " synchronized=%s\n", quotedBool(
@@ -1259,7 +1251,7 @@
} while (*cp++ != ';');
} else {
// Primitive char, copy it.
- if (strchr("ZBCSIFJD", *base) == NULL) {
+ if (strchr("ZBCSIFJD", *base) == nullptr) {
fprintf(stderr, "ERROR: bad method signature '%s'\n", base);
break; // while
}
@@ -1267,10 +1259,9 @@
}
// Null terminate and display.
*cp++ = '\0';
- char* tmp = descriptorToDot(tmpBuf);
+ std::unique_ptr<char[]> dot(descriptorToDot(tmpBuf));
fprintf(gOutFile, "<parameter name=\"arg%d\" type=\"%s\">\n"
- "</parameter>\n", argNum++, tmp);
- free(tmp);
+ "</parameter>\n", argNum++, dot.get());
} // while
free(tmpBuf);
if (constructor) {
@@ -1312,9 +1303,8 @@
}
} else if (gOptions.outputFormat == OUTPUT_XML) {
fprintf(gOutFile, "<field name=\"%s\"\n", name);
- char *tmp = descriptorToDot(typeDescriptor);
- fprintf(gOutFile, " type=\"%s\"\n", tmp);
- free(tmp);
+ std::unique_ptr<char[]> dot(descriptorToDot(typeDescriptor));
+ fprintf(gOutFile, " type=\"%s\"\n", dot.get());
fprintf(gOutFile, " transient=%s\n", quotedBool((flags & kAccTransient) != 0));
fprintf(gOutFile, " volatile=%s\n", quotedBool((flags & kAccVolatile) != 0));
// The "value=" is not knowable w/o parsing annotations.
@@ -1469,13 +1459,11 @@
}
fprintf(gOutFile, " Interfaces -\n");
} else {
- char* tmp = descriptorClassToDot(classDescriptor);
- fprintf(gOutFile, "<class name=\"%s\"\n", tmp);
- free(tmp);
+ std::unique_ptr<char[]> dot(descriptorClassToDot(classDescriptor));
+ fprintf(gOutFile, "<class name=\"%s\"\n", dot.get());
if (superclassDescriptor != nullptr) {
- tmp = descriptorToDot(superclassDescriptor);
- fprintf(gOutFile, " extends=\"%s\"\n", tmp);
- free(tmp);
+ dot = descriptorToDot(superclassDescriptor);
+ fprintf(gOutFile, " extends=\"%s\"\n", dot.get());
}
fprintf(gOutFile, " interface=%s\n",
quotedBool((pClassDef.access_flags_ & kAccInterface) != 0));
diff --git a/dexlist/dexlist.cc b/dexlist/dexlist.cc
index 6f19df5..a1bde0e 100644
--- a/dexlist/dexlist.cc
+++ b/dexlist/dexlist.cc
@@ -60,18 +60,17 @@
* final ";" (if any) have been removed and all occurrences of '/'
* have been changed to '.'.
*/
-static char* descriptorToDot(const char* str) {
- size_t at = strlen(str);
+static std::unique_ptr<char[]> descriptorToDot(const char* str) {
+ size_t len = strlen(str);
if (str[0] == 'L') {
- at -= 2; // Two fewer chars to copy.
- str++;
+ len -= 2; // Two fewer chars to copy (trims L and ;).
+ str++; // Start past 'L'.
}
- char* newStr = reinterpret_cast<char*>(malloc(at + 1));
- newStr[at] = '\0';
- while (at > 0) {
- at--;
- newStr[at] = (str[at] == '/') ? '.' : str[at];
+ std::unique_ptr<char[]> newStr(new char[len + 1]);
+ for (size_t i = 0; i < len; i++) {
+ newStr[i] = (str[i] == '/') ? '.' : str[i];
}
+ newStr[len] = '\0';
return newStr;
}
@@ -103,14 +102,13 @@
const DexFile::MethodId& pMethodId = pDexFile->GetMethodId(idx);
const char* methodName = pDexFile->StringDataByIdx(pMethodId.name_idx_);
const char* classDescriptor = pDexFile->StringByTypeIdx(pMethodId.class_idx_);
- char* className = descriptorToDot(classDescriptor);
+ std::unique_ptr<char[]> className(descriptorToDot(classDescriptor));
const u4 insnsOff = codeOffset + 0x10;
// Don't list methods that do not match a particular query.
if (gOptions.methodToFind != nullptr &&
- (strcmp(gOptions.classToFind, className) != 0 ||
+ (strcmp(gOptions.classToFind, className.get()) != 0 ||
strcmp(gOptions.methodToFind, methodName) != 0)) {
- free(className);
return;
}
@@ -130,10 +128,9 @@
// Dump actual method information.
fprintf(gOutFile, "0x%08x %d %s %s %s %s %d\n",
insnsOff, pCode->insns_size_in_code_units_ * 2,
- className, methodName, typeDesc, fileName, firstLine);
+ className.get(), methodName, typeDesc, fileName, firstLine);
free(typeDesc);
- free(className);
}
/*
diff --git a/disassembler/disassembler_arm.cc b/disassembler/disassembler_arm.cc
index 1a3e3f5..c410cd9 100644
--- a/disassembler/disassembler_arm.cc
+++ b/disassembler/disassembler_arm.cc
@@ -782,23 +782,13 @@
args << Rm;
// Shift operand.
- bool noShift = (imm5 == 0 && shift_type != 0x3);
+ bool noShift = (imm5 == 0 && shift_type == 0x0);
if (!noShift) {
args << ", ";
- switch (shift_type) {
- case 0x0: args << "lsl"; break;
- case 0x1: args << "lsr"; break;
- case 0x2: args << "asr"; break;
- case 0x3:
- if (imm5 == 0) {
- args << "rrx";
- } else {
- args << "ror #" << imm5;
- }
- break;
- }
- if (shift_type != 0x3 /* rrx */) {
- args << StringPrintf(" #%d", (0 != imm5 || 0 == shift_type) ? imm5 : 32);
+ if (shift_type == 0x3u && imm5 == 0u) {
+ args << "rrx";
+ } else {
+ args << kThumb2ShiftOperations[shift_type] << " #" << ((0 != imm5) ? imm5 : 32);
}
}
@@ -1516,82 +1506,82 @@
}
break;
}
- default: // more formats
- if ((op2 >> 4) == 2) { // 010xxxx
- // data processing (register)
- if ((instr & 0x0080f0f0) == 0x0000f000) {
- // LSL, LSR, ASR, ROR
- uint32_t shift_op = (instr >> 21) & 3;
- uint32_t S = (instr >> 20) & 1;
- ArmRegister Rd(instr, 8);
+ default: // more formats
+ if ((op2 >> 4) == 2) { // 010xxxx
+ // data processing (register)
+ if ((instr & 0x0080f0f0) == 0x0000f000) {
+ // LSL, LSR, ASR, ROR
+ uint32_t shift_op = (instr >> 21) & 3;
+ uint32_t S = (instr >> 20) & 1;
+ ArmRegister Rd(instr, 8);
+ ArmRegister Rn(instr, 16);
+ ArmRegister Rm(instr, 0);
+ opcode << kThumb2ShiftOperations[shift_op] << (S != 0 ? "s" : "");
+ args << Rd << ", " << Rn << ", " << Rm;
+ }
+ } else if ((op2 >> 3) == 6) { // 0110xxx
+ // Multiply, multiply accumulate, and absolute difference
+ op1 = (instr >> 20) & 0x7;
+ op2 = (instr >> 4) & 0x1;
+ ArmRegister Ra(instr, 12);
ArmRegister Rn(instr, 16);
ArmRegister Rm(instr, 0);
- opcode << kThumb2ShiftOperations[shift_op] << (S != 0 ? "s" : "");
- args << Rd << ", " << Rn << ", " << Rm;
- }
- } else if ((op2 >> 3) == 6) { // 0110xxx
- // Multiply, multiply accumulate, and absolute difference
- op1 = (instr >> 20) & 0x7;
- op2 = (instr >> 4) & 0x1;
- ArmRegister Ra(instr, 12);
- ArmRegister Rn(instr, 16);
- ArmRegister Rm(instr, 0);
- ArmRegister Rd(instr, 8);
- switch (op1) {
- case 0:
- if (op2 == 0) {
- if (Ra.r == 0xf) {
- opcode << "mul";
- args << Rd << ", " << Rn << ", " << Rm;
+ ArmRegister Rd(instr, 8);
+ switch (op1) {
+ case 0:
+ if (op2 == 0) {
+ if (Ra.r == 0xf) {
+ opcode << "mul";
+ args << Rd << ", " << Rn << ", " << Rm;
+ } else {
+ opcode << "mla";
+ args << Rd << ", " << Rn << ", " << Rm << ", " << Ra;
+ }
} else {
- opcode << "mla";
+ opcode << "mls";
args << Rd << ", " << Rn << ", " << Rm << ", " << Ra;
}
- } else {
- opcode << "mls";
- args << Rd << ", " << Rn << ", " << Rm << ", " << Ra;
+ break;
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ break; // do these sometime
}
- break;
- case 1:
- case 2:
- case 3:
- case 4:
- case 5:
- case 6:
- break; // do these sometime
+ } else if ((op2 >> 3) == 7) { // 0111xxx
+ // Long multiply, long multiply accumulate, and divide
+ op1 = (instr >> 20) & 0x7;
+ op2 = (instr >> 4) & 0xf;
+ ArmRegister Rn(instr, 16);
+ ArmRegister Rm(instr, 0);
+ ArmRegister Rd(instr, 8);
+ ArmRegister RdHi(instr, 8);
+ ArmRegister RdLo(instr, 12);
+ switch (op1) {
+ case 0:
+ opcode << "smull";
+ args << RdLo << ", " << RdHi << ", " << Rn << ", " << Rm;
+ break;
+ case 1:
+ opcode << "sdiv";
+ args << Rd << ", " << Rn << ", " << Rm;
+ break;
+ case 2:
+ opcode << "umull";
+ args << RdLo << ", " << RdHi << ", " << Rn << ", " << Rm;
+ break;
+ case 3:
+ opcode << "udiv";
+ args << Rd << ", " << Rn << ", " << Rm;
+ break;
+ case 4:
+ case 5:
+ case 6:
+ break; // TODO: when we generate these...
+ }
}
- } else if ((op2 >> 3) == 7) { // 0111xxx
- // Long multiply, long multiply accumulate, and divide
- op1 = (instr >> 20) & 0x7;
- op2 = (instr >> 4) & 0xf;
- ArmRegister Rn(instr, 16);
- ArmRegister Rm(instr, 0);
- ArmRegister Rd(instr, 8);
- ArmRegister RdHi(instr, 8);
- ArmRegister RdLo(instr, 12);
- switch (op1) {
- case 0:
- opcode << "smull";
- args << RdLo << ", " << RdHi << ", " << Rn << ", " << Rm;
- break;
- case 1:
- opcode << "sdiv";
- args << Rd << ", " << Rn << ", " << Rm;
- break;
- case 2:
- opcode << "umull";
- args << RdLo << ", " << RdHi << ", " << Rn << ", " << Rm;
- break;
- case 3:
- opcode << "udiv";
- args << Rd << ", " << Rn << ", " << Rm;
- break;
- case 4:
- case 5:
- case 6:
- break; // TODO: when we generate these...
- }
- }
}
break;
default:
diff --git a/runtime/arch/arm/entrypoints_init_arm.cc b/runtime/arch/arm/entrypoints_init_arm.cc
index 4c68862..8f18ff3 100644
--- a/runtime/arch/arm/entrypoints_init_arm.cc
+++ b/runtime/arch/arm/entrypoints_init_arm.cc
@@ -30,6 +30,22 @@
extern "C" uint32_t artIsAssignableFromCode(const mirror::Class* klass,
const mirror::Class* ref_class);
+// Read barrier entrypoints.
+// art_quick_read_barrier_mark_regX uses an non-standard calling
+// convention: it expects its input in register X and returns its
+// result in that same register.
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg01(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg02(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg03(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg04(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg05(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg06(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg07(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg08(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg09(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg10(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg11(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg12(mirror::Object*);
// Used by soft float.
// Single-precision FP arithmetics.
@@ -103,7 +119,39 @@
// Read barrier.
qpoints->pReadBarrierJni = ReadBarrierJni;
- qpoints->pReadBarrierMark = artReadBarrierMark;
+ qpoints->pReadBarrierMarkReg00 = artReadBarrierMark;
+ qpoints->pReadBarrierMarkReg01 = art_quick_read_barrier_mark_reg01;
+ qpoints->pReadBarrierMarkReg02 = art_quick_read_barrier_mark_reg02;
+ qpoints->pReadBarrierMarkReg03 = art_quick_read_barrier_mark_reg03;
+ qpoints->pReadBarrierMarkReg04 = art_quick_read_barrier_mark_reg04;
+ qpoints->pReadBarrierMarkReg05 = art_quick_read_barrier_mark_reg05;
+ qpoints->pReadBarrierMarkReg06 = art_quick_read_barrier_mark_reg06;
+ qpoints->pReadBarrierMarkReg07 = art_quick_read_barrier_mark_reg07;
+ qpoints->pReadBarrierMarkReg08 = art_quick_read_barrier_mark_reg08;
+ qpoints->pReadBarrierMarkReg09 = art_quick_read_barrier_mark_reg09;
+ qpoints->pReadBarrierMarkReg10 = art_quick_read_barrier_mark_reg10;
+ qpoints->pReadBarrierMarkReg11 = art_quick_read_barrier_mark_reg11;
+ qpoints->pReadBarrierMarkReg12 = art_quick_read_barrier_mark_reg12;
+ qpoints->pReadBarrierMarkReg13 = nullptr; // Cannot use register 13 (SP) to pass arguments.
+ qpoints->pReadBarrierMarkReg14 = nullptr; // Cannot use register 14 (LR) to pass arguments.
+ qpoints->pReadBarrierMarkReg15 = nullptr; // Cannot use register 15 (PC) to pass arguments.
+ // ARM has only 16 core registers.
+ qpoints->pReadBarrierMarkReg16 = nullptr;
+ qpoints->pReadBarrierMarkReg17 = nullptr;
+ qpoints->pReadBarrierMarkReg18 = nullptr;
+ qpoints->pReadBarrierMarkReg19 = nullptr;
+ qpoints->pReadBarrierMarkReg20 = nullptr;
+ qpoints->pReadBarrierMarkReg21 = nullptr;
+ qpoints->pReadBarrierMarkReg22 = nullptr;
+ qpoints->pReadBarrierMarkReg23 = nullptr;
+ qpoints->pReadBarrierMarkReg24 = nullptr;
+ qpoints->pReadBarrierMarkReg25 = nullptr;
+ qpoints->pReadBarrierMarkReg26 = nullptr;
+ qpoints->pReadBarrierMarkReg27 = nullptr;
+ qpoints->pReadBarrierMarkReg28 = nullptr;
+ qpoints->pReadBarrierMarkReg29 = nullptr;
+ qpoints->pReadBarrierMarkReg30 = nullptr;
+ qpoints->pReadBarrierMarkReg31 = nullptr;
qpoints->pReadBarrierSlow = artReadBarrierSlow;
qpoints->pReadBarrierForRootSlow = artReadBarrierForRootSlow;
}
diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S
index d940164..82d64b9 100644
--- a/runtime/arch/arm/quick_entrypoints_arm.S
+++ b/runtime/arch/arm/quick_entrypoints_arm.S
@@ -1743,3 +1743,43 @@
.cfi_adjust_cfa_offset -4
pop {pc}
END art_quick_l2f
+
+ /*
+ * Create a function `name` calling the ReadBarrier::Mark routine,
+ * getting its argument and returning its result through register
+ * `reg`, thus following a non-standard runtime calling convention:
+ * - `reg` is used to pass the (sole) argument of this function
+ * (instead of R0);
+ * - `reg` is used to return the result of this function (instead of R0);
+ * - R0 is treated like a normal (non-argument) caller-save register;
+ * - everything else is the same as in the standard runtime calling
+ * convention (e.g. same callee-save registers).
+ */
+.macro READ_BARRIER_MARK_REG name, reg
+ENTRY \name
+ push {lr} @ save return address
+ .cfi_adjust_cfa_offset 4
+ .cfi_rel_offset lr, 0
+ sub sp, #4 @ push padding (native calling convention 8-byte alignment)
+ .cfi_adjust_cfa_offset 4
+ mov r0, \reg @ pass arg1 - obj from `reg`
+ bl artReadBarrierMark @ artReadBarrierMark(obj)
+ mov \reg, r0 @ return result into `reg`
+ add sp, #4 @ pop padding
+ .cfi_adjust_cfa_offset -4
+ pop {pc} @ return
+END \name
+.endm
+
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg01, r1
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg02, r2
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg03, r3
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg04, r4
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg05, r5
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg06, r6
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg07, r7
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg08, r8
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg09, r9
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg10, r10
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg11, r11
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg12, r12
diff --git a/runtime/arch/arm64/entrypoints_init_arm64.cc b/runtime/arch/arm64/entrypoints_init_arm64.cc
index bf0f647..c3188b6 100644
--- a/runtime/arch/arm64/entrypoints_init_arm64.cc
+++ b/runtime/arch/arm64/entrypoints_init_arm64.cc
@@ -30,6 +30,42 @@
extern "C" uint32_t artIsAssignableFromCode(const mirror::Class* klass,
const mirror::Class* ref_class);
+// Read barrier entrypoints.
+// art_quick_read_barrier_mark_regX uses an non-standard calling
+// convention: it expects its input in register X and returns its
+// result in that same register.
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg01(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg02(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg03(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg04(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg05(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg06(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg07(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg08(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg09(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg10(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg11(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg12(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg12(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg13(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg14(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg15(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg16(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg17(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg18(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg19(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg20(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg21(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg22(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg22(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg23(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg24(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg25(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg26(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg27(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg28(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg29(mirror::Object*);
+
void InitEntryPoints(JniEntryPoints* jpoints, QuickEntryPoints* qpoints) {
DefaultInitEntryPoints(jpoints, qpoints);
@@ -86,7 +122,38 @@
// Read barrier.
qpoints->pReadBarrierJni = ReadBarrierJni;
- qpoints->pReadBarrierMark = artReadBarrierMark;
+ qpoints->pReadBarrierMarkReg00 = artReadBarrierMark;
+ qpoints->pReadBarrierMarkReg01 = art_quick_read_barrier_mark_reg01;
+ qpoints->pReadBarrierMarkReg02 = art_quick_read_barrier_mark_reg02;
+ qpoints->pReadBarrierMarkReg03 = art_quick_read_barrier_mark_reg03;
+ qpoints->pReadBarrierMarkReg04 = art_quick_read_barrier_mark_reg04;
+ qpoints->pReadBarrierMarkReg05 = art_quick_read_barrier_mark_reg05;
+ qpoints->pReadBarrierMarkReg06 = art_quick_read_barrier_mark_reg06;
+ qpoints->pReadBarrierMarkReg07 = art_quick_read_barrier_mark_reg07;
+ qpoints->pReadBarrierMarkReg08 = art_quick_read_barrier_mark_reg08;
+ qpoints->pReadBarrierMarkReg09 = art_quick_read_barrier_mark_reg09;
+ qpoints->pReadBarrierMarkReg10 = art_quick_read_barrier_mark_reg10;
+ qpoints->pReadBarrierMarkReg11 = art_quick_read_barrier_mark_reg11;
+ qpoints->pReadBarrierMarkReg12 = art_quick_read_barrier_mark_reg12;
+ qpoints->pReadBarrierMarkReg13 = art_quick_read_barrier_mark_reg13;
+ qpoints->pReadBarrierMarkReg14 = art_quick_read_barrier_mark_reg14;
+ qpoints->pReadBarrierMarkReg15 = art_quick_read_barrier_mark_reg15;
+ qpoints->pReadBarrierMarkReg16 = art_quick_read_barrier_mark_reg16;
+ qpoints->pReadBarrierMarkReg17 = art_quick_read_barrier_mark_reg17;
+ qpoints->pReadBarrierMarkReg18 = art_quick_read_barrier_mark_reg18;
+ qpoints->pReadBarrierMarkReg19 = art_quick_read_barrier_mark_reg19;
+ qpoints->pReadBarrierMarkReg20 = art_quick_read_barrier_mark_reg20;
+ qpoints->pReadBarrierMarkReg21 = art_quick_read_barrier_mark_reg21;
+ qpoints->pReadBarrierMarkReg22 = art_quick_read_barrier_mark_reg22;
+ qpoints->pReadBarrierMarkReg23 = art_quick_read_barrier_mark_reg23;
+ qpoints->pReadBarrierMarkReg24 = art_quick_read_barrier_mark_reg24;
+ qpoints->pReadBarrierMarkReg25 = art_quick_read_barrier_mark_reg25;
+ qpoints->pReadBarrierMarkReg26 = art_quick_read_barrier_mark_reg26;
+ qpoints->pReadBarrierMarkReg27 = art_quick_read_barrier_mark_reg27;
+ qpoints->pReadBarrierMarkReg28 = art_quick_read_barrier_mark_reg28;
+ qpoints->pReadBarrierMarkReg29 = art_quick_read_barrier_mark_reg29;
+ qpoints->pReadBarrierMarkReg30 = nullptr; // Cannot use register 30 (LR) to pass arguments.
+ qpoints->pReadBarrierMarkReg31 = nullptr; // Cannot use register 31 (SP/XZR) to pass arguments.
qpoints->pReadBarrierSlow = artReadBarrierSlow;
qpoints->pReadBarrierForRootSlow = artReadBarrierForRootSlow;
};
diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S
index 10ee63f..e9ad1f4 100644
--- a/runtime/arch/arm64/quick_entrypoints_arm64.S
+++ b/runtime/arch/arm64/quick_entrypoints_arm64.S
@@ -2214,3 +2214,59 @@
asr x0, x0, #1
ret
END art_quick_indexof
+
+ /*
+ * Create a function `name` calling the ReadBarrier::Mark routine,
+ * getting its argument and returning its result through register
+ * `reg`, thus following a non-standard runtime calling convention:
+ * - `reg` is used to pass the (sole) argument of this function
+ * (instead of W0);
+ * - `reg` is used to return the result of this function (instead of W0);
+ * - W0 is treated like a normal (non-argument) caller-save register;
+ * - everything else is the same as in the standard runtime calling
+ * convention (e.g. same callee-save registers).
+ */
+.macro READ_BARRIER_MARK_REG name, reg
+ENTRY \name
+ str xLR, [sp, #-16]! // Save return address and add padding (16B align stack).
+ .cfi_adjust_cfa_offset 16
+ .cfi_rel_offset x30, 0
+ mov w0, \reg // Pass arg1 - obj from `reg`
+ bl artReadBarrierMark // artReadBarrierMark(obj)
+ mov \reg, w0 // Return result into `reg`
+ ldr xLR, [sp], #16 // Restore return address and remove padding.
+ .cfi_restore x30
+ .cfi_adjust_cfa_offset -16
+ ret
+END \name
+.endm
+
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg01, w1
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg02, w2
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg03, w3
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg04, w4
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg05, w5
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg06, w6
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg07, w7
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg08, w8
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg09, w9
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg10, w10
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg11, w11
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg12, w12
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg13, w13
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg14, w14
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg15, w15
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg16, w16
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg17, w17
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg18, w18
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg19, w19
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg20, w20
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg21, w21
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg22, w22
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg23, w23
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg24, w24
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg25, w25
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg26, w26
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg27, w27
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg28, w28
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg29, w29
diff --git a/runtime/arch/mips/entrypoints_direct_mips.h b/runtime/arch/mips/entrypoints_direct_mips.h
index 5b74d62..937cd1e 100644
--- a/runtime/arch/mips/entrypoints_direct_mips.h
+++ b/runtime/arch/mips/entrypoints_direct_mips.h
@@ -46,7 +46,6 @@
entrypoint == kQuickCmplDouble ||
entrypoint == kQuickCmplFloat ||
entrypoint == kQuickReadBarrierJni ||
- entrypoint == kQuickReadBarrierMark ||
entrypoint == kQuickReadBarrierSlow ||
entrypoint == kQuickReadBarrierForRootSlow;
}
diff --git a/runtime/arch/mips/entrypoints_init_mips.cc b/runtime/arch/mips/entrypoints_init_mips.cc
index 6697a8d..e3cc0e0 100644
--- a/runtime/arch/mips/entrypoints_init_mips.cc
+++ b/runtime/arch/mips/entrypoints_init_mips.cc
@@ -284,8 +284,104 @@
// Read barrier.
qpoints->pReadBarrierJni = ReadBarrierJni;
static_assert(IsDirectEntrypoint(kQuickReadBarrierJni), "Direct C stub not marked direct.");
- qpoints->pReadBarrierMark = artReadBarrierMark;
- static_assert(IsDirectEntrypoint(kQuickReadBarrierMark), "Direct C stub not marked direct.");
+ // Read barriers (and these entry points in particular) are not
+ // supported in the compiler on MIPS32.
+ qpoints->pReadBarrierMarkReg00 = nullptr;
+ static_assert(!IsDirectEntrypoint(kQuickReadBarrierMarkReg00),
+ "Non-direct C stub marked direct.");
+ qpoints->pReadBarrierMarkReg01 = nullptr;
+ static_assert(!IsDirectEntrypoint(kQuickReadBarrierMarkReg01),
+ "Non-direct C stub marked direct.");
+ qpoints->pReadBarrierMarkReg02 = nullptr;
+ static_assert(!IsDirectEntrypoint(kQuickReadBarrierMarkReg02),
+ "Non-direct C stub marked direct.");
+ qpoints->pReadBarrierMarkReg03 = nullptr;
+ static_assert(!IsDirectEntrypoint(kQuickReadBarrierMarkReg03),
+ "Non-direct C stub marked direct.");
+ qpoints->pReadBarrierMarkReg04 = nullptr;
+ static_assert(!IsDirectEntrypoint(kQuickReadBarrierMarkReg04),
+ "Non-direct C stub marked direct.");
+ qpoints->pReadBarrierMarkReg05 = nullptr;
+ static_assert(!IsDirectEntrypoint(kQuickReadBarrierMarkReg05),
+ "Non-direct C stub marked direct.");
+ qpoints->pReadBarrierMarkReg06 = nullptr;
+ static_assert(!IsDirectEntrypoint(kQuickReadBarrierMarkReg06),
+ "Non-direct C stub marked direct.");
+ qpoints->pReadBarrierMarkReg07 = nullptr;
+ static_assert(!IsDirectEntrypoint(kQuickReadBarrierMarkReg07),
+ "Non-direct C stub marked direct.");
+ qpoints->pReadBarrierMarkReg08 = nullptr;
+ static_assert(!IsDirectEntrypoint(kQuickReadBarrierMarkReg08),
+ "Non-direct C stub marked direct.");
+ qpoints->pReadBarrierMarkReg09 = nullptr;
+ static_assert(!IsDirectEntrypoint(kQuickReadBarrierMarkReg09),
+ "Non-direct C stub marked direct.");
+ qpoints->pReadBarrierMarkReg10 = nullptr;
+ static_assert(!IsDirectEntrypoint(kQuickReadBarrierMarkReg10),
+ "Non-direct C stub marked direct.");
+ qpoints->pReadBarrierMarkReg11 = nullptr;
+ static_assert(!IsDirectEntrypoint(kQuickReadBarrierMarkReg11),
+ "Non-direct C stub marked direct.");
+ qpoints->pReadBarrierMarkReg12 = nullptr;
+ static_assert(!IsDirectEntrypoint(kQuickReadBarrierMarkReg12),
+ "Non-direct C stub marked direct.");
+ qpoints->pReadBarrierMarkReg13 = nullptr;
+ static_assert(!IsDirectEntrypoint(kQuickReadBarrierMarkReg13),
+ "Non-direct C stub marked direct.");
+ qpoints->pReadBarrierMarkReg14 = nullptr;
+ static_assert(!IsDirectEntrypoint(kQuickReadBarrierMarkReg14),
+ "Non-direct C stub marked direct.");
+ qpoints->pReadBarrierMarkReg15 = nullptr;
+ static_assert(!IsDirectEntrypoint(kQuickReadBarrierMarkReg15),
+ "Non-direct C stub marked direct.");
+ qpoints->pReadBarrierMarkReg16 = nullptr;
+ static_assert(!IsDirectEntrypoint(kQuickReadBarrierMarkReg16),
+ "Non-direct C stub marked direct.");
+ qpoints->pReadBarrierMarkReg17 = nullptr;
+ static_assert(!IsDirectEntrypoint(kQuickReadBarrierMarkReg17),
+ "Non-direct C stub marked direct.");
+ qpoints->pReadBarrierMarkReg18 = nullptr;
+ static_assert(!IsDirectEntrypoint(kQuickReadBarrierMarkReg18),
+ "Non-direct C stub marked direct.");
+ qpoints->pReadBarrierMarkReg19 = nullptr;
+ static_assert(!IsDirectEntrypoint(kQuickReadBarrierMarkReg19),
+ "Non-direct C stub marked direct.");
+ qpoints->pReadBarrierMarkReg20 = nullptr;
+ static_assert(!IsDirectEntrypoint(kQuickReadBarrierMarkReg20),
+ "Non-direct C stub marked direct.");
+ qpoints->pReadBarrierMarkReg21 = nullptr;
+ static_assert(!IsDirectEntrypoint(kQuickReadBarrierMarkReg21),
+ "Non-direct C stub marked direct.");
+ qpoints->pReadBarrierMarkReg22 = nullptr;
+ static_assert(!IsDirectEntrypoint(kQuickReadBarrierMarkReg22),
+ "Non-direct C stub marked direct.");
+ qpoints->pReadBarrierMarkReg23 = nullptr;
+ static_assert(!IsDirectEntrypoint(kQuickReadBarrierMarkReg23),
+ "Non-direct C stub marked direct.");
+ qpoints->pReadBarrierMarkReg24 = nullptr;
+ static_assert(!IsDirectEntrypoint(kQuickReadBarrierMarkReg24),
+ "Non-direct C stub marked direct.");
+ qpoints->pReadBarrierMarkReg25 = nullptr;
+ static_assert(!IsDirectEntrypoint(kQuickReadBarrierMarkReg25),
+ "Non-direct C stub marked direct.");
+ qpoints->pReadBarrierMarkReg26 = nullptr;
+ static_assert(!IsDirectEntrypoint(kQuickReadBarrierMarkReg26),
+ "Non-direct C stub marked direct.");
+ qpoints->pReadBarrierMarkReg27 = nullptr;
+ static_assert(!IsDirectEntrypoint(kQuickReadBarrierMarkReg27),
+ "Non-direct C stub marked direct.");
+ qpoints->pReadBarrierMarkReg28 = nullptr;
+ static_assert(!IsDirectEntrypoint(kQuickReadBarrierMarkReg28),
+ "Non-direct C stub marked direct.");
+ qpoints->pReadBarrierMarkReg29 = nullptr;
+ static_assert(!IsDirectEntrypoint(kQuickReadBarrierMarkReg29),
+ "Non-direct C stub marked direct.");
+ qpoints->pReadBarrierMarkReg30 = nullptr;
+ static_assert(!IsDirectEntrypoint(kQuickReadBarrierMarkReg30),
+ "Non-direct C stub marked direct.");
+ qpoints->pReadBarrierMarkReg31 = nullptr;
+ static_assert(!IsDirectEntrypoint(kQuickReadBarrierMarkReg31),
+ "Non-direct C stub marked direct.");
qpoints->pReadBarrierSlow = artReadBarrierSlow;
static_assert(IsDirectEntrypoint(kQuickReadBarrierSlow), "Direct C stub not marked direct.");
qpoints->pReadBarrierForRootSlow = artReadBarrierForRootSlow;
diff --git a/runtime/arch/mips64/entrypoints_init_mips64.cc b/runtime/arch/mips64/entrypoints_init_mips64.cc
index 030c127..b19aa01 100644
--- a/runtime/arch/mips64/entrypoints_init_mips64.cc
+++ b/runtime/arch/mips64/entrypoints_init_mips64.cc
@@ -97,7 +97,40 @@
// Read barrier.
qpoints->pReadBarrierJni = ReadBarrierJni;
- qpoints->pReadBarrierMark = artReadBarrierMark;
+ // Read barriers (and these entry points in particular) are not
+ // supported in the compiler on MIPS64.
+ qpoints->pReadBarrierMarkReg00 = nullptr;
+ qpoints->pReadBarrierMarkReg01 = nullptr;
+ qpoints->pReadBarrierMarkReg02 = nullptr;
+ qpoints->pReadBarrierMarkReg03 = nullptr;
+ qpoints->pReadBarrierMarkReg04 = nullptr;
+ qpoints->pReadBarrierMarkReg05 = nullptr;
+ qpoints->pReadBarrierMarkReg06 = nullptr;
+ qpoints->pReadBarrierMarkReg07 = nullptr;
+ qpoints->pReadBarrierMarkReg08 = nullptr;
+ qpoints->pReadBarrierMarkReg09 = nullptr;
+ qpoints->pReadBarrierMarkReg10 = nullptr;
+ qpoints->pReadBarrierMarkReg11 = nullptr;
+ qpoints->pReadBarrierMarkReg12 = nullptr;
+ qpoints->pReadBarrierMarkReg13 = nullptr;
+ qpoints->pReadBarrierMarkReg14 = nullptr;
+ qpoints->pReadBarrierMarkReg15 = nullptr;
+ qpoints->pReadBarrierMarkReg16 = nullptr;
+ qpoints->pReadBarrierMarkReg17 = nullptr;
+ qpoints->pReadBarrierMarkReg18 = nullptr;
+ qpoints->pReadBarrierMarkReg19 = nullptr;
+ qpoints->pReadBarrierMarkReg20 = nullptr;
+ qpoints->pReadBarrierMarkReg21 = nullptr;
+ qpoints->pReadBarrierMarkReg22 = nullptr;
+ qpoints->pReadBarrierMarkReg23 = nullptr;
+ qpoints->pReadBarrierMarkReg24 = nullptr;
+ qpoints->pReadBarrierMarkReg25 = nullptr;
+ qpoints->pReadBarrierMarkReg26 = nullptr;
+ qpoints->pReadBarrierMarkReg27 = nullptr;
+ qpoints->pReadBarrierMarkReg28 = nullptr;
+ qpoints->pReadBarrierMarkReg29 = nullptr;
+ qpoints->pReadBarrierMarkReg30 = nullptr;
+ qpoints->pReadBarrierMarkReg31 = nullptr;
qpoints->pReadBarrierSlow = artReadBarrierSlow;
qpoints->pReadBarrierForRootSlow = artReadBarrierForRootSlow;
};
diff --git a/runtime/arch/stub_test.cc b/runtime/arch/stub_test.cc
index a7d6d6f..09af373 100644
--- a/runtime/arch/stub_test.cc
+++ b/runtime/arch/stub_test.cc
@@ -2153,6 +2153,8 @@
#endif
}
+// TODO: Exercise the ReadBarrierMarkRegX entry points.
+
TEST_F(StubTest, ReadBarrier) {
#if defined(ART_USE_READ_BARRIER) && (defined(__i386__) || defined(__arm__) || \
defined(__aarch64__) || defined(__mips__) || (defined(__x86_64__) && !defined(__APPLE__)))
diff --git a/runtime/arch/x86/entrypoints_init_x86.cc b/runtime/arch/x86/entrypoints_init_x86.cc
index 15a8571..69c939e 100644
--- a/runtime/arch/x86/entrypoints_init_x86.cc
+++ b/runtime/arch/x86/entrypoints_init_x86.cc
@@ -29,7 +29,16 @@
const mirror::Class* ref_class);
// Read barrier entrypoints.
-extern "C" mirror::Object* art_quick_read_barrier_mark(mirror::Object*);
+// art_quick_read_barrier_mark_regX uses an non-standard calling
+// convention: it expects its input in register X and returns its
+// result in that same register.
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg00(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg01(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg02(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg03(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg05(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg06(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg07(mirror::Object*);
extern "C" mirror::Object* art_quick_read_barrier_slow(mirror::Object*, mirror::Object*, uint32_t);
extern "C" mirror::Object* art_quick_read_barrier_for_root_slow(GcRoot<mirror::Object>*);
@@ -76,7 +85,39 @@
// Read barrier.
qpoints->pReadBarrierJni = ReadBarrierJni;
- qpoints->pReadBarrierMark = art_quick_read_barrier_mark;
+ qpoints->pReadBarrierMarkReg00 = art_quick_read_barrier_mark_reg00;
+ qpoints->pReadBarrierMarkReg01 = art_quick_read_barrier_mark_reg01;
+ qpoints->pReadBarrierMarkReg02 = art_quick_read_barrier_mark_reg02;
+ qpoints->pReadBarrierMarkReg03 = art_quick_read_barrier_mark_reg03;
+ qpoints->pReadBarrierMarkReg04 = nullptr; // Cannot use register 4 (ESP) to pass arguments.
+ qpoints->pReadBarrierMarkReg05 = art_quick_read_barrier_mark_reg05;
+ qpoints->pReadBarrierMarkReg06 = art_quick_read_barrier_mark_reg06;
+ qpoints->pReadBarrierMarkReg07 = art_quick_read_barrier_mark_reg07;
+ // x86 has only 8 core registers.
+ qpoints->pReadBarrierMarkReg08 = nullptr;
+ qpoints->pReadBarrierMarkReg09 = nullptr;
+ qpoints->pReadBarrierMarkReg10 = nullptr;
+ qpoints->pReadBarrierMarkReg11 = nullptr;
+ qpoints->pReadBarrierMarkReg12 = nullptr;
+ qpoints->pReadBarrierMarkReg13 = nullptr;
+ qpoints->pReadBarrierMarkReg14 = nullptr;
+ qpoints->pReadBarrierMarkReg15 = nullptr;
+ qpoints->pReadBarrierMarkReg16 = nullptr;
+ qpoints->pReadBarrierMarkReg17 = nullptr;
+ qpoints->pReadBarrierMarkReg18 = nullptr;
+ qpoints->pReadBarrierMarkReg19 = nullptr;
+ qpoints->pReadBarrierMarkReg20 = nullptr;
+ qpoints->pReadBarrierMarkReg21 = nullptr;
+ qpoints->pReadBarrierMarkReg22 = nullptr;
+ qpoints->pReadBarrierMarkReg23 = nullptr;
+ qpoints->pReadBarrierMarkReg24 = nullptr;
+ qpoints->pReadBarrierMarkReg25 = nullptr;
+ qpoints->pReadBarrierMarkReg26 = nullptr;
+ qpoints->pReadBarrierMarkReg27 = nullptr;
+ qpoints->pReadBarrierMarkReg28 = nullptr;
+ qpoints->pReadBarrierMarkReg29 = nullptr;
+ qpoints->pReadBarrierMarkReg30 = nullptr;
+ qpoints->pReadBarrierMarkReg31 = nullptr;
qpoints->pReadBarrierSlow = art_quick_read_barrier_slow;
qpoints->pReadBarrierForRootSlow = art_quick_read_barrier_for_root_slow;
};
diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S
index 6234f0f..e75fecb 100644
--- a/runtime/arch/x86/quick_entrypoints_x86.S
+++ b/runtime/arch/x86/quick_entrypoints_x86.S
@@ -1908,7 +1908,10 @@
UNREACHABLE
END_FUNCTION art_nested_signal_return
-DEFINE_FUNCTION art_quick_read_barrier_mark
+// Call the ReadBarrierMark entry point, getting input and returning
+// result through EAX (register 0), following the standard runtime
+// calling convention.
+DEFINE_FUNCTION art_quick_read_barrier_mark_reg00
subl LITERAL(8), %esp // alignment padding
CFI_ADJUST_CFA_OFFSET(8)
PUSH eax // pass arg1 - obj
@@ -1916,7 +1919,38 @@
addl LITERAL(12), %esp // pop argument and remove padding
CFI_ADJUST_CFA_OFFSET(-12)
ret
-END_FUNCTION art_quick_read_barrier_mark
+END_FUNCTION art_quick_read_barrier_mark_reg00
+
+// Create a function `name` calling the ReadBarrier::Mark routine,
+// getting its argument and returning its result through register
+// `reg`, thus following a non-standard runtime calling convention:
+// - `reg` is used to pass the (sole) argument of this function
+// (instead of EAX);
+// - `reg` is used to return the result of this function (instead of EAX);
+// - EAX is treated like a normal (non-argument) caller-save register;
+// - everything else is the same as in the standard runtime calling
+// convention (e.g. same callee-save registers).
+MACRO2(READ_BARRIER_MARK_REG, name, reg)
+ DEFINE_FUNCTION VAR(name)
+ subl LITERAL(8), %esp // alignment padding
+ CFI_ADJUST_CFA_OFFSET(8)
+ PUSH RAW_VAR(reg) // pass arg1 - obj from `reg`
+ call SYMBOL(artReadBarrierMark) // artReadBarrierMark(obj)
+ movl %eax, REG_VAR(reg) // return result into `reg`
+ addl LITERAL(12), %esp // pop argument and remove padding
+ CFI_ADJUST_CFA_OFFSET(-12)
+ ret
+ END_FUNCTION VAR(name)
+END_MACRO
+
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg01, ecx
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg02, edx
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg03, ebx
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg05, ebp
+// Note: There is no art_quick_read_barrier_mark_reg04, as register 4 (ESP)
+// cannot be used to pass arguments.
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg06, esi
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg07, edi
DEFINE_FUNCTION art_quick_read_barrier_slow
PUSH edx // pass arg3 - offset
diff --git a/runtime/arch/x86_64/entrypoints_init_x86_64.cc b/runtime/arch/x86_64/entrypoints_init_x86_64.cc
index bd6df70..2bea3db 100644
--- a/runtime/arch/x86_64/entrypoints_init_x86_64.cc
+++ b/runtime/arch/x86_64/entrypoints_init_x86_64.cc
@@ -32,7 +32,24 @@
const mirror::Class* ref_class);
// Read barrier entrypoints.
-extern "C" mirror::Object* art_quick_read_barrier_mark(mirror::Object*);
+// art_quick_read_barrier_mark_regX uses an non-standard calling
+// convention: it expects its input in register X and returns its
+// result in that same register.
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg00(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg01(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg02(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg03(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg05(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg06(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg07(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg08(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg09(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg10(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg11(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg12(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg13(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg14(mirror::Object*);
+extern "C" mirror::Object* art_quick_read_barrier_mark_reg15(mirror::Object*);
extern "C" mirror::Object* art_quick_read_barrier_slow(mirror::Object*, mirror::Object*, uint32_t);
extern "C" mirror::Object* art_quick_read_barrier_for_root_slow(GcRoot<mirror::Object>*);
@@ -82,7 +99,39 @@
// Read barrier.
qpoints->pReadBarrierJni = ReadBarrierJni;
- qpoints->pReadBarrierMark = art_quick_read_barrier_mark;
+ qpoints->pReadBarrierMarkReg00 = art_quick_read_barrier_mark_reg00;
+ qpoints->pReadBarrierMarkReg01 = art_quick_read_barrier_mark_reg01;
+ qpoints->pReadBarrierMarkReg02 = art_quick_read_barrier_mark_reg02;
+ qpoints->pReadBarrierMarkReg03 = art_quick_read_barrier_mark_reg03;
+ qpoints->pReadBarrierMarkReg04 = nullptr; // Cannot use register 4 (RSP) to pass arguments.
+ qpoints->pReadBarrierMarkReg05 = art_quick_read_barrier_mark_reg05;
+ qpoints->pReadBarrierMarkReg06 = art_quick_read_barrier_mark_reg06;
+ qpoints->pReadBarrierMarkReg07 = art_quick_read_barrier_mark_reg07;
+ qpoints->pReadBarrierMarkReg08 = art_quick_read_barrier_mark_reg08;
+ qpoints->pReadBarrierMarkReg09 = art_quick_read_barrier_mark_reg09;
+ qpoints->pReadBarrierMarkReg10 = art_quick_read_barrier_mark_reg10;
+ qpoints->pReadBarrierMarkReg11 = art_quick_read_barrier_mark_reg11;
+ qpoints->pReadBarrierMarkReg12 = art_quick_read_barrier_mark_reg12;
+ qpoints->pReadBarrierMarkReg13 = art_quick_read_barrier_mark_reg13;
+ qpoints->pReadBarrierMarkReg14 = art_quick_read_barrier_mark_reg14;
+ qpoints->pReadBarrierMarkReg15 = art_quick_read_barrier_mark_reg15;
+ // x86-64 has only 16 core registers.
+ qpoints->pReadBarrierMarkReg16 = nullptr;
+ qpoints->pReadBarrierMarkReg17 = nullptr;
+ qpoints->pReadBarrierMarkReg18 = nullptr;
+ qpoints->pReadBarrierMarkReg19 = nullptr;
+ qpoints->pReadBarrierMarkReg20 = nullptr;
+ qpoints->pReadBarrierMarkReg21 = nullptr;
+ qpoints->pReadBarrierMarkReg22 = nullptr;
+ qpoints->pReadBarrierMarkReg23 = nullptr;
+ qpoints->pReadBarrierMarkReg24 = nullptr;
+ qpoints->pReadBarrierMarkReg25 = nullptr;
+ qpoints->pReadBarrierMarkReg26 = nullptr;
+ qpoints->pReadBarrierMarkReg27 = nullptr;
+ qpoints->pReadBarrierMarkReg28 = nullptr;
+ qpoints->pReadBarrierMarkReg29 = nullptr;
+ qpoints->pReadBarrierMarkReg30 = nullptr;
+ qpoints->pReadBarrierMarkReg31 = nullptr;
qpoints->pReadBarrierSlow = art_quick_read_barrier_slow;
qpoints->pReadBarrierForRootSlow = art_quick_read_barrier_for_root_slow;
#endif // __APPLE__
diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
index e777e6c..496e6a8 100644
--- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
@@ -1815,16 +1815,89 @@
UNREACHABLE
END_FUNCTION art_nested_signal_return
-DEFINE_FUNCTION art_quick_read_barrier_mark
+// Call the ReadBarrier::Mark routine, getting argument and returning
+// result through RAX (register 0), thus following a non-standard
+// runtime calling convention:
+// - RAX is used to pass the (sole) argument of this function (instead
+// of RDI);
+// - RDI is treated like a normal (non-argument) caller-save register;
+// - everything else is the same as in the standard runtime calling
+// convention; in particular, RAX is still used to return the result
+// of this function.
+DEFINE_FUNCTION art_quick_read_barrier_mark_reg00
+ SETUP_FP_CALLEE_SAVE_FRAME
+ subq LITERAL(8), %rsp // Alignment padding.
+ CFI_ADJUST_CFA_OFFSET(8)
+ movq %rax, %rdi // Pass arg1 - obj from RAX.
+ call SYMBOL(artReadBarrierMark) // artReadBarrierMark(obj)
+ addq LITERAL(8), %rsp // Remove padding.
+ CFI_ADJUST_CFA_OFFSET(-8)
+ RESTORE_FP_CALLEE_SAVE_FRAME
+ ret
+END_FUNCTION art_quick_read_barrier_mark_reg00
+
+// Call the ReadBarrier::Mark routine, getting argument and returning
+// result through RDI (register 7), thus following a non-standard
+// runtime calling convention:
+// - RDI is used to return the result of this function (instead of RAX);
+// - RAX is treated like a normal (non-result) caller-save register;
+// - everything else is the same as in the standard runtime calling
+// convention; in particular, RDI is still used to pass the (sole)
+// argument of this function.
+DEFINE_FUNCTION art_quick_read_barrier_mark_reg07
SETUP_FP_CALLEE_SAVE_FRAME
subq LITERAL(8), %rsp // Alignment padding.
CFI_ADJUST_CFA_OFFSET(8)
call SYMBOL(artReadBarrierMark) // artReadBarrierMark(obj)
- addq LITERAL(8), %rsp
+ movq %rax, %rdi // Return result into RDI.
+ addq LITERAL(8), %rsp // Remove padding.
CFI_ADJUST_CFA_OFFSET(-8)
RESTORE_FP_CALLEE_SAVE_FRAME
ret
-END_FUNCTION art_quick_read_barrier_slow
+END_FUNCTION art_quick_read_barrier_mark_reg07
+
+// Create a function `name` calling the ReadBarrier::Mark routine,
+// getting its argument and returning its result through register
+// `reg`, thus following a non-standard runtime calling convention:
+// - `reg` is used to pass the (sole) argument of this function (instead
+// of RDI);
+// - `reg` is used to return the result of this function (instead of RAX);
+// - RDI is treated like a normal (non-argument) caller-save register;
+// - RAX is treated like a normal (non-result) caller-save register;
+// - everything else is the same as in the standard runtime calling
+// convention (e.g. same callee-save registers).
+MACRO2(READ_BARRIER_MARK_REG, name, reg)
+ DEFINE_FUNCTION VAR(name)
+ SETUP_FP_CALLEE_SAVE_FRAME
+ subq LITERAL(8), %rsp // Alignment padding.
+ CFI_ADJUST_CFA_OFFSET(8)
+ movq REG_VAR(reg), %rdi // Pass arg1 - obj from `reg`.
+ call SYMBOL(artReadBarrierMark) // artReadBarrierMark(obj)
+ movq %rax, REG_VAR(reg) // Return result into `reg`.
+ addq LITERAL(8), %rsp // Remove padding.
+ CFI_ADJUST_CFA_OFFSET(-8)
+ RESTORE_FP_CALLEE_SAVE_FRAME
+ ret
+ END_FUNCTION VAR(name)
+END_MACRO
+
+// Note: art_quick_read_barrier_mark_reg00 is implemented above.
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg01, rcx
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg02, rdx
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg03, rbx
+// Note: There is no art_quick_read_barrier_mark_reg04, as register 4 (RSP)
+// cannot be used to pass arguments.
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg05, rbp
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg06, rsi
+// Note: art_quick_read_barrier_mark_reg07 is implemented above.
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg08, r8
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg09, r9
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg10, r10
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg11, r11
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg12, r12
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg13, r13
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg14, r14
+READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg15, r15
DEFINE_FUNCTION art_quick_read_barrier_slow
SETUP_FP_CALLEE_SAVE_FRAME
diff --git a/runtime/asm_support.h b/runtime/asm_support.h
index da68923..50a786f 100644
--- a/runtime/asm_support.h
+++ b/runtime/asm_support.h
@@ -127,20 +127,20 @@
ADD_TEST_EQ(THREAD_SELF_OFFSET,
art::Thread::SelfOffset<__SIZEOF_POINTER__>().Int32Value())
+// Offset of field Thread::tlsPtr_.thread_local_objects.
+#define THREAD_LOCAL_OBJECTS_OFFSET (THREAD_CARD_TABLE_OFFSET + 199 * __SIZEOF_POINTER__)
+ADD_TEST_EQ(THREAD_LOCAL_OBJECTS_OFFSET,
+ art::Thread::ThreadLocalObjectsOffset<__SIZEOF_POINTER__>().Int32Value())
// Offset of field Thread::tlsPtr_.thread_local_pos.
-#define THREAD_LOCAL_POS_OFFSET (THREAD_CARD_TABLE_OFFSET + 168 * __SIZEOF_POINTER__)
+#define THREAD_LOCAL_POS_OFFSET (THREAD_LOCAL_OBJECTS_OFFSET + __SIZEOF_SIZE_T__)
ADD_TEST_EQ(THREAD_LOCAL_POS_OFFSET,
art::Thread::ThreadLocalPosOffset<__SIZEOF_POINTER__>().Int32Value())
// Offset of field Thread::tlsPtr_.thread_local_end.
#define THREAD_LOCAL_END_OFFSET (THREAD_LOCAL_POS_OFFSET + __SIZEOF_POINTER__)
ADD_TEST_EQ(THREAD_LOCAL_END_OFFSET,
art::Thread::ThreadLocalEndOffset<__SIZEOF_POINTER__>().Int32Value())
-// Offset of field Thread::tlsPtr_.thread_local_objects.
-#define THREAD_LOCAL_OBJECTS_OFFSET (THREAD_LOCAL_END_OFFSET + __SIZEOF_POINTER__)
-ADD_TEST_EQ(THREAD_LOCAL_OBJECTS_OFFSET,
- art::Thread::ThreadLocalObjectsOffset<__SIZEOF_POINTER__>().Int32Value())
// Offset of field Thread::tlsPtr_.mterp_current_ibase.
-#define THREAD_CURRENT_IBASE_OFFSET (THREAD_LOCAL_OBJECTS_OFFSET + __SIZEOF_SIZE_T__)
+#define THREAD_CURRENT_IBASE_OFFSET (THREAD_LOCAL_END_OFFSET + __SIZEOF_POINTER__)
ADD_TEST_EQ(THREAD_CURRENT_IBASE_OFFSET,
art::Thread::MterpCurrentIBaseOffset<__SIZEOF_POINTER__>().Int32Value())
// Offset of field Thread::tlsPtr_.mterp_default_ibase.
diff --git a/runtime/entrypoints/quick/quick_entrypoints_list.h b/runtime/entrypoints/quick/quick_entrypoints_list.h
index 30b639e..d6b7d9e 100644
--- a/runtime/entrypoints/quick/quick_entrypoints_list.h
+++ b/runtime/entrypoints/quick/quick_entrypoints_list.h
@@ -164,7 +164,38 @@
V(NewStringFromStringBuilder, void) \
\
V(ReadBarrierJni, void, mirror::CompressedReference<mirror::Object>*, Thread*) \
- V(ReadBarrierMark, mirror::Object*, mirror::Object*) \
+ V(ReadBarrierMarkReg00, mirror::Object*, mirror::Object*) \
+ V(ReadBarrierMarkReg01, mirror::Object*, mirror::Object*) \
+ V(ReadBarrierMarkReg02, mirror::Object*, mirror::Object*) \
+ V(ReadBarrierMarkReg03, mirror::Object*, mirror::Object*) \
+ V(ReadBarrierMarkReg04, mirror::Object*, mirror::Object*) \
+ V(ReadBarrierMarkReg05, mirror::Object*, mirror::Object*) \
+ V(ReadBarrierMarkReg06, mirror::Object*, mirror::Object*) \
+ V(ReadBarrierMarkReg07, mirror::Object*, mirror::Object*) \
+ V(ReadBarrierMarkReg08, mirror::Object*, mirror::Object*) \
+ V(ReadBarrierMarkReg09, mirror::Object*, mirror::Object*) \
+ V(ReadBarrierMarkReg10, mirror::Object*, mirror::Object*) \
+ V(ReadBarrierMarkReg11, mirror::Object*, mirror::Object*) \
+ V(ReadBarrierMarkReg12, mirror::Object*, mirror::Object*) \
+ V(ReadBarrierMarkReg13, mirror::Object*, mirror::Object*) \
+ V(ReadBarrierMarkReg14, mirror::Object*, mirror::Object*) \
+ V(ReadBarrierMarkReg15, mirror::Object*, mirror::Object*) \
+ V(ReadBarrierMarkReg16, mirror::Object*, mirror::Object*) \
+ V(ReadBarrierMarkReg17, mirror::Object*, mirror::Object*) \
+ V(ReadBarrierMarkReg18, mirror::Object*, mirror::Object*) \
+ V(ReadBarrierMarkReg19, mirror::Object*, mirror::Object*) \
+ V(ReadBarrierMarkReg20, mirror::Object*, mirror::Object*) \
+ V(ReadBarrierMarkReg21, mirror::Object*, mirror::Object*) \
+ V(ReadBarrierMarkReg22, mirror::Object*, mirror::Object*) \
+ V(ReadBarrierMarkReg23, mirror::Object*, mirror::Object*) \
+ V(ReadBarrierMarkReg24, mirror::Object*, mirror::Object*) \
+ V(ReadBarrierMarkReg25, mirror::Object*, mirror::Object*) \
+ V(ReadBarrierMarkReg26, mirror::Object*, mirror::Object*) \
+ V(ReadBarrierMarkReg27, mirror::Object*, mirror::Object*) \
+ V(ReadBarrierMarkReg28, mirror::Object*, mirror::Object*) \
+ V(ReadBarrierMarkReg29, mirror::Object*, mirror::Object*) \
+ V(ReadBarrierMarkReg30, mirror::Object*, mirror::Object*) \
+ V(ReadBarrierMarkReg31, mirror::Object*, mirror::Object*) \
V(ReadBarrierSlow, mirror::Object*, mirror::Object*, mirror::Object*, uint32_t) \
V(ReadBarrierForRootSlow, mirror::Object*, GcRoot<mirror::Object>*)
diff --git a/runtime/entrypoints_order_test.cc b/runtime/entrypoints_order_test.cc
index 7a624b2..ffe4109 100644
--- a/runtime/entrypoints_order_test.cc
+++ b/runtime/entrypoints_order_test.cc
@@ -121,10 +121,10 @@
// Skip across the entrypoints structures.
- EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_start, thread_local_pos, sizeof(void*));
+ EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_start, thread_local_objects, sizeof(void*));
+ EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_objects, thread_local_pos, sizeof(size_t));
EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_pos, thread_local_end, sizeof(void*));
- EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_end, thread_local_objects, sizeof(void*));
- EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_objects, mterp_current_ibase, sizeof(void*));
+ EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_end, mterp_current_ibase, sizeof(void*));
EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, mterp_current_ibase, mterp_default_ibase, sizeof(void*));
EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, mterp_default_ibase, mterp_alt_ibase, sizeof(void*));
EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, mterp_alt_ibase, rosalloc_runs, sizeof(void*));
@@ -324,8 +324,70 @@
sizeof(void*));
EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pNewStringFromStringBuilder, pReadBarrierJni,
sizeof(void*));
- EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pReadBarrierJni, pReadBarrierMark, sizeof(void*));
- EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pReadBarrierMark, pReadBarrierSlow, sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pReadBarrierJni, pReadBarrierMarkReg00, sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pReadBarrierMarkReg00, pReadBarrierMarkReg01,
+ sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pReadBarrierMarkReg01, pReadBarrierMarkReg02,
+ sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pReadBarrierMarkReg02, pReadBarrierMarkReg03,
+ sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pReadBarrierMarkReg03, pReadBarrierMarkReg04,
+ sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pReadBarrierMarkReg04, pReadBarrierMarkReg05,
+ sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pReadBarrierMarkReg05, pReadBarrierMarkReg06,
+ sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pReadBarrierMarkReg06, pReadBarrierMarkReg07,
+ sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pReadBarrierMarkReg07, pReadBarrierMarkReg08,
+ sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pReadBarrierMarkReg08, pReadBarrierMarkReg09,
+ sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pReadBarrierMarkReg09, pReadBarrierMarkReg10,
+ sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pReadBarrierMarkReg10, pReadBarrierMarkReg11,
+ sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pReadBarrierMarkReg11, pReadBarrierMarkReg12,
+ sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pReadBarrierMarkReg12, pReadBarrierMarkReg13,
+ sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pReadBarrierMarkReg13, pReadBarrierMarkReg14,
+ sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pReadBarrierMarkReg14, pReadBarrierMarkReg15,
+ sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pReadBarrierMarkReg15, pReadBarrierMarkReg16,
+ sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pReadBarrierMarkReg16, pReadBarrierMarkReg17,
+ sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pReadBarrierMarkReg17, pReadBarrierMarkReg18,
+ sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pReadBarrierMarkReg18, pReadBarrierMarkReg19,
+ sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pReadBarrierMarkReg19, pReadBarrierMarkReg20,
+ sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pReadBarrierMarkReg20, pReadBarrierMarkReg21,
+ sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pReadBarrierMarkReg21, pReadBarrierMarkReg22,
+ sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pReadBarrierMarkReg22, pReadBarrierMarkReg23,
+ sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pReadBarrierMarkReg23, pReadBarrierMarkReg24,
+ sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pReadBarrierMarkReg24, pReadBarrierMarkReg25,
+ sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pReadBarrierMarkReg25, pReadBarrierMarkReg26,
+ sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pReadBarrierMarkReg26, pReadBarrierMarkReg27,
+ sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pReadBarrierMarkReg27, pReadBarrierMarkReg28,
+ sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pReadBarrierMarkReg28, pReadBarrierMarkReg29,
+ sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pReadBarrierMarkReg29, pReadBarrierMarkReg30,
+ sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pReadBarrierMarkReg30, pReadBarrierMarkReg31,
+ sizeof(void*));
+ EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pReadBarrierMarkReg31, pReadBarrierSlow, sizeof(void*));
EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pReadBarrierSlow, pReadBarrierForRootSlow,
sizeof(void*));
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index 46be5e6..d4ad0ea 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -378,13 +378,13 @@
// TODO: Verify the dex location is well formed, and throw an IOException if
// not?
- OatFileAssistant oat_file_assistant(filename, target_instruction_set, profile_changed, false);
+ OatFileAssistant oat_file_assistant(filename, target_instruction_set, false);
// Always treat elements of the bootclasspath as up-to-date.
if (oat_file_assistant.IsInBootClassPath()) {
return OatFileAssistant::kNoDexOptNeeded;
}
- return oat_file_assistant.GetDexOptNeeded(filter);
+ return oat_file_assistant.GetDexOptNeeded(filter, profile_changed);
}
static jstring DexFile_getDexFileStatus(JNIEnv* env,
@@ -411,7 +411,6 @@
}
OatFileAssistant oat_file_assistant(filename.c_str(), target_instruction_set,
- false /* profile_changed */,
false /* load_executable */);
std::ostringstream status;
@@ -486,7 +485,7 @@
return JNI_FALSE;
}
- OatFileAssistant oat_file_assistant(filename, kRuntimeISA, false, false);
+ OatFileAssistant oat_file_assistant(filename, kRuntimeISA, false);
return oat_file_assistant.IsUpToDate() ? JNI_FALSE : JNI_TRUE;
}
diff --git a/runtime/native/dalvik_system_ZygoteHooks.cc b/runtime/native/dalvik_system_ZygoteHooks.cc
index 1aa789f..198a52e 100644
--- a/runtime/native/dalvik_system_ZygoteHooks.cc
+++ b/runtime/native/dalvik_system_ZygoteHooks.cc
@@ -46,6 +46,16 @@
if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) == -1) {
PLOG(ERROR) << "prctl(PR_SET_DUMPABLE) failed for pid " << getpid();
}
+
+ // Even if Yama is on a non-privileged native debugger should
+ // be able to attach to the debuggable app.
+ if (prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0) == -1) {
+ // if Yama is off prctl(PR_SET_PTRACER) returns EINVAL - don't log in this
+ // case since it's expected behaviour.
+ if (errno != EINVAL) {
+ PLOG(ERROR) << "prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY) failed for pid " << getpid();
+ }
+ }
#endif
// We don't want core dumps, though, so set the core dump size to 0.
rlimit rl;
@@ -168,12 +178,17 @@
// Only restart if it was streaming mode.
// TODO: Expose buffer size, so we can also do file mode.
if (output_mode == Trace::TraceOutputMode::kStreaming) {
- const char* proc_name_cutils = get_process_name();
+ static constexpr size_t kMaxProcessNameLength = 100;
+ char name_buf[kMaxProcessNameLength] = {};
+ int rc = pthread_getname_np(pthread_self(), name_buf, kMaxProcessNameLength);
std::string proc_name;
- if (proc_name_cutils != nullptr) {
- proc_name = proc_name_cutils;
+
+ if (rc == 0) {
+ // On success use the pthread name.
+ proc_name = name_buf;
}
- if (proc_name_cutils == nullptr || proc_name == "zygote" || proc_name == "zygote64") {
+
+ if (proc_name.empty() || proc_name == "zygote" || proc_name == "zygote64") {
// Either no process name, or the name hasn't been changed, yet. Just use pid.
pid_t pid = getpid();
proc_name = StringPrintf("%u", static_cast<uint32_t>(pid));
diff --git a/runtime/oat.h b/runtime/oat.h
index 6243660..e506e3c 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -32,7 +32,7 @@
class PACKED(4) OatHeader {
public:
static constexpr uint8_t kOatMagic[] = { 'o', 'a', 't', '\n' };
- static constexpr uint8_t kOatVersion[] = { '0', '8', '2', '\0' };
+ static constexpr uint8_t kOatVersion[] = { '0', '8', '3', '\0' };
static constexpr const char* kImageLocationKey = "image-location";
static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline";
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index 218c490..aae9d97 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -64,17 +64,15 @@
OatFileAssistant::OatFileAssistant(const char* dex_location,
const InstructionSet isa,
- bool profile_changed,
bool load_executable)
- : OatFileAssistant(dex_location, nullptr, isa, profile_changed, load_executable)
+ : OatFileAssistant(dex_location, nullptr, isa, load_executable)
{ }
OatFileAssistant::OatFileAssistant(const char* dex_location,
const char* oat_location,
const InstructionSet isa,
- bool profile_changed,
bool load_executable)
- : isa_(isa), profile_changed_(profile_changed), load_executable_(load_executable) {
+ : isa_(isa), load_executable_(load_executable) {
CHECK(dex_location != nullptr) << "OatFileAssistant: null dex location";
dex_location_.assign(dex_location);
@@ -89,7 +87,6 @@
if (oat_location != nullptr) {
cached_oat_file_name_ = std::string(oat_location);
cached_oat_file_name_attempted_ = true;
- cached_oat_file_name_found_ = true;
}
}
@@ -134,29 +131,43 @@
return true;
}
-bool OatFileAssistant::OatFileCompilerFilterIsOkay(CompilerFilter::Filter target) {
+static bool GivenOatFileCompilerFilterIsOkay(const OatFile& oat_file,
+ CompilerFilter::Filter target,
+ bool profile_changed) {
+ CompilerFilter::Filter current = oat_file.GetCompilerFilter();
+
+ if (profile_changed && CompilerFilter::DependsOnProfile(current)) {
+ VLOG(oat) << "Compiler filter not okay because Profile changed";
+ return false;
+ }
+ return CompilerFilter::IsAsGoodAs(current, target);
+}
+
+bool OatFileAssistant::OatFileCompilerFilterIsOkay(CompilerFilter::Filter target,
+ bool profile_changed) {
const OatFile* oat_file = GetOatFile();
if (oat_file != nullptr) {
- CompilerFilter::Filter current = oat_file->GetCompilerFilter();
- return CompilerFilter::IsAsGoodAs(current, target);
+ return GivenOatFileCompilerFilterIsOkay(*oat_file, target, profile_changed);
}
return false;
}
-bool OatFileAssistant::OdexFileCompilerFilterIsOkay(CompilerFilter::Filter target) {
+bool OatFileAssistant::OdexFileCompilerFilterIsOkay(CompilerFilter::Filter target,
+ bool profile_changed) {
const OatFile* odex_file = GetOdexFile();
if (odex_file != nullptr) {
- CompilerFilter::Filter current = odex_file->GetCompilerFilter();
- return CompilerFilter::IsAsGoodAs(current, target);
+ return GivenOatFileCompilerFilterIsOkay(*odex_file, target, profile_changed);
}
return false;
}
-OatFileAssistant::DexOptNeeded OatFileAssistant::GetDexOptNeeded(CompilerFilter::Filter target) {
+OatFileAssistant::DexOptNeeded
+OatFileAssistant::GetDexOptNeeded(CompilerFilter::Filter target,
+ bool profile_changed) {
bool compilation_desired = CompilerFilter::IsBytecodeCompilationEnabled(target);
// See if the oat file is in good shape as is.
- bool oat_okay = OatFileCompilerFilterIsOkay(target);
+ bool oat_okay = OatFileCompilerFilterIsOkay(target, profile_changed);
if (oat_okay) {
if (compilation_desired) {
if (OatFileIsUpToDate()) {
@@ -170,7 +181,7 @@
}
// See if the odex file is in good shape as is.
- bool odex_okay = OdexFileCompilerFilterIsOkay(target);
+ bool odex_okay = OdexFileCompilerFilterIsOkay(target, profile_changed);
if (odex_okay) {
if (compilation_desired) {
if (OdexFileIsUpToDate()) {
@@ -225,13 +236,13 @@
}
OatFileAssistant::ResultOfAttemptToUpdate
-OatFileAssistant::MakeUpToDate(std::string* error_msg) {
+OatFileAssistant::MakeUpToDate(bool profile_changed, std::string* error_msg) {
CompilerFilter::Filter target;
if (!GetRuntimeCompilerFilterOption(&target, error_msg)) {
return kUpdateNotAttempted;
}
- switch (GetDexOptNeeded(target)) {
+ switch (GetDexOptNeeded(target, profile_changed)) {
case kNoDexOptNeeded: return kUpdateSucceeded;
case kDex2OatNeeded: return GenerateOatFile(error_msg);
case kPatchOatNeeded: return RelocateOatFile(OdexFileName(), error_msg);
@@ -345,15 +356,13 @@
cached_odex_file_name_attempted_ = true;
std::string error_msg;
- cached_odex_file_name_found_ = DexFilenameToOdexFilename(
- dex_location_, isa_, &cached_odex_file_name_, &error_msg);
- if (!cached_odex_file_name_found_) {
+ if (!DexFilenameToOdexFilename(dex_location_, isa_, &cached_odex_file_name_, &error_msg)) {
// If we can't figure out the odex file, we treat it as if the odex
// file was inaccessible.
LOG(WARNING) << "Failed to determine odex file name: " << error_msg;
}
}
- return cached_odex_file_name_found_ ? &cached_odex_file_name_ : nullptr;
+ return cached_odex_file_name_.empty() ? nullptr : &cached_odex_file_name_;
}
bool OatFileAssistant::OdexFileExists() {
@@ -361,26 +370,20 @@
}
OatFileAssistant::OatStatus OatFileAssistant::OdexFileStatus() {
- if (OdexFileIsOutOfDate()) {
- return kOatOutOfDate;
+ if (!odex_file_status_attempted_) {
+ odex_file_status_attempted_ = true;
+ const OatFile* odex_file = GetOdexFile();
+ if (odex_file == nullptr) {
+ cached_odex_file_status_ = kOatOutOfDate;
+ } else {
+ cached_odex_file_status_ = GivenOatFileStatus(*odex_file);
+ }
}
- if (OdexFileIsUpToDate()) {
- return kOatUpToDate;
- }
- return kOatNeedsRelocation;
+ return cached_odex_file_status_;
}
bool OatFileAssistant::OdexFileIsOutOfDate() {
- if (!odex_file_is_out_of_date_attempted_) {
- odex_file_is_out_of_date_attempted_ = true;
- const OatFile* odex_file = GetOdexFile();
- if (odex_file == nullptr) {
- cached_odex_file_is_out_of_date_ = true;
- } else {
- cached_odex_file_is_out_of_date_ = GivenOatFileIsOutOfDate(*odex_file);
- }
- }
- return cached_odex_file_is_out_of_date_;
+ return OdexFileStatus() == kOatOutOfDate;
}
bool OatFileAssistant::OdexFileNeedsRelocation() {
@@ -388,16 +391,7 @@
}
bool OatFileAssistant::OdexFileIsUpToDate() {
- if (!odex_file_is_up_to_date_attempted_) {
- odex_file_is_up_to_date_attempted_ = true;
- const OatFile* odex_file = GetOdexFile();
- if (odex_file == nullptr) {
- cached_odex_file_is_up_to_date_ = false;
- } else {
- cached_odex_file_is_up_to_date_ = GivenOatFileIsUpToDate(*odex_file);
- }
- }
- return cached_odex_file_is_up_to_date_;
+ return OdexFileStatus() == kOatUpToDate;
}
CompilerFilter::Filter OatFileAssistant::OdexFileCompilerFilter() {
@@ -406,7 +400,8 @@
return odex_file->GetCompilerFilter();
}
-std::string OatFileAssistant::ArtFileName(const OatFile* oat_file) const {
+
+static std::string ArtFileName(const OatFile* oat_file) {
const std::string oat_file_location = oat_file->GetLocation();
// Replace extension with .art
const size_t last_ext = oat_file_location.find_last_of('.');
@@ -428,16 +423,15 @@
std::string cache_dir = StringPrintf("%s%s",
DalvikCacheDirectory().c_str(), GetInstructionSetString(isa_));
std::string error_msg;
- cached_oat_file_name_found_ = GetDalvikCacheFilename(dex_location_.c_str(),
- cache_dir.c_str(), &cached_oat_file_name_, &error_msg);
- if (!cached_oat_file_name_found_) {
+ if (!GetDalvikCacheFilename(dex_location_.c_str(),
+ cache_dir.c_str(), &cached_oat_file_name_, &error_msg)) {
// If we can't determine the oat file name, we treat the oat file as
// inaccessible.
LOG(WARNING) << "Failed to determine oat file name for dex location "
<< dex_location_ << ": " << error_msg;
}
}
- return cached_oat_file_name_found_ ? &cached_oat_file_name_ : nullptr;
+ return cached_oat_file_name_.empty() ? nullptr : &cached_oat_file_name_;
}
bool OatFileAssistant::OatFileExists() {
@@ -445,26 +439,20 @@
}
OatFileAssistant::OatStatus OatFileAssistant::OatFileStatus() {
- if (OatFileIsOutOfDate()) {
- return kOatOutOfDate;
+ if (!oat_file_status_attempted_) {
+ oat_file_status_attempted_ = true;
+ const OatFile* oat_file = GetOatFile();
+ if (oat_file == nullptr) {
+ cached_oat_file_status_ = kOatOutOfDate;
+ } else {
+ cached_oat_file_status_ = GivenOatFileStatus(*oat_file);
+ }
}
- if (OatFileIsUpToDate()) {
- return kOatUpToDate;
- }
- return kOatNeedsRelocation;
+ return cached_oat_file_status_;
}
bool OatFileAssistant::OatFileIsOutOfDate() {
- if (!oat_file_is_out_of_date_attempted_) {
- oat_file_is_out_of_date_attempted_ = true;
- const OatFile* oat_file = GetOatFile();
- if (oat_file == nullptr) {
- cached_oat_file_is_out_of_date_ = true;
- } else {
- cached_oat_file_is_out_of_date_ = GivenOatFileIsOutOfDate(*oat_file);
- }
- }
- return cached_oat_file_is_out_of_date_;
+ return OatFileStatus() == kOatOutOfDate;
}
bool OatFileAssistant::OatFileNeedsRelocation() {
@@ -472,16 +460,7 @@
}
bool OatFileAssistant::OatFileIsUpToDate() {
- if (!oat_file_is_up_to_date_attempted_) {
- oat_file_is_up_to_date_attempted_ = true;
- const OatFile* oat_file = GetOatFile();
- if (oat_file == nullptr) {
- cached_oat_file_is_up_to_date_ = false;
- } else {
- cached_oat_file_is_up_to_date_ = GivenOatFileIsUpToDate(*oat_file);
- }
- }
- return cached_oat_file_is_up_to_date_;
+ return OatFileStatus() == kOatUpToDate;
}
CompilerFilter::Filter OatFileAssistant::OatFileCompilerFilter() {
@@ -492,19 +471,6 @@
}
OatFileAssistant::OatStatus OatFileAssistant::GivenOatFileStatus(const OatFile& file) {
- // TODO: This could cause GivenOatFileIsOutOfDate to be called twice, which
- // is more work than we need to do. If performance becomes a concern, and
- // this method is actually called, this should be fixed.
- if (GivenOatFileIsOutOfDate(file)) {
- return kOatOutOfDate;
- }
- if (GivenOatFileIsUpToDate(file)) {
- return kOatUpToDate;
- }
- return kOatNeedsRelocation;
-}
-
-bool OatFileAssistant::GivenOatFileIsOutOfDate(const OatFile& file) {
// Verify the dex checksum.
// Note: GetOatDexFile will return null if the dex checksum doesn't match
// what we provide, which verifies the primary dex checksum for us.
@@ -512,7 +478,7 @@
const OatFile::OatDexFile* oat_dex_file = file.GetOatDexFile(
dex_location_.c_str(), dex_checksum_pointer, false);
if (oat_dex_file == nullptr) {
- return true;
+ return kOatOutOfDate;
}
// Verify the dex checksums for any secondary multidex files
@@ -537,7 +503,7 @@
<< secondary_dex_location
<< ". Expected: " << expected_secondary_checksum
<< ", Actual: " << actual_secondary_checksum;
- return true;
+ return kOatOutOfDate;
}
} else {
// If we can't get the checksum for the secondary location, we assume
@@ -557,7 +523,7 @@
VLOG(oat) << "No image for oat image checksum to match against.";
if (HasOriginalDexFiles()) {
- return true;
+ return kOatOutOfDate;
}
// If there is no original dex file to fall back to, grudgingly accept
@@ -571,45 +537,18 @@
} else if (file.GetOatHeader().GetImageFileLocationOatChecksum()
!= GetCombinedImageChecksum()) {
VLOG(oat) << "Oat image checksum does not match image checksum.";
- return true;
+ return kOatOutOfDate;
}
} else {
VLOG(oat) << "Image checksum test skipped for compiler filter " << current_compiler_filter;
}
- // Verify the profile hasn't changed recently.
- // TODO: Move this check to OatFileCompilerFilterIsOkay? Nothing bad should
- // happen if we use an oat file compiled with an out-of-date profile.
- if (CompilerFilter::DependsOnProfile(current_compiler_filter)) {
- if (profile_changed_) {
- VLOG(oat) << "The profile has changed recently.";
- return true;
- }
- } else {
- VLOG(oat) << "Profile check skipped for compiler filter " << current_compiler_filter;
- }
-
- // Everything looks good; the dex file is not out of date.
- return false;
-}
-
-bool OatFileAssistant::GivenOatFileNeedsRelocation(const OatFile& file) {
- return GivenOatFileStatus(file) == kOatNeedsRelocation;
-}
-
-bool OatFileAssistant::GivenOatFileIsUpToDate(const OatFile& file) {
- if (GivenOatFileIsOutOfDate(file)) {
- return false;
- }
-
- CompilerFilter::Filter current_compiler_filter = file.GetCompilerFilter();
-
if (CompilerFilter::IsBytecodeCompilationEnabled(current_compiler_filter)) {
if (!file.IsPic()) {
const ImageInfo* image_info = GetImageInfo();
if (image_info == nullptr) {
VLOG(oat) << "No image to check oat relocation against.";
- return false;
+ return kOatNeedsRelocation;
}
// Verify the oat_data_begin recorded for the image in the oat file matches
@@ -621,7 +560,7 @@
": Oat file image oat_data_begin (" << oat_data_begin << ")"
<< " does not match actual image oat_data_begin ("
<< image_info->oat_data_begin << ")";
- return false;
+ return kOatNeedsRelocation;
}
// Verify the oat_patch_delta recorded for the image in the oat file matches
@@ -632,7 +571,7 @@
": Oat file image patch delta (" << oat_patch_delta << ")"
<< " does not match actual image patch delta ("
<< image_info->patch_delta << ")";
- return false;
+ return kOatNeedsRelocation;
}
} else {
// Oat files compiled in PIC mode do not require relocation.
@@ -641,7 +580,7 @@
} else {
VLOG(oat) << "Oat relocation test skipped for compiler filter " << current_compiler_filter;
}
- return true;
+ return kOatUpToDate;
}
OatFileAssistant::ResultOfAttemptToUpdate
@@ -946,8 +885,7 @@
void OatFileAssistant::ClearOdexFileCache() {
odex_file_load_attempted_ = false;
cached_odex_file_.reset();
- odex_file_is_out_of_date_attempted_ = false;
- odex_file_is_up_to_date_attempted_ = false;
+ odex_file_status_attempted_ = false;
}
const OatFile* OatFileAssistant::GetOatFile() {
@@ -987,8 +925,7 @@
void OatFileAssistant::ClearOatFileCache() {
oat_file_load_attempted_ = false;
cached_oat_file_.reset();
- oat_file_is_out_of_date_attempted_ = false;
- oat_file_is_up_to_date_attempted_ = false;
+ oat_file_status_attempted_ = false;
}
const OatFileAssistant::ImageInfo* OatFileAssistant::GetImageInfo() {
diff --git a/runtime/oat_file_assistant.h b/runtime/oat_file_assistant.h
index d55e373..e4aba3f 100644
--- a/runtime/oat_file_assistant.h
+++ b/runtime/oat_file_assistant.h
@@ -101,14 +101,10 @@
// device. For example, on an arm device, use arm or arm64. An oat file can
// be loaded executable only if the ISA matches the current runtime.
//
- // profile_changed should be true if the profile has recently changed
- // for this dex location.
- //
// load_executable should be true if the caller intends to try and load
// executable code for this dex location.
OatFileAssistant(const char* dex_location,
const InstructionSet isa,
- bool profile_changed,
bool load_executable);
// Constructs an OatFileAssistant, providing an explicit target oat_location
@@ -116,7 +112,6 @@
OatFileAssistant(const char* dex_location,
const char* oat_location,
const InstructionSet isa,
- bool profile_changed,
bool load_executable);
~OatFileAssistant();
@@ -145,8 +140,10 @@
// Return what action needs to be taken to produce up-to-date code for this
// dex location that is at least as good as an oat file generated with the
- // given compiler filter.
- DexOptNeeded GetDexOptNeeded(CompilerFilter::Filter target_compiler_filter);
+ // given compiler filter. profile_changed should be true to indicate the
+ // profile has recently changed for this dex location.
+ DexOptNeeded GetDexOptNeeded(CompilerFilter::Filter target_compiler_filter,
+ bool profile_changed = false);
// Returns true if there is up-to-date code for this dex location,
// irrespective of the compiler filter of the up-to-date code.
@@ -164,11 +161,15 @@
// Attempts to generate or relocate the oat file as needed to make it up to
// date based on the current runtime and compiler options.
+ // profile_changed should be true to indicate the profile has recently
+ // changed for this dex location.
+ //
+ // Returns the result of attempting to update the code.
//
// If the result is not kUpdateSucceeded, the value of error_msg will be set
// to a string describing why there was a failure or the update was not
// attempted. error_msg must not be null.
- ResultOfAttemptToUpdate MakeUpToDate(std::string* error_msg);
+ ResultOfAttemptToUpdate MakeUpToDate(bool profile_changed, std::string* error_msg);
// Returns an oat file that can be used for loading dex files.
// Returns null if no suitable oat file was found.
@@ -179,7 +180,7 @@
std::unique_ptr<OatFile> GetBestOatFile();
// Open and returns an image space associated with the oat file.
- gc::space::ImageSpace* OpenImageSpace(const OatFile* oat_file);
+ static gc::space::ImageSpace* OpenImageSpace(const OatFile* oat_file);
// Loads the dex files in the given oat file for the given dex location.
// The oat file should be up to date for the given dex location.
@@ -238,15 +239,9 @@
// |OatFileExists() == true|.
CompilerFilter::Filter OatFileCompilerFilter();
- // Return image file name. Does not cache since it relies on the oat file.
- std::string ArtFileName(const OatFile* oat_file) const;
-
- // These methods return the status for a given opened oat file with respect
- // to the dex location.
+ // Return the status for a given opened oat file with respect to the dex
+ // location.
OatStatus GivenOatFileStatus(const OatFile& file);
- bool GivenOatFileIsOutOfDate(const OatFile& file);
- bool GivenOatFileNeedsRelocation(const OatFile& file);
- bool GivenOatFileIsUpToDate(const OatFile& file);
// Generates the oat file by relocation from the named input file.
// This does not check the current status before attempting to relocate the
@@ -282,7 +277,8 @@
// Constructs the odex file name for the given dex location.
// Returns true on success, in which case odex_filename is set to the odex
// file name.
- // Returns false on error, in which case error_msg describes the error.
+ // Returns false on error, in which case error_msg describes the error and
+ // odex_filename is not changed.
// Neither odex_filename nor error_msg may be null.
static bool DexFilenameToOdexFilename(const std::string& location,
InstructionSet isa, std::string* odex_filename, std::string* error_msg);
@@ -324,8 +320,9 @@
const OatFile* GetOdexFile();
// Returns true if the compiler filter used to generate the odex file is at
- // least as good as the given target filter.
- bool OdexFileCompilerFilterIsOkay(CompilerFilter::Filter target);
+ // least as good as the given target filter. profile_changed should be true
+ // to indicate the profile has recently changed for this dex location.
+ bool OdexFileCompilerFilterIsOkay(CompilerFilter::Filter target, bool profile_changed);
// Returns true if the odex file is opened executable.
bool OdexFileIsExecutable();
@@ -343,8 +340,9 @@
const OatFile* GetOatFile();
// Returns true if the compiler filter used to generate the oat file is at
- // least as good as the given target filter.
- bool OatFileCompilerFilterIsOkay(CompilerFilter::Filter target);
+ // least as good as the given target filter. profile_changed should be true
+ // to indicate the profile has recently changed for this dex location.
+ bool OatFileCompilerFilterIsOkay(CompilerFilter::Filter target, bool profile_changed);
// Returns true if the oat file is opened executable.
bool OatFileIsExecutable();
@@ -375,9 +373,6 @@
// the 32 or 64 bit variant for the current device.
const InstructionSet isa_ = kNone;
- // Whether the profile has recently changed.
- bool profile_changed_ = false;
-
// Whether we will attempt to load oat files executable.
bool load_executable_ = false;
@@ -390,8 +385,9 @@
// Cached value of the odex file name.
// This should be accessed only by the OdexFileName() method.
+ // The sentinel value "" is used if the odex file name could not be
+ // determined.
bool cached_odex_file_name_attempted_ = false;
- bool cached_odex_file_name_found_;
std::string cached_odex_file_name_;
// Cached value of the loaded odex file.
@@ -400,18 +396,15 @@
bool odex_file_load_attempted_ = false;
std::unique_ptr<OatFile> cached_odex_file_;
- // Cached results for OdexFileIsOutOfDate
- bool odex_file_is_out_of_date_attempted_ = false;
- bool cached_odex_file_is_out_of_date_;
-
- // Cached results for OdexFileIsUpToDate
- bool odex_file_is_up_to_date_attempted_ = false;
- bool cached_odex_file_is_up_to_date_;
+ // Cached results for OdexFileStatus
+ bool odex_file_status_attempted_ = false;
+ OatStatus cached_odex_file_status_;
// Cached value of the oat file name.
// This should be accessed only by the OatFileName() method.
+ // The sentinel value "" is used if the oat file name could not be
+ // determined.
bool cached_oat_file_name_attempted_ = false;
- bool cached_oat_file_name_found_;
std::string cached_oat_file_name_;
// Cached value of the loaded oat file.
@@ -420,13 +413,9 @@
bool oat_file_load_attempted_ = false;
std::unique_ptr<OatFile> cached_oat_file_;
- // Cached results for OatFileIsOutOfDate
- bool oat_file_is_out_of_date_attempted_ = false;
- bool cached_oat_file_is_out_of_date_;
-
- // Cached results for OatFileIsUpToDate
- bool oat_file_is_up_to_date_attempted_ = false;
- bool cached_oat_file_is_up_to_date_;
+ // Cached results for OatFileStatus
+ bool oat_file_status_attempted_ = false;
+ OatStatus cached_oat_file_status_;
// Cached value of the image info.
// Use the GetImageInfo method rather than accessing these directly.
diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc
index a1d3ed9..6bccea6 100644
--- a/runtime/oat_file_assistant_test.cc
+++ b/runtime/oat_file_assistant_test.cc
@@ -213,7 +213,7 @@
// generation of oat files.
static void GenerateOatForTest(const char* dex_location, CompilerFilter::Filter filter) {
// Use an oat file assistant to find the proper oat location.
- OatFileAssistant ofa(dex_location, kRuntimeISA, false, false);
+ OatFileAssistant ofa(dex_location, kRuntimeISA, false);
const std::string* oat_location = ofa.OatFileName();
ASSERT_TRUE(oat_location != nullptr);
@@ -245,7 +245,7 @@
std::string dex_location = GetScratchDir() + "/DexNoOat.jar";
Copy(GetDexSrc1(), dex_location);
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kVerifyAtRuntime));
@@ -275,7 +275,7 @@
TEST_F(OatFileAssistantTest, NoDexNoOat) {
std::string dex_location = GetScratchDir() + "/NoDexNoOat.jar";
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, true);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
@@ -283,7 +283,7 @@
// Trying to make the oat file up to date should not fail or crash.
std::string error_msg;
- EXPECT_EQ(OatFileAssistant::kUpdateSucceeded, oat_file_assistant.MakeUpToDate(&error_msg));
+ EXPECT_EQ(OatFileAssistant::kUpdateSucceeded, oat_file_assistant.MakeUpToDate(false, &error_msg));
// Trying to get the best oat file should fail, but not crash.
std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
@@ -297,7 +297,7 @@
Copy(GetDexSrc1(), dex_location);
GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
@@ -321,18 +321,23 @@
}
// Case: We have a DEX file and speed-profile OAT file for it.
-// Expect: The status is kNoDexOptNeeded if the profile hasn't changed.
+// Expect: The status is kNoDexOptNeeded if the profile hasn't changed, but
+// kDex2Oat if the profile has changed.
TEST_F(OatFileAssistantTest, ProfileOatUpToDate) {
std::string dex_location = GetScratchDir() + "/ProfileOatUpToDate.jar";
Copy(GetDexSrc1(), dex_location);
GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeedProfile);
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeedProfile));
+ oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeedProfile, false));
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kInterpretOnly));
+ oat_file_assistant.GetDexOptNeeded(CompilerFilter::kInterpretOnly, false));
+ EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
+ oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeedProfile, true));
+ EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
+ oat_file_assistant.GetDexOptNeeded(CompilerFilter::kInterpretOnly, true));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
EXPECT_FALSE(oat_file_assistant.OdexFileExists());
@@ -346,32 +351,6 @@
EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
}
-// Case: We have a DEX file and speed-profile OAT file for it.
-// Expect: The status is kNoDex2OatNeeded if the profile has changed.
-TEST_F(OatFileAssistantTest, ProfileOatOutOfDate) {
- std::string dex_location = GetScratchDir() + "/ProfileOatOutOfDate.jar";
- Copy(GetDexSrc1(), dex_location);
- GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeedProfile);
-
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true, false);
-
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeedProfile));
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kInterpretOnly));
-
- EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_FALSE(oat_file_assistant.OdexFileExists());
- EXPECT_TRUE(oat_file_assistant.OdexFileIsOutOfDate());
- EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
- EXPECT_TRUE(oat_file_assistant.OatFileExists());
- EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
- EXPECT_FALSE(oat_file_assistant.OatFileNeedsRelocation());
- EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
- EXPECT_EQ(OatFileAssistant::kOatOutOfDate, oat_file_assistant.OatFileStatus());
- EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
-}
-
// Case: We have a MultiDEX file and up-to-date OAT file for it.
// Expect: The status is kNoDexOptNeeded and we load all dex files.
TEST_F(OatFileAssistantTest, MultiDexOatUpToDate) {
@@ -379,9 +358,9 @@
Copy(GetMultiDexSrc1(), dex_location);
GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, true);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
+ oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed, false));
EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
// Verify we can load both dex files.
@@ -406,9 +385,9 @@
// is out of date.
Copy(GetMultiDexSrc2(), dex_location);
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, true);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
+ oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed, false));
EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
}
@@ -435,7 +414,7 @@
// Verify we can load both dex files.
OatFileAssistant oat_file_assistant(dex_location.c_str(),
oat_location.c_str(),
- kRuntimeISA, false, true);
+ kRuntimeISA, true);
std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
ASSERT_TRUE(oat_file.get() != nullptr);
EXPECT_TRUE(oat_file->IsExecutable());
@@ -455,7 +434,7 @@
GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
Copy(GetDexSrc2(), dex_location);
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kVerifyAtRuntime));
EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
@@ -482,7 +461,7 @@
GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
// Verify the status.
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kVerifyAtRuntime));
@@ -518,7 +497,7 @@
Copy(GetStrippedDexSrc1(), dex_location);
// Verify the status.
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, true);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
EXPECT_EQ(OatFileAssistant::kPatchOatNeeded,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
@@ -536,7 +515,7 @@
std::string error_msg;
Runtime::Current()->AddCompilerOption("--compiler-filter=speed");
ASSERT_EQ(OatFileAssistant::kUpdateSucceeded,
- oat_file_assistant.MakeUpToDate(&error_msg)) << error_msg;
+ oat_file_assistant.MakeUpToDate(false, &error_msg)) << error_msg;
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
@@ -577,7 +556,7 @@
Copy(GetStrippedDexSrc1(), dex_location);
// Verify the status.
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, true);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kVerifyAtRuntime));
@@ -600,7 +579,7 @@
std::string error_msg;
Runtime::Current()->AddCompilerOption("--compiler-filter=speed");
ASSERT_EQ(OatFileAssistant::kUpdateSucceeded,
- oat_file_assistant.MakeUpToDate(&error_msg)) << error_msg;
+ oat_file_assistant.MakeUpToDate(false, &error_msg)) << error_msg;
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
@@ -635,7 +614,7 @@
Copy(GetStrippedDexSrc1(), dex_location);
// Verify the status.
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, true);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
@@ -658,7 +637,7 @@
std::string error_msg;
Runtime::Current()->AddCompilerOption("--compiler-filter=speed");
EXPECT_EQ(OatFileAssistant::kUpdateSucceeded,
- oat_file_assistant.MakeUpToDate(&error_msg)) << error_msg;
+ oat_file_assistant.MakeUpToDate(false, &error_msg)) << error_msg;
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
@@ -686,7 +665,7 @@
GenerateOdexForTest(dex_location, oat_location, CompilerFilter::kSpeed);
OatFileAssistant oat_file_assistant(dex_location.c_str(),
- oat_location.c_str(), kRuntimeISA, false, true);
+ oat_location.c_str(), kRuntimeISA, true);
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kInterpretOnly));
@@ -710,7 +689,7 @@
std::string error_msg;
Runtime::Current()->AddCompilerOption("--compiler-filter=speed");
ASSERT_EQ(OatFileAssistant::kUpdateSucceeded,
- oat_file_assistant.MakeUpToDate(&error_msg)) << error_msg;
+ oat_file_assistant.MakeUpToDate(false, &error_msg)) << error_msg;
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
@@ -746,7 +725,7 @@
GenerateNoPatchOdexForTest(dex_location, oat_location, CompilerFilter::kSpeed);
OatFileAssistant oat_file_assistant(dex_location.c_str(),
- oat_location.c_str(), kRuntimeISA, false, true);
+ oat_location.c_str(), kRuntimeISA, true);
EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
@@ -755,7 +734,7 @@
std::string error_msg;
Runtime::Current()->AddCompilerOption("--compiler-filter=speed");
ASSERT_EQ(OatFileAssistant::kUpdateSucceeded,
- oat_file_assistant.MakeUpToDate(&error_msg)) << error_msg;
+ oat_file_assistant.MakeUpToDate(false, &error_msg)) << error_msg;
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
@@ -785,7 +764,7 @@
// Verify things don't go bad.
OatFileAssistant oat_file_assistant(dex_location.c_str(),
- oat_location.c_str(), kRuntimeISA, false, true);
+ oat_location.c_str(), kRuntimeISA, true);
EXPECT_EQ(OatFileAssistant::kPatchOatNeeded,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
@@ -820,7 +799,7 @@
GeneratePicOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
// Verify the status.
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
@@ -848,7 +827,7 @@
GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kVerifyAtRuntime);
// Verify the status.
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kVerifyAtRuntime));
@@ -874,7 +853,7 @@
GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
// Load the oat using an oat file assistant.
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, true);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
ASSERT_TRUE(oat_file.get() != nullptr);
@@ -893,7 +872,7 @@
GenerateOatForTest(dex_location.c_str(), CompilerFilter::kInterpretOnly);
// Load the oat using an oat file assistant.
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, true);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
ASSERT_TRUE(oat_file.get() != nullptr);
@@ -912,7 +891,7 @@
GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
// Load the oat using an oat file assistant.
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
ASSERT_TRUE(oat_file.get() != nullptr);
@@ -932,11 +911,11 @@
Copy(GetDexSrc1(), dex_location);
OatFileAssistant oat_file_assistant(
- dex_location.c_str(), oat_location.c_str(), kRuntimeISA, false, true);
+ dex_location.c_str(), oat_location.c_str(), kRuntimeISA, true);
std::string error_msg;
Runtime::Current()->AddCompilerOption("--compiler-filter=speed");
ASSERT_EQ(OatFileAssistant::kUpdateSucceeded,
- oat_file_assistant.MakeUpToDate(&error_msg)) << error_msg;
+ oat_file_assistant.MakeUpToDate(false, &error_msg)) << error_msg;
std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
ASSERT_TRUE(oat_file.get() != nullptr);
@@ -948,7 +927,7 @@
EXPECT_TRUE(OS::FileExists(oat_location.c_str()));
// Verify it didn't create an oat in the default location.
- OatFileAssistant ofm(dex_location.c_str(), kRuntimeISA, false, false);
+ OatFileAssistant ofm(dex_location.c_str(), kRuntimeISA, false);
EXPECT_FALSE(ofm.OatFileExists());
}
@@ -964,11 +943,11 @@
Copy(GetDexSrc1(), dex_location);
OatFileAssistant oat_file_assistant(
- dex_location.c_str(), oat_location.c_str(), kRuntimeISA, false, true);
+ dex_location.c_str(), oat_location.c_str(), kRuntimeISA, true);
std::string error_msg;
Runtime::Current()->AddCompilerOption("--compiler-filter=speed");
ASSERT_EQ(OatFileAssistant::kUpdateNotAttempted,
- oat_file_assistant.MakeUpToDate(&error_msg));
+ oat_file_assistant.MakeUpToDate(false, &error_msg));
std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
ASSERT_TRUE(oat_file.get() == nullptr);
@@ -981,7 +960,7 @@
std::string oat_location = GetScratchDir() + "/GenNoDex.oat";
OatFileAssistant oat_file_assistant(
- dex_location.c_str(), oat_location.c_str(), kRuntimeISA, false, true);
+ dex_location.c_str(), oat_location.c_str(), kRuntimeISA, true);
std::string error_msg;
Runtime::Current()->AddCompilerOption("--compiler-filter=speed");
EXPECT_EQ(OatFileAssistant::kUpdateNotAttempted,
@@ -1031,7 +1010,7 @@
Copy(GetDexSrc1(), abs_dex_location);
std::string dex_location = MakePathRelative(abs_dex_location);
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, true);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
@@ -1049,7 +1028,7 @@
TEST_F(OatFileAssistantTest, ShortDexLocation) {
std::string dex_location = "/xx";
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, true);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
@@ -1066,7 +1045,7 @@
std::string error_msg;
Runtime::Current()->AddCompilerOption("--compiler-filter=speed");
EXPECT_EQ(OatFileAssistant::kUpdateSucceeded,
- oat_file_assistant.MakeUpToDate(&error_msg));
+ oat_file_assistant.MakeUpToDate(false, &error_msg));
EXPECT_TRUE(error_msg.empty());
}
@@ -1076,7 +1055,7 @@
std::string dex_location = GetScratchDir() + "/LongDexExtension.jarx";
Copy(GetDexSrc1(), dex_location);
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
@@ -1173,7 +1152,7 @@
GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
// Load the oat using an executable oat file assistant.
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, true);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
ASSERT_TRUE(oat_file.get() != nullptr);
@@ -1195,7 +1174,7 @@
GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
// Load the oat using an executable oat file assistant.
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, true);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
ASSERT_TRUE(oat_file.get() != nullptr);
@@ -1209,12 +1188,12 @@
std::string dex_location = GetScratchDir() + "/RuntimeCompilerFilterOptionUsed.jar";
Copy(GetDexSrc1(), dex_location);
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
std::string error_msg;
Runtime::Current()->AddCompilerOption("--compiler-filter=interpret-only");
EXPECT_EQ(OatFileAssistant::kUpdateSucceeded,
- oat_file_assistant.MakeUpToDate(&error_msg)) << error_msg;
+ oat_file_assistant.MakeUpToDate(false, &error_msg)) << error_msg;
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kInterpretOnly));
EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
@@ -1222,7 +1201,7 @@
Runtime::Current()->AddCompilerOption("--compiler-filter=speed");
EXPECT_EQ(OatFileAssistant::kUpdateSucceeded,
- oat_file_assistant.MakeUpToDate(&error_msg)) << error_msg;
+ oat_file_assistant.MakeUpToDate(false, &error_msg)) << error_msg;
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kInterpretOnly));
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
@@ -1230,7 +1209,7 @@
Runtime::Current()->AddCompilerOption("--compiler-filter=bogus");
EXPECT_EQ(OatFileAssistant::kUpdateNotAttempted,
- oat_file_assistant.MakeUpToDate(&error_msg));
+ oat_file_assistant.MakeUpToDate(false, &error_msg));
}
TEST(OatFileAssistantUtilsTest, DexFilenameToOdexFilename) {
diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc
index b7e6040..7680517 100644
--- a/runtime/oat_file_manager.cc
+++ b/runtime/oat_file_manager.cc
@@ -558,7 +558,6 @@
OatFileAssistant oat_file_assistant(dex_location,
oat_location,
kRuntimeISA,
- /*profile_changed*/false,
!runtime->IsAotCompiler());
// Lock the target oat location to avoid races generating and loading the
@@ -576,7 +575,7 @@
// Update the oat file on disk if we can, based on the --compiler-filter
// option derived from the current runtime options.
// This may fail, but that's okay. Best effort is all that matters here.
- switch (oat_file_assistant.MakeUpToDate(/*out*/ &error_msg)) {
+ switch (oat_file_assistant.MakeUpToDate(/*profile_changed*/false, /*out*/ &error_msg)) {
case OatFileAssistant::kUpdateFailed:
LOG(WARNING) << error_msg;
break;
diff --git a/runtime/thread.cc b/runtime/thread.cc
index b9ee442..50f76da 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -2574,7 +2574,38 @@
QUICK_ENTRY_POINT_INFO(pNewStringFromStringBuffer)
QUICK_ENTRY_POINT_INFO(pNewStringFromStringBuilder)
QUICK_ENTRY_POINT_INFO(pReadBarrierJni)
- QUICK_ENTRY_POINT_INFO(pReadBarrierMark)
+ QUICK_ENTRY_POINT_INFO(pReadBarrierMarkReg00)
+ QUICK_ENTRY_POINT_INFO(pReadBarrierMarkReg01)
+ QUICK_ENTRY_POINT_INFO(pReadBarrierMarkReg02)
+ QUICK_ENTRY_POINT_INFO(pReadBarrierMarkReg03)
+ QUICK_ENTRY_POINT_INFO(pReadBarrierMarkReg04)
+ QUICK_ENTRY_POINT_INFO(pReadBarrierMarkReg05)
+ QUICK_ENTRY_POINT_INFO(pReadBarrierMarkReg06)
+ QUICK_ENTRY_POINT_INFO(pReadBarrierMarkReg07)
+ QUICK_ENTRY_POINT_INFO(pReadBarrierMarkReg08)
+ QUICK_ENTRY_POINT_INFO(pReadBarrierMarkReg09)
+ QUICK_ENTRY_POINT_INFO(pReadBarrierMarkReg10)
+ QUICK_ENTRY_POINT_INFO(pReadBarrierMarkReg11)
+ QUICK_ENTRY_POINT_INFO(pReadBarrierMarkReg12)
+ QUICK_ENTRY_POINT_INFO(pReadBarrierMarkReg13)
+ QUICK_ENTRY_POINT_INFO(pReadBarrierMarkReg14)
+ QUICK_ENTRY_POINT_INFO(pReadBarrierMarkReg15)
+ QUICK_ENTRY_POINT_INFO(pReadBarrierMarkReg16)
+ QUICK_ENTRY_POINT_INFO(pReadBarrierMarkReg17)
+ QUICK_ENTRY_POINT_INFO(pReadBarrierMarkReg18)
+ QUICK_ENTRY_POINT_INFO(pReadBarrierMarkReg19)
+ QUICK_ENTRY_POINT_INFO(pReadBarrierMarkReg20)
+ QUICK_ENTRY_POINT_INFO(pReadBarrierMarkReg21)
+ QUICK_ENTRY_POINT_INFO(pReadBarrierMarkReg22)
+ QUICK_ENTRY_POINT_INFO(pReadBarrierMarkReg23)
+ QUICK_ENTRY_POINT_INFO(pReadBarrierMarkReg24)
+ QUICK_ENTRY_POINT_INFO(pReadBarrierMarkReg25)
+ QUICK_ENTRY_POINT_INFO(pReadBarrierMarkReg26)
+ QUICK_ENTRY_POINT_INFO(pReadBarrierMarkReg27)
+ QUICK_ENTRY_POINT_INFO(pReadBarrierMarkReg28)
+ QUICK_ENTRY_POINT_INFO(pReadBarrierMarkReg29)
+ QUICK_ENTRY_POINT_INFO(pReadBarrierMarkReg30)
+ QUICK_ENTRY_POINT_INFO(pReadBarrierMarkReg31)
QUICK_ENTRY_POINT_INFO(pReadBarrierSlow)
QUICK_ENTRY_POINT_INFO(pReadBarrierForRootSlow)
#undef QUICK_ENTRY_POINT_INFO
diff --git a/runtime/thread.h b/runtime/thread.h
index ab24625..a3a4005 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -1352,7 +1352,7 @@
stacked_shadow_frame_record(nullptr), deoptimization_context_stack(nullptr),
frame_id_to_shadow_frame(nullptr), name(nullptr), pthread_self(0),
last_no_thread_suspension_cause(nullptr), thread_local_start(nullptr),
- thread_local_pos(nullptr), thread_local_end(nullptr), thread_local_objects(0),
+ thread_local_objects(0), thread_local_pos(nullptr), thread_local_end(nullptr),
mterp_current_ibase(nullptr), mterp_default_ibase(nullptr), mterp_alt_ibase(nullptr),
thread_local_alloc_stack_top(nullptr), thread_local_alloc_stack_end(nullptr),
nested_signal_state(nullptr), flip_function(nullptr), method_verifier(nullptr),
@@ -1468,11 +1468,11 @@
// Thread-local allocation pointer.
uint8_t* thread_local_start;
+ size_t thread_local_objects;
// thread_local_pos and thread_local_end must be consecutive for ldrd and are 8 byte aligned for
// potentially better performance.
uint8_t* thread_local_pos;
uint8_t* thread_local_end;
- size_t thread_local_objects;
// Mterp jump table bases.
void* mterp_current_ibase;
diff --git a/test/458-checker-instruction-simplification/src/Main.java b/test/458-checker-instruction-simplification/src/Main.java
index c717eaa..359d521 100644
--- a/test/458-checker-instruction-simplification/src/Main.java
+++ b/test/458-checker-instruction-simplification/src/Main.java
@@ -1971,8 +1971,165 @@
return (value >> temp) + temp;
}
-public static void main(String[] args) {
+ /// CHECK-START: int Main.$noinline$intAddSubSimplifyArg1(int, int) instruction_simplifier (before)
+ /// CHECK: <<X:i\d+>> ParameterValue
+ /// CHECK: <<Y:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Sum:i\d+>> Add [<<X>>,<<Y>>]
+ /// CHECK-DAG: <<Res:i\d+>> Sub [<<Sum>>,<<X>>]
+ /// CHECK-DAG: Return [<<Res>>]
+
+ /// CHECK-START: int Main.$noinline$intAddSubSimplifyArg1(int, int) instruction_simplifier (after)
+ /// CHECK: <<X:i\d+>> ParameterValue
+ /// CHECK: <<Y:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Sum:i\d+>> Add [<<X>>,<<Y>>]
+ /// CHECK-DAG: Return [<<Y>>]
+
+ public static int $noinline$intAddSubSimplifyArg1(int x, int y) {
+ if (doThrow) { throw new Error(); }
+ int sum = x + y;
+ return sum - x;
+ }
+
+ /// CHECK-START: int Main.$noinline$intAddSubSimplifyArg2(int, int) instruction_simplifier (before)
+ /// CHECK: <<X:i\d+>> ParameterValue
+ /// CHECK: <<Y:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Sum:i\d+>> Add [<<X>>,<<Y>>]
+ /// CHECK-DAG: <<Res:i\d+>> Sub [<<Sum>>,<<Y>>]
+ /// CHECK-DAG: Return [<<Res>>]
+
+ /// CHECK-START: int Main.$noinline$intAddSubSimplifyArg2(int, int) instruction_simplifier (after)
+ /// CHECK: <<X:i\d+>> ParameterValue
+ /// CHECK: <<Y:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Sum:i\d+>> Add [<<X>>,<<Y>>]
+ /// CHECK-DAG: Return [<<X>>]
+
+ public static int $noinline$intAddSubSimplifyArg2(int x, int y) {
+ if (doThrow) { throw new Error(); }
+ int sum = x + y;
+ return sum - y;
+ }
+
+ /// CHECK-START: int Main.$noinline$intSubAddSimplifyLeft(int, int) instruction_simplifier (before)
+ /// CHECK: <<X:i\d+>> ParameterValue
+ /// CHECK: <<Y:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Sub:i\d+>> Sub [<<X>>,<<Y>>]
+ /// CHECK-DAG: <<Res:i\d+>> Add [<<Sub>>,<<Y>>]
+ /// CHECK-DAG: Return [<<Res>>]
+
+ /// CHECK-START: int Main.$noinline$intSubAddSimplifyLeft(int, int) instruction_simplifier (after)
+ /// CHECK: <<X:i\d+>> ParameterValue
+ /// CHECK: <<Y:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Sub:i\d+>> Sub [<<X>>,<<Y>>]
+ /// CHECK-DAG: Return [<<X>>]
+
+ public static int $noinline$intSubAddSimplifyLeft(int x, int y) {
+ if (doThrow) { throw new Error(); }
+ int sub = x - y;
+ return sub + y;
+ }
+
+ /// CHECK-START: int Main.$noinline$intSubAddSimplifyRight(int, int) instruction_simplifier (before)
+ /// CHECK: <<X:i\d+>> ParameterValue
+ /// CHECK: <<Y:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Sub:i\d+>> Sub [<<X>>,<<Y>>]
+ /// CHECK-DAG: <<Res:i\d+>> Add [<<Y>>,<<Sub>>]
+ /// CHECK-DAG: Return [<<Res>>]
+
+ /// CHECK-START: int Main.$noinline$intSubAddSimplifyRight(int, int) instruction_simplifier (after)
+ /// CHECK: <<X:i\d+>> ParameterValue
+ /// CHECK: <<Y:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Sub:i\d+>> Sub [<<X>>,<<Y>>]
+ /// CHECK-DAG: Return [<<X>>]
+
+ public static int $noinline$intSubAddSimplifyRight(int x, int y) {
+ if (doThrow) { throw new Error(); }
+ int sub = x - y;
+ return y + sub;
+ }
+
+ /// CHECK-START: float Main.$noinline$floatAddSubSimplifyArg1(float, float) instruction_simplifier (before)
+ /// CHECK: <<X:f\d+>> ParameterValue
+ /// CHECK: <<Y:f\d+>> ParameterValue
+ /// CHECK-DAG: <<Sum:f\d+>> Add [<<X>>,<<Y>>]
+ /// CHECK-DAG: <<Res:f\d+>> Sub [<<Sum>>,<<X>>]
+ /// CHECK-DAG: Return [<<Res>>]
+
+ /// CHECK-START: float Main.$noinline$floatAddSubSimplifyArg1(float, float) instruction_simplifier (after)
+ /// CHECK: <<X:f\d+>> ParameterValue
+ /// CHECK: <<Y:f\d+>> ParameterValue
+ /// CHECK-DAG: <<Sum:f\d+>> Add [<<X>>,<<Y>>]
+ /// CHECK-DAG: <<Res:f\d+>> Sub [<<Sum>>,<<X>>]
+ /// CHECK-DAG: Return [<<Res>>]
+
+ public static float $noinline$floatAddSubSimplifyArg1(float x, float y) {
+ if (doThrow) { throw new Error(); }
+ float sum = x + y;
+ return sum - x;
+ }
+
+ /// CHECK-START: float Main.$noinline$floatAddSubSimplifyArg2(float, float) instruction_simplifier (before)
+ /// CHECK: <<X:f\d+>> ParameterValue
+ /// CHECK: <<Y:f\d+>> ParameterValue
+ /// CHECK-DAG: <<Sum:f\d+>> Add [<<X>>,<<Y>>]
+ /// CHECK-DAG: <<Res:f\d+>> Sub [<<Sum>>,<<Y>>]
+ /// CHECK-DAG: Return [<<Res>>]
+
+ /// CHECK-START: float Main.$noinline$floatAddSubSimplifyArg2(float, float) instruction_simplifier (after)
+ /// CHECK: <<X:f\d+>> ParameterValue
+ /// CHECK: <<Y:f\d+>> ParameterValue
+ /// CHECK-DAG: <<Sum:f\d+>> Add [<<X>>,<<Y>>]
+ /// CHECK-DAG: <<Res:f\d+>> Sub [<<Sum>>,<<Y>>]
+ /// CHECK-DAG: Return [<<Res>>]
+
+ public static float $noinline$floatAddSubSimplifyArg2(float x, float y) {
+ if (doThrow) { throw new Error(); }
+ float sum = x + y;
+ return sum - y;
+ }
+
+ /// CHECK-START: float Main.$noinline$floatSubAddSimplifyLeft(float, float) instruction_simplifier (before)
+ /// CHECK: <<X:f\d+>> ParameterValue
+ /// CHECK: <<Y:f\d+>> ParameterValue
+ /// CHECK-DAG: <<Sub:f\d+>> Sub [<<X>>,<<Y>>]
+ /// CHECK-DAG: <<Res:f\d+>> Add [<<Sub>>,<<Y>>]
+ /// CHECK-DAG: Return [<<Res>>]
+
+ /// CHECK-START: float Main.$noinline$floatSubAddSimplifyLeft(float, float) instruction_simplifier (after)
+ /// CHECK: <<X:f\d+>> ParameterValue
+ /// CHECK: <<Y:f\d+>> ParameterValue
+ /// CHECK-DAG: <<Sub:f\d+>> Sub [<<X>>,<<Y>>]
+ /// CHECK-DAG: <<Res:f\d+>> Add [<<Sub>>,<<Y>>]
+ /// CHECK-DAG: Return [<<Res>>]
+
+ public static float $noinline$floatSubAddSimplifyLeft(float x, float y) {
+ if (doThrow) { throw new Error(); }
+ float sub = x - y;
+ return sub + y;
+ }
+
+ /// CHECK-START: float Main.$noinline$floatSubAddSimplifyRight(float, float) instruction_simplifier (before)
+ /// CHECK: <<X:f\d+>> ParameterValue
+ /// CHECK: <<Y:f\d+>> ParameterValue
+ /// CHECK-DAG: <<Sub:f\d+>> Sub [<<X>>,<<Y>>]
+ /// CHECK-DAG: <<Res:f\d+>> Add [<<Y>>,<<Sub>>]
+ /// CHECK-DAG: Return [<<Res>>]
+
+ /// CHECK-START: float Main.$noinline$floatSubAddSimplifyRight(float, float) instruction_simplifier (after)
+ /// CHECK: <<X:f\d+>> ParameterValue
+ /// CHECK: <<Y:f\d+>> ParameterValue
+ /// CHECK-DAG: <<Sub:f\d+>> Sub [<<X>>,<<Y>>]
+ /// CHECK-DAG: <<Res:f\d+>> Add [<<Y>>,<<Sub>>]
+ /// CHECK-DAG: Return [<<Res>>]
+
+ public static float $noinline$floatSubAddSimplifyRight(float x, float y) {
+ if (doThrow) { throw new Error(); }
+ float sub = x - y;
+ return y + sub;
+ }
+
+ public static void main(String[] args) {
int arg = 123456;
+ float floatArg = 123456.125f;
assertLongEquals(arg, $noinline$Add0(arg));
assertIntEquals(5, $noinline$AddAddSubAddConst(1));
@@ -2143,6 +2300,15 @@
assertLongEquals(0xaf37bc048d159e24L, $noinline$longSmallerShiftMasking(0xabcdef0123456789L, 2 + 256));
assertIntEquals(0xfffd5e7c, $noinline$otherUseOfUnnecessaryShiftMasking(0xabcdef01, 13));
assertIntEquals(0xfffd5e7c, $noinline$otherUseOfUnnecessaryShiftMasking(0xabcdef01, 13 + 512));
+
+ assertIntEquals(654321, $noinline$intAddSubSimplifyArg1(arg, 654321));
+ assertIntEquals(arg, $noinline$intAddSubSimplifyArg2(arg, 654321));
+ assertIntEquals(arg, $noinline$intSubAddSimplifyLeft(arg, 654321));
+ assertIntEquals(arg, $noinline$intSubAddSimplifyRight(arg, 654321));
+ assertFloatEquals(654321.125f, $noinline$floatAddSubSimplifyArg1(floatArg, 654321.125f));
+ assertFloatEquals(floatArg, $noinline$floatAddSubSimplifyArg2(floatArg, 654321.125f));
+ assertFloatEquals(floatArg, $noinline$floatSubAddSimplifyLeft(floatArg, 654321.125f));
+ assertFloatEquals(floatArg, $noinline$floatSubAddSimplifyRight(floatArg, 654321.125f));
}
private static boolean $inline$true() { return true; }
diff --git a/test/566-polymorphic-inlining/polymorphic_inline.cc b/test/566-polymorphic-inlining/polymorphic_inline.cc
index c0d93dd..9f4c6c9 100644
--- a/test/566-polymorphic-inlining/polymorphic_inline.cc
+++ b/test/566-polymorphic-inlining/polymorphic_inline.cc
@@ -81,6 +81,7 @@
do_checks(cls, "testInvokeVirtual");
do_checks(cls, "testInvokeInterface");
+ do_checks(cls, "testInvokeInterface2");
do_checks(cls, "$noinline$testInlineToSameTarget");
}
diff --git a/test/566-polymorphic-inlining/src/Main.java b/test/566-polymorphic-inlining/src/Main.java
index d39e6ed..53852a4 100644
--- a/test/566-polymorphic-inlining/src/Main.java
+++ b/test/566-polymorphic-inlining/src/Main.java
@@ -16,6 +16,8 @@
interface Itf {
public Class sameInvokeInterface();
+ public Class sameInvokeInterface2();
+ public Class sameInvokeInterface3();
}
public class Main implements Itf {
@@ -50,6 +52,8 @@
testInvokeVirtual(mains[1]);
testInvokeInterface(itfs[0]);
testInvokeInterface(itfs[1]);
+ testInvokeInterface2(itfs[0]);
+ testInvokeInterface2(itfs[1]);
$noinline$testInlineToSameTarget(mains[0]);
$noinline$testInlineToSameTarget(mains[1]);
}
@@ -64,9 +68,13 @@
assertEquals(Itf.class, testInvokeInterface(itfs[0]));
assertEquals(Itf.class, testInvokeInterface(itfs[1]));
+ assertEquals(Itf.class, testInvokeInterface2(itfs[0]));
+ assertEquals(Itf.class, testInvokeInterface2(itfs[1]));
+
// This will trigger a deoptimization of the compiled code.
assertEquals(OtherSubclass.class, testInvokeVirtual(mains[2]));
assertEquals(OtherSubclass.class, testInvokeInterface(itfs[2]));
+ assertEquals(null, testInvokeInterface2(itfs[2]));
// Run this once to make sure we execute the JITted code.
$noinline$testInlineToSameTarget(mains[0]);
@@ -83,10 +91,28 @@
return Itf.class;
}
+ public Class sameInvokeInterface2() {
+ field.getClass(); // null check to ensure we get an inlined frame in the CodeInfo.
+ return Itf.class;
+ }
+
+ public Class sameInvokeInterface3() {
+ field.getClass(); // null check to ensure we get an inlined frame in the CodeInfo.
+ return Itf.class;
+ }
+
public static Class testInvokeInterface(Itf i) {
return i.sameInvokeInterface();
}
+ public static Class testInvokeInterface2(Itf i) {
+ // Make three interface calls that will do a ClassTableGet to ensure bogus code
+ // generation of ClassTableGet will crash.
+ i.sameInvokeInterface();
+ i.sameInvokeInterface2();
+ return i.sameInvokeInterface3();
+ }
+
public static Class testInvokeVirtual(Main m) {
return m.sameInvokeVirtual();
}
@@ -120,4 +146,11 @@
public Class sameInvokeInterface() {
return OtherSubclass.class;
}
+
+ public Class sameInvokeInterface2() {
+ return null;
+ }
+ public Class sameInvokeInterface3() {
+ return null;
+ }
}
diff --git a/test/609-checker-x86-bounds-check/expected.txt b/test/609-checker-x86-bounds-check/expected.txt
new file mode 100644
index 0000000..b0aad4d
--- /dev/null
+++ b/test/609-checker-x86-bounds-check/expected.txt
@@ -0,0 +1 @@
+passed
diff --git a/test/609-checker-x86-bounds-check/info.txt b/test/609-checker-x86-bounds-check/info.txt
new file mode 100644
index 0000000..c0f26d0
--- /dev/null
+++ b/test/609-checker-x86-bounds-check/info.txt
@@ -0,0 +1 @@
+Checker test that we combine ArrayLength and BoundsCheck on x86/x86_64.
diff --git a/test/609-checker-x86-bounds-check/src/Main.java b/test/609-checker-x86-bounds-check/src/Main.java
new file mode 100644
index 0000000..bfc2be8
--- /dev/null
+++ b/test/609-checker-x86-bounds-check/src/Main.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+public class Main {
+
+ public static void main(String args[]) {
+ int[] array = new int[51];
+ testArrayLengthBoundsCheckX86(array, 10);
+
+ System.out.println("passed");
+ }
+
+ /// CHECK-START-X86: void Main.testArrayLengthBoundsCheckX86(int[], int) x86_memory_operand_generation (before)
+ /// CHECK-DAG: <<Array:l\d+>> ParameterValue
+ /// CHECK-DAG: <<Index:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Value:i\d+>> IntConstant 9
+ /// CHECK-DAG: <<CheckedArray:l\d+>> NullCheck [<<Array>>]
+ /// CHECK-DAG: <<Length:i\d+>> ArrayLength [<<CheckedArray>>] is_string_length:false loop:none
+ /// CHECK-DAG: <<CheckedIndex:i\d+>> BoundsCheck [<<Index>>,<<Length>>]
+ /// CHECK-DAG: <<ArraySet:v\d+>> ArraySet [<<CheckedArray>>,<<CheckedIndex>>,<<Value>>]
+
+ /// CHECK-START-X86: void Main.testArrayLengthBoundsCheckX86(int[], int) x86_memory_operand_generation (after)
+ /// CHECK-DAG: <<Array:l\d+>> ParameterValue
+ /// CHECK-DAG: <<Index:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Value:i\d+>> IntConstant 9
+ /// CHECK-DAG: <<CheckedArray:l\d+>> NullCheck [<<Array>>]
+ /// CHECK-DAG: <<Length:i\d+>> ArrayLength [<<CheckedArray>>] is_string_length:false emitted_at_use:true loop:none
+ /// CHECK-DAG: <<CheckedIndex:i\d+>> BoundsCheck [<<Index>>,<<Length>>]
+ /// CHECK-DAG: <<ArraySet:v\d+>> ArraySet [<<CheckedArray>>,<<CheckedIndex>>,<<Value>>]
+
+ /// CHECK-START-X86: void Main.testArrayLengthBoundsCheckX86(int[], int) disassembly (after)
+ /// CHECK-DAG: <<Array:l\d+>> ParameterValue
+ /// CHECK-DAG: <<Index:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Value:i\d+>> IntConstant 9
+ /// CHECK: <<CheckedArray:l\d+>> NullCheck [<<Array>>]
+ /// CHECK-NEXT: <<Length:i\d+>> ArrayLength [<<Array>>] is_string_length:false emitted_at_use:true loop:none
+ /// CHECK-NEXT: <<CheckedIndex:i\d+>> BoundsCheck [<<Index>>,<<Length>>]
+ /// CHECK-NEXT: cmp [<<BaseReg:\w+>> + 8], <<IndexReg:\w+>>
+ /// CHECK: <<ArraySet:v\d+>> ArraySet [<<Array>>,<<Index>>,<<Value>>]
+ /// CHECK-NEXT: mov [<<BaseReg>> + <<IndexReg>> * 4 + 12], 9
+
+ /// CHECK-START-X86_64: void Main.testArrayLengthBoundsCheckX86(int[], int) x86_memory_operand_generation (before)
+ /// CHECK-DAG: <<Array:l\d+>> ParameterValue
+ /// CHECK-DAG: <<Index:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Value:i\d+>> IntConstant 9
+ /// CHECK-DAG: <<CheckedArray:l\d+>> NullCheck [<<Array>>]
+ /// CHECK-DAG: <<Length:i\d+>> ArrayLength [<<CheckedArray>>] is_string_length:false loop:none
+ /// CHECK-DAG: <<CheckedIndex:i\d+>> BoundsCheck [<<Index>>,<<Length>>]
+ /// CHECK-DAG: <<ArraySet:v\d+>> ArraySet [<<CheckedArray>>,<<CheckedIndex>>,<<Value>>]
+
+ /// CHECK-START-X86_64: void Main.testArrayLengthBoundsCheckX86(int[], int) x86_memory_operand_generation (after)
+ /// CHECK-DAG: <<Array:l\d+>> ParameterValue
+ /// CHECK-DAG: <<Index:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Value:i\d+>> IntConstant 9
+ /// CHECK-DAG: <<CheckedArray:l\d+>> NullCheck [<<Array>>]
+ /// CHECK-DAG: <<Length:i\d+>> ArrayLength [<<CheckedArray>>] is_string_length:false emitted_at_use:true loop:none
+ /// CHECK-DAG: <<CheckedIndex:i\d+>> BoundsCheck [<<Index>>,<<Length>>]
+ /// CHECK-DAG: <<ArraySet:v\d+>> ArraySet [<<CheckedArray>>,<<CheckedIndex>>,<<Value>>]
+
+ // Test assumes parameter value is in lower 8 registers (it is passed in edx).
+ /// CHECK-START-X86_64: void Main.testArrayLengthBoundsCheckX86(int[], int) disassembly (after)
+ /// CHECK-DAG: <<Array:l\d+>> ParameterValue
+ /// CHECK-DAG: <<Index:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Value:i\d+>> IntConstant 9
+ /// CHECK: <<CheckedArray:l\d+>> NullCheck [<<Array>>]
+ /// CHECK-NEXT: <<Length:i\d+>> ArrayLength [<<Array>>] is_string_length:false emitted_at_use:true loop:none
+ /// CHECK-NEXT: <<CheckedIndex:i\d+>> BoundsCheck [<<Index>>,<<Length>>]
+ /// CHECK-NEXT: cmp [<<BaseReg:\w+>> + 8], e<<IndexReg:\w+>>
+ /// CHECK: <<ArraySet:v\d+>> ArraySet [<<Array>>,<<Index>>,<<Value>>]
+ /// CHECK-NEXT: mov [<<BaseReg>> + r<<IndexReg>> * 4 + 12], 9
+
+ static void testArrayLengthBoundsCheckX86(int[] array, int index) {
+ array[index] = 9;
+ }
+}
diff --git a/tools/libcore_failures.txt b/tools/libcore_failures.txt
index f25fb98..996f2f8 100644
--- a/tools/libcore_failures.txt
+++ b/tools/libcore_failures.txt
@@ -253,5 +253,12 @@
names: ["jsr166.CollectionTest#testEmptyMeansEmpty",
"jsr166.Collection8Test#testForEach",
"jsr166.Collection8Test#testForEachConcurrentStressTest"]
+},
+{
+ description: "Flaky test",
+ result: EXEC_FAILED,
+ bug: 30107038,
+ modes: [device],
+ names: ["org.apache.harmony.tests.java.lang.ProcessTest#test_destroyForcibly"]
}
]