diff options
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/optimizing/code_generator_arm.cc | 49 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_arm.h | 20 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_arm64.cc | 95 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_arm64.h | 22 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_x86.cc | 23 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_x86.h | 17 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_x86_64.cc | 23 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_x86_64.h | 17 | ||||
| -rw-r--r-- | compiler/optimizing/intrinsics_arm.cc | 50 | ||||
| -rw-r--r-- | compiler/optimizing/intrinsics_arm64.cc | 51 | ||||
| -rw-r--r-- | compiler/optimizing/intrinsics_x86.cc | 38 | ||||
| -rw-r--r-- | compiler/optimizing/intrinsics_x86_64.cc | 50 | ||||
| -rw-r--r-- | compiler/optimizing/locations.h | 10 | ||||
| -rw-r--r-- | compiler/utils/string_reference.h | 7 | ||||
| -rw-r--r-- | compiler/utils/string_reference_test.cc | 107 |
15 files changed, 402 insertions, 177 deletions
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index b9466ba212..83b4705302 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -430,7 +430,9 @@ class ReadBarrierMarkSlowPathARM : public SlowPathCode { instruction_->IsLoadClass() || instruction_->IsLoadString() || instruction_->IsInstanceOf() || - instruction_->IsCheckCast()) + instruction_->IsCheckCast() || + ((instruction_->IsInvokeStaticOrDirect() || instruction_->IsInvokeVirtual()) && + instruction_->GetLocations()->Intrinsified())) << "Unexpected instruction in read barrier marking slow path: " << instruction_->DebugName(); @@ -493,8 +495,12 @@ class ReadBarrierForHeapReferenceSlowPathARM : public SlowPathCode { Register reg_out = out_.AsRegister<Register>(); DCHECK(locations->CanCall()); DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out)); - DCHECK(!instruction_->IsInvoke() || - (instruction_->IsInvokeStaticOrDirect() && + DCHECK(instruction_->IsInstanceFieldGet() || + instruction_->IsStaticFieldGet() || + instruction_->IsArrayGet() || + instruction_->IsInstanceOf() || + instruction_->IsCheckCast() || + ((instruction_->IsInvokeStaticOrDirect() || instruction_->IsInvokeVirtual()) && instruction_->GetLocations()->Intrinsified())) << "Unexpected instruction in read barrier for heap reference slow path: " << instruction_->DebugName(); @@ -507,7 +513,7 @@ class ReadBarrierForHeapReferenceSlowPathARM : public SlowPathCode { // introduce a copy of it, `index`. Location index = index_; if (index_.IsValid()) { - // Handle `index_` for HArrayGet and intrinsic UnsafeGetObject. + // Handle `index_` for HArrayGet and UnsafeGetObject/UnsafeGetObjectVolatile intrinsics. if (instruction_->IsArrayGet()) { // Compute the actual memory offset and store it in `index`. Register index_reg = index_.AsRegister<Register>(); @@ -555,7 +561,11 @@ class ReadBarrierForHeapReferenceSlowPathARM : public SlowPathCode { "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes."); __ AddConstant(index_reg, index_reg, offset_); } else { - DCHECK(instruction_->IsInvoke()); + // In the case of the UnsafeGetObject/UnsafeGetObjectVolatile + // intrinsics, `index_` is not shifted by a scale factor of 2 + // (as in the case of ArrayGet), as it is actually an offset + // to an object field within an object. + DCHECK(instruction_->IsInvoke()) << instruction_->DebugName(); DCHECK(instruction_->GetLocations()->Intrinsified()); DCHECK((instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObject) || (instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObjectVolatile)) @@ -6203,8 +6213,9 @@ void CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier(HInstruction* instr // /* HeapReference<Object> */ ref = *(obj + offset) Location no_index = Location::NoLocation(); + ScaleFactor no_scale_factor = TIMES_1; GenerateReferenceLoadWithBakerReadBarrier( - instruction, ref, obj, offset, no_index, temp, needs_null_check); + instruction, ref, obj, offset, no_index, no_scale_factor, temp, needs_null_check); } void CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier(HInstruction* instruction, @@ -6217,10 +6228,14 @@ void CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier(HInstruction* instr DCHECK(kEmitCompilerReadBarrier); DCHECK(kUseBakerReadBarrier); + static_assert( + sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t), + "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes."); // /* HeapReference<Object> */ ref = // *(obj + data_offset + index * sizeof(HeapReference<Object>)) + ScaleFactor scale_factor = TIMES_4; GenerateReferenceLoadWithBakerReadBarrier( - instruction, ref, obj, data_offset, index, temp, needs_null_check); + instruction, ref, obj, data_offset, index, scale_factor, temp, needs_null_check); } void CodeGeneratorARM::GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction, @@ -6228,6 +6243,7 @@ void CodeGeneratorARM::GenerateReferenceLoadWithBakerReadBarrier(HInstruction* i Register obj, uint32_t offset, Location index, + ScaleFactor scale_factor, Location temp, bool needs_null_check) { DCHECK(kEmitCompilerReadBarrier); @@ -6282,17 +6298,22 @@ void CodeGeneratorARM::GenerateReferenceLoadWithBakerReadBarrier(HInstruction* i // The actual reference load. if (index.IsValid()) { - static_assert( - sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t), - "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes."); - // /* HeapReference<Object> */ ref = - // *(obj + offset + index * sizeof(HeapReference<Object>)) + // Load types involving an "index": ArrayGet and + // UnsafeGetObject/UnsafeGetObjectVolatile intrinsics. + // /* HeapReference<Object> */ ref = *(obj + offset + (index << scale_factor)) if (index.IsConstant()) { size_t computed_offset = - (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + offset; + (index.GetConstant()->AsIntConstant()->GetValue() << scale_factor) + offset; __ LoadFromOffset(kLoadWord, ref_reg, obj, computed_offset); } else { - __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4)); + // Handle the special case of the + // UnsafeGetObject/UnsafeGetObjectVolatile intrinsics, which use + // a register pair as index ("long offset"), of which only the low + // part contains data. + Register index_reg = index.IsRegisterPair() + ? index.AsRegisterPairLow<Register>() + : index.AsRegister<Register>(); + __ add(IP, obj, ShifterOperand(index_reg, LSL, scale_factor)); __ LoadFromOffset(kLoadWord, ref_reg, IP, offset); } } else { diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h index 4fce5af8e6..477c4f18c1 100644 --- a/compiler/optimizing/code_generator_arm.h +++ b/compiler/optimizing/code_generator_arm.h @@ -472,6 +472,16 @@ class CodeGeneratorARM : public CodeGenerator { Location index, Location temp, bool needs_null_check); + // Factored implementation used by GenerateFieldLoadWithBakerReadBarrier + // and GenerateArrayLoadWithBakerReadBarrier. + void GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction, + Location ref, + Register obj, + uint32_t offset, + Location index, + ScaleFactor scale_factor, + Location temp, + bool needs_null_check); // Generate a read barrier for a heap reference within `instruction` // using a slow path. @@ -527,16 +537,6 @@ class CodeGeneratorARM : public CodeGenerator { void GenerateExplicitNullCheck(HNullCheck* instruction); private: - // Factored implementation of GenerateFieldLoadWithBakerReadBarrier - // and GenerateArrayLoadWithBakerReadBarrier. - void GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction, - Location ref, - Register obj, - uint32_t offset, - Location index, - Location temp, - bool needs_null_check); - Register GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOrDirect* invoke, Register temp); using Uint32ToLiteralMap = ArenaSafeMap<uint32_t, Literal*>; diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc index 4692a4a876..07d5e50c6b 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -598,7 +598,9 @@ class ReadBarrierMarkSlowPathARM64 : public SlowPathCodeARM64 { instruction_->IsLoadClass() || instruction_->IsLoadString() || instruction_->IsInstanceOf() || - instruction_->IsCheckCast()) + instruction_->IsCheckCast() || + ((instruction_->IsInvokeStaticOrDirect() || instruction_->IsInvokeVirtual()) && + instruction_->GetLocations()->Intrinsified())) << "Unexpected instruction in read barrier marking slow path: " << instruction_->DebugName(); @@ -661,8 +663,12 @@ class ReadBarrierForHeapReferenceSlowPathARM64 : public SlowPathCodeARM64 { Primitive::Type type = Primitive::kPrimNot; DCHECK(locations->CanCall()); DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(out_.reg())); - DCHECK(!instruction_->IsInvoke() || - (instruction_->IsInvokeStaticOrDirect() && + DCHECK(instruction_->IsInstanceFieldGet() || + instruction_->IsStaticFieldGet() || + instruction_->IsArrayGet() || + instruction_->IsInstanceOf() || + instruction_->IsCheckCast() || + ((instruction_->IsInvokeStaticOrDirect() || instruction_->IsInvokeVirtual()) && instruction_->GetLocations()->Intrinsified())) << "Unexpected instruction in read barrier for heap reference slow path: " << instruction_->DebugName(); @@ -680,7 +686,7 @@ class ReadBarrierForHeapReferenceSlowPathARM64 : public SlowPathCodeARM64 { // introduce a copy of it, `index`. Location index = index_; if (index_.IsValid()) { - // Handle `index_` for HArrayGet and intrinsic UnsafeGetObject. + // Handle `index_` for HArrayGet and UnsafeGetObject/UnsafeGetObjectVolatile intrinsics. if (instruction_->IsArrayGet()) { // Compute the actual memory offset and store it in `index`. Register index_reg = RegisterFrom(index_, Primitive::kPrimInt); @@ -728,7 +734,11 @@ class ReadBarrierForHeapReferenceSlowPathARM64 : public SlowPathCodeARM64 { "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes."); __ Add(index_reg, index_reg, Operand(offset_)); } else { - DCHECK(instruction_->IsInvoke()); + // In the case of the UnsafeGetObject/UnsafeGetObjectVolatile + // intrinsics, `index_` is not shifted by a scale factor of 2 + // (as in the case of ArrayGet), as it is actually an offset + // to an object field within an object. + DCHECK(instruction_->IsInvoke()) << instruction_->DebugName(); DCHECK(instruction_->GetLocations()->Intrinsified()); DCHECK((instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObject) || (instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObjectVolatile)) @@ -5102,8 +5112,16 @@ void CodeGeneratorARM64::GenerateFieldLoadWithBakerReadBarrier(HInstruction* ins // /* HeapReference<Object> */ ref = *(obj + offset) Location no_index = Location::NoLocation(); - GenerateReferenceLoadWithBakerReadBarrier( - instruction, ref, obj, offset, no_index, temp, needs_null_check, use_load_acquire); + size_t no_scale_factor = 0U; + GenerateReferenceLoadWithBakerReadBarrier(instruction, + ref, + obj, + offset, + no_index, + no_scale_factor, + temp, + needs_null_check, + use_load_acquire); } void CodeGeneratorARM64::GenerateArrayLoadWithBakerReadBarrier(HInstruction* instruction, @@ -5120,10 +5138,21 @@ void CodeGeneratorARM64::GenerateArrayLoadWithBakerReadBarrier(HInstruction* ins // never use Load-Acquire instructions on ARM64. const bool use_load_acquire = false; + static_assert( + sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t), + "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes."); // /* HeapReference<Object> */ ref = // *(obj + data_offset + index * sizeof(HeapReference<Object>)) - GenerateReferenceLoadWithBakerReadBarrier( - instruction, ref, obj, data_offset, index, temp, needs_null_check, use_load_acquire); + size_t scale_factor = Primitive::ComponentSizeShift(Primitive::kPrimNot); + GenerateReferenceLoadWithBakerReadBarrier(instruction, + ref, + obj, + data_offset, + index, + scale_factor, + temp, + needs_null_check, + use_load_acquire); } void CodeGeneratorARM64::GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction, @@ -5131,15 +5160,16 @@ void CodeGeneratorARM64::GenerateReferenceLoadWithBakerReadBarrier(HInstruction* vixl::Register obj, uint32_t offset, Location index, + size_t scale_factor, Register temp, bool needs_null_check, bool use_load_acquire) { DCHECK(kEmitCompilerReadBarrier); DCHECK(kUseBakerReadBarrier); - // If `index` is a valid location, then we are emitting an array - // load, so we shouldn't be using a Load Acquire instruction. - // In other words: `index.IsValid()` => `!use_load_acquire`. - DCHECK(!index.IsValid() || !use_load_acquire); + // If we are emitting an array load, we should not be using a + // Load Acquire instruction. In other words: + // `instruction->IsArrayGet()` => `!use_load_acquire`. + DCHECK(!instruction->IsArrayGet() || !use_load_acquire); MacroAssembler* masm = GetVIXLAssembler(); UseScratchRegisterScope temps(masm); @@ -5196,20 +5226,33 @@ void CodeGeneratorARM64::GenerateReferenceLoadWithBakerReadBarrier(HInstruction* // The actual reference load. if (index.IsValid()) { - static_assert( - sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t), - "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes."); - // /* HeapReference<Object> */ ref = - // *(obj + offset + index * sizeof(HeapReference<Object>)) - const size_t shift_amount = Primitive::ComponentSizeShift(type); - if (index.IsConstant()) { - uint32_t computed_offset = offset + (Int64ConstantFrom(index) << shift_amount); - Load(type, ref_reg, HeapOperand(obj, computed_offset)); + // Load types involving an "index". + if (use_load_acquire) { + // UnsafeGetObjectVolatile intrinsic case. + // Register `index` is not an index in an object array, but an + // offset to an object reference field within object `obj`. + DCHECK(instruction->IsInvoke()) << instruction->DebugName(); + DCHECK(instruction->GetLocations()->Intrinsified()); + DCHECK(instruction->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObjectVolatile) + << instruction->AsInvoke()->GetIntrinsic(); + DCHECK_EQ(offset, 0U); + DCHECK_EQ(scale_factor, 0U); + DCHECK_EQ(needs_null_check, 0U); + // /* HeapReference<Object> */ ref = *(obj + index) + MemOperand field = HeapOperand(obj, XRegisterFrom(index)); + LoadAcquire(instruction, ref_reg, field, /* needs_null_check */ false); } else { - temp2 = temps.AcquireW(); - __ Add(temp2, obj, offset); - Load(type, ref_reg, HeapOperand(temp2, XRegisterFrom(index), LSL, shift_amount)); - temps.Release(temp2); + // ArrayGet and UnsafeGetObject intrinsics cases. + // /* HeapReference<Object> */ ref = *(obj + offset + (index << scale_factor)) + if (index.IsConstant()) { + uint32_t computed_offset = offset + (Int64ConstantFrom(index) << scale_factor); + Load(type, ref_reg, HeapOperand(obj, computed_offset)); + } else { + temp2 = temps.AcquireW(); + __ Add(temp2, obj, offset); + Load(type, ref_reg, HeapOperand(temp2, XRegisterFrom(index), LSL, scale_factor)); + temps.Release(temp2); + } } } else { // /* HeapReference<Object> */ ref = *(obj + offset) diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h index e6fd336be7..d4bf695602 100644 --- a/compiler/optimizing/code_generator_arm64.h +++ b/compiler/optimizing/code_generator_arm64.h @@ -531,6 +531,17 @@ class CodeGeneratorARM64 : public CodeGenerator { Location index, vixl::Register temp, bool needs_null_check); + // Factored implementation used by GenerateFieldLoadWithBakerReadBarrier + // and GenerateArrayLoadWithBakerReadBarrier. + void GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction, + Location ref, + vixl::Register obj, + uint32_t offset, + Location index, + size_t scale_factor, + vixl::Register temp, + bool needs_null_check, + bool use_load_acquire); // Generate a read barrier for a heap reference within `instruction` // using a slow path. @@ -586,17 +597,6 @@ class CodeGeneratorARM64 : public CodeGenerator { void GenerateExplicitNullCheck(HNullCheck* instruction); private: - // Factored implementation of GenerateFieldLoadWithBakerReadBarrier - // and GenerateArrayLoadWithBakerReadBarrier. - void GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction, - Location ref, - vixl::Register obj, - uint32_t offset, - Location index, - vixl::Register temp, - bool needs_null_check, - bool use_load_acquire); - using Uint64ToLiteralMap = ArenaSafeMap<uint64_t, vixl::Literal<uint64_t>*>; using Uint32ToLiteralMap = ArenaSafeMap<uint32_t, vixl::Literal<uint32_t>*>; using MethodToLiteralMap = ArenaSafeMap<MethodReference, diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index 52868f4b2e..af10bad6cc 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -448,7 +448,9 @@ class ReadBarrierMarkSlowPathX86 : public SlowPathCode { instruction_->IsLoadClass() || instruction_->IsLoadString() || instruction_->IsInstanceOf() || - instruction_->IsCheckCast()) + instruction_->IsCheckCast() || + ((instruction_->IsInvokeStaticOrDirect() || instruction_->IsInvokeVirtual()) && + instruction_->GetLocations()->Intrinsified())) << "Unexpected instruction in read barrier marking slow path: " << instruction_->DebugName(); @@ -511,8 +513,12 @@ class ReadBarrierForHeapReferenceSlowPathX86 : public SlowPathCode { Register reg_out = out_.AsRegister<Register>(); DCHECK(locations->CanCall()); DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out)); - DCHECK(!instruction_->IsInvoke() || - (instruction_->IsInvokeStaticOrDirect() && + DCHECK(instruction_->IsInstanceFieldGet() || + instruction_->IsStaticFieldGet() || + instruction_->IsArrayGet() || + instruction_->IsInstanceOf() || + instruction_->IsCheckCast() || + ((instruction_->IsInvokeStaticOrDirect() || instruction_->IsInvokeVirtual()) && instruction_->GetLocations()->Intrinsified())) << "Unexpected instruction in read barrier for heap reference slow path: " << instruction_->DebugName(); @@ -525,7 +531,7 @@ class ReadBarrierForHeapReferenceSlowPathX86 : public SlowPathCode { // introduce a copy of it, `index`. Location index = index_; if (index_.IsValid()) { - // Handle `index_` for HArrayGet and intrinsic UnsafeGetObject. + // Handle `index_` for HArrayGet and UnsafeGetObject/UnsafeGetObjectVolatile intrinsics. if (instruction_->IsArrayGet()) { // Compute the actual memory offset and store it in `index`. Register index_reg = index_.AsRegister<Register>(); @@ -573,7 +579,11 @@ class ReadBarrierForHeapReferenceSlowPathX86 : public SlowPathCode { "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes."); __ AddImmediate(index_reg, Immediate(offset_)); } else { - DCHECK(instruction_->IsInvoke()); + // In the case of the UnsafeGetObject/UnsafeGetObjectVolatile + // intrinsics, `index_` is not shifted by a scale factor of 2 + // (as in the case of ArrayGet), as it is actually an offset + // to an object field within an object. + DCHECK(instruction_->IsInvoke()) << instruction_->DebugName(); DCHECK(instruction_->GetLocations()->Intrinsified()); DCHECK((instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObject) || (instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObjectVolatile)) @@ -6977,6 +6987,9 @@ void CodeGeneratorX86::GenerateArrayLoadWithBakerReadBarrier(HInstruction* instr DCHECK(kEmitCompilerReadBarrier); DCHECK(kUseBakerReadBarrier); + static_assert( + sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t), + "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes."); // /* HeapReference<Object> */ ref = // *(obj + data_offset + index * sizeof(HeapReference<Object>)) Address src = index.IsConstant() ? diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h index fb402bef00..2a9fb80995 100644 --- a/compiler/optimizing/code_generator_x86.h +++ b/compiler/optimizing/code_generator_x86.h @@ -491,6 +491,14 @@ class CodeGeneratorX86 : public CodeGenerator { Location index, Location temp, bool needs_null_check); + // Factored implementation used by GenerateFieldLoadWithBakerReadBarrier + // and GenerateArrayLoadWithBakerReadBarrier. + void GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction, + Location ref, + Register obj, + const Address& src, + Location temp, + bool needs_null_check); // Generate a read barrier for a heap reference within `instruction` // using a slow path. @@ -561,15 +569,6 @@ class CodeGeneratorX86 : public CodeGenerator { static constexpr int32_t kDummy32BitOffset = 256; private: - // Factored implementation of GenerateFieldLoadWithBakerReadBarrier - // and GenerateArrayLoadWithBakerReadBarrier. - void GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction, - Location ref, - Register obj, - const Address& src, - Location temp, - bool needs_null_check); - Register GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOrDirect* invoke, Register temp); struct PcRelativeDexCacheAccessInfo { diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index 9a3e8d266b..2b21454101 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -469,7 +469,9 @@ class ReadBarrierMarkSlowPathX86_64 : public SlowPathCode { instruction_->IsLoadClass() || instruction_->IsLoadString() || instruction_->IsInstanceOf() || - instruction_->IsCheckCast()) + instruction_->IsCheckCast() || + ((instruction_->IsInvokeStaticOrDirect() || instruction_->IsInvokeVirtual()) && + instruction_->GetLocations()->Intrinsified())) << "Unexpected instruction in read barrier marking slow path: " << instruction_->DebugName(); @@ -532,8 +534,12 @@ class ReadBarrierForHeapReferenceSlowPathX86_64 : public SlowPathCode { CpuRegister reg_out = out_.AsRegister<CpuRegister>(); DCHECK(locations->CanCall()); DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out.AsRegister())) << out_; - DCHECK(!instruction_->IsInvoke() || - (instruction_->IsInvokeStaticOrDirect() && + DCHECK(instruction_->IsInstanceFieldGet() || + instruction_->IsStaticFieldGet() || + instruction_->IsArrayGet() || + instruction_->IsInstanceOf() || + instruction_->IsCheckCast() || + ((instruction_->IsInvokeStaticOrDirect() || instruction_->IsInvokeVirtual()) && instruction_->GetLocations()->Intrinsified())) << "Unexpected instruction in read barrier for heap reference slow path: " << instruction_->DebugName(); @@ -546,7 +552,7 @@ class ReadBarrierForHeapReferenceSlowPathX86_64 : public SlowPathCode { // introduce a copy of it, `index`. Location index = index_; if (index_.IsValid()) { - // Handle `index_` for HArrayGet and intrinsic UnsafeGetObject. + // Handle `index_` for HArrayGet and UnsafeGetObject/UnsafeGetObjectVolatile intrinsics. if (instruction_->IsArrayGet()) { // Compute real offset and store it in index_. Register index_reg = index_.AsRegister<CpuRegister>().AsRegister(); @@ -594,7 +600,11 @@ class ReadBarrierForHeapReferenceSlowPathX86_64 : public SlowPathCode { "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes."); __ AddImmediate(CpuRegister(index_reg), Immediate(offset_)); } else { - DCHECK(instruction_->IsInvoke()); + // In the case of the UnsafeGetObject/UnsafeGetObjectVolatile + // intrinsics, `index_` is not shifted by a scale factor of 2 + // (as in the case of ArrayGet), as it is actually an offset + // to an object field within an object. + DCHECK(instruction_->IsInvoke()) << instruction_->DebugName(); DCHECK(instruction_->GetLocations()->Intrinsified()); DCHECK((instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObject) || (instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObjectVolatile)) @@ -6430,6 +6440,9 @@ void CodeGeneratorX86_64::GenerateArrayLoadWithBakerReadBarrier(HInstruction* in DCHECK(kEmitCompilerReadBarrier); DCHECK(kUseBakerReadBarrier); + static_assert( + sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t), + "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes."); // /* HeapReference<Object> */ ref = // *(obj + data_offset + index * sizeof(HeapReference<Object>)) Address src = index.IsConstant() ? diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h index cf4cc4c8d2..d7cfd37c33 100644 --- a/compiler/optimizing/code_generator_x86_64.h +++ b/compiler/optimizing/code_generator_x86_64.h @@ -433,6 +433,14 @@ class CodeGeneratorX86_64 : public CodeGenerator { Location index, Location temp, bool needs_null_check); + // Factored implementation used by GenerateFieldLoadWithBakerReadBarrier + // and GenerateArrayLoadWithBakerReadBarrier. + void GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction, + Location ref, + CpuRegister obj, + const Address& src, + Location temp, + bool needs_null_check); // Generate a read barrier for a heap reference within `instruction` // using a slow path. @@ -535,15 +543,6 @@ class CodeGeneratorX86_64 : public CodeGenerator { static constexpr int32_t kDummy32BitOffset = 256; private: - // Factored implementation of GenerateFieldLoadWithBakerReadBarrier - // and GenerateArrayLoadWithBakerReadBarrier. - void GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction, - Location ref, - CpuRegister obj, - const Address& src, - Location temp, - bool needs_null_check); - struct PcRelativeDexCacheAccessInfo { PcRelativeDexCacheAccessInfo(const DexFile& dex_file, uint32_t element_off) : target_dex_file(dex_file), element_offset(element_off), label() { } diff --git a/compiler/optimizing/intrinsics_arm.cc b/compiler/optimizing/intrinsics_arm.cc index 93950d58b5..f43f8edf06 100644 --- a/compiler/optimizing/intrinsics_arm.cc +++ b/compiler/optimizing/intrinsics_arm.cc @@ -47,19 +47,6 @@ bool IntrinsicLocationsBuilderARM::TryDispatch(HInvoke* invoke) { if (res == nullptr) { return false; } - if (kEmitCompilerReadBarrier && res->CanCall()) { - // Generating an intrinsic for this HInvoke may produce an - // IntrinsicSlowPathARM slow path. Currently this approach - // does not work when using read barriers, as the emitted - // calling sequence will make use of another slow path - // (ReadBarrierForRootSlowPathARM for HInvokeStaticOrDirect, - // ReadBarrierSlowPathARM for HInvokeVirtual). So we bail - // out in this case. - // - // TODO: Find a way to have intrinsics work with read barriers. - invoke->SetLocations(nullptr); - return false; - } return res->Intrinsified(); } @@ -524,8 +511,8 @@ static void GenUnsafeGet(HInvoke* invoke, if (kEmitCompilerReadBarrier) { if (kUseBakerReadBarrier) { Location temp = locations->GetTemp(0); - codegen->GenerateArrayLoadWithBakerReadBarrier( - invoke, trg_loc, base, 0U, offset_loc, temp, /* needs_null_check */ false); + codegen->GenerateReferenceLoadWithBakerReadBarrier( + invoke, trg_loc, base, 0U, offset_loc, TIMES_1, temp, /* needs_null_check */ false); if (is_volatile) { __ dmb(ISH); } @@ -581,10 +568,11 @@ static void CreateIntIntIntToIntLocations(ArenaAllocator* arena, locations->SetInAt(0, Location::NoLocation()); // Unused receiver. locations->SetInAt(1, Location::RequiresRegister()); locations->SetInAt(2, Location::RequiresRegister()); - locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); + locations->SetOut(Location::RequiresRegister(), + can_call ? Location::kOutputOverlap : Location::kNoOutputOverlap); if (type == Primitive::kPrimNot && kEmitCompilerReadBarrier && kUseBakerReadBarrier) { // We need a temporary register for the read barrier marking slow - // path in InstructionCodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier. + // path in InstructionCodeGeneratorARM::GenerateReferenceLoadWithBakerReadBarrier. locations->AddTemp(Location::RequiresRegister()); } } @@ -919,9 +907,10 @@ void IntrinsicLocationsBuilderARM::VisitUnsafeCASObject(HInvoke* invoke) { // The UnsafeCASObject intrinsic is missing a read barrier, and // therefore sometimes does not work as expected (b/25883050). // Turn it off temporarily as a quick fix, until the read barrier is - // implemented (see TODO in GenCAS below). + // implemented (see TODO in GenCAS). // - // TODO(rpl): Fix this issue and re-enable this intrinsic with read barriers. + // TODO(rpl): Implement read barrier support in GenCAS and re-enable + // this intrinsic. if (kEmitCompilerReadBarrier) { return; } @@ -932,6 +921,15 @@ void IntrinsicCodeGeneratorARM::VisitUnsafeCASInt(HInvoke* invoke) { GenCas(invoke->GetLocations(), Primitive::kPrimInt, codegen_); } void IntrinsicCodeGeneratorARM::VisitUnsafeCASObject(HInvoke* invoke) { + // The UnsafeCASObject intrinsic is missing a read barrier, and + // therefore sometimes does not work as expected (b/25883050). + // Turn it off temporarily as a quick fix, until the read barrier is + // implemented (see TODO in GenCAS). + // + // TODO(rpl): Implement read barrier support in GenCAS and re-enable + // this intrinsic. + DCHECK(!kEmitCompilerReadBarrier); + GenCas(invoke->GetLocations(), Primitive::kPrimNot, codegen_); } @@ -1335,6 +1333,12 @@ void IntrinsicCodeGeneratorARM::VisitStringNewStringFromString(HInvoke* invoke) } void IntrinsicLocationsBuilderARM::VisitSystemArrayCopy(HInvoke* invoke) { + // TODO(rpl): Implement read barriers in the SystemArrayCopy + // intrinsic and re-enable it (b/29516905). + if (kEmitCompilerReadBarrier) { + return; + } + CodeGenerator::CreateSystemArrayCopyLocationSummary(invoke); LocationSummary* locations = invoke->GetLocations(); if (locations == nullptr) { @@ -1419,11 +1423,11 @@ static void CheckPosition(ArmAssembler* assembler, } } -// TODO: Implement read barriers in the SystemArrayCopy intrinsic. -// Note that this code path is not used (yet) because we do not -// intrinsify methods that can go into the IntrinsicSlowPathARM -// slow path. void IntrinsicCodeGeneratorARM::VisitSystemArrayCopy(HInvoke* invoke) { + // TODO(rpl): Implement read barriers in the SystemArrayCopy + // intrinsic and re-enable it (b/29516905). + DCHECK(!kEmitCompilerReadBarrier); + ArmAssembler* assembler = GetAssembler(); LocationSummary* locations = invoke->GetLocations(); diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc index 4da0843a76..1685cf9c3c 100644 --- a/compiler/optimizing/intrinsics_arm64.cc +++ b/compiler/optimizing/intrinsics_arm64.cc @@ -149,19 +149,6 @@ bool IntrinsicLocationsBuilderARM64::TryDispatch(HInvoke* invoke) { if (res == nullptr) { return false; } - if (kEmitCompilerReadBarrier && res->CanCall()) { - // Generating an intrinsic for this HInvoke may produce an - // IntrinsicSlowPathARM64 slow path. Currently this approach - // does not work when using read barriers, as the emitted - // calling sequence will make use of another slow path - // (ReadBarrierForRootSlowPathARM64 for HInvokeStaticOrDirect, - // ReadBarrierSlowPathARM64 for HInvokeVirtual). So we bail - // out in this case. - // - // TODO: Find a way to have intrinsics work with read barriers. - invoke->SetLocations(nullptr); - return false; - } return res->Intrinsified(); } @@ -791,8 +778,15 @@ static void GenUnsafeGet(HInvoke* invoke, // UnsafeGetObject/UnsafeGetObjectVolatile with Baker's read barrier case. UseScratchRegisterScope temps(masm); Register temp = temps.AcquireW(); - codegen->GenerateArrayLoadWithBakerReadBarrier( - invoke, trg_loc, base, 0U, offset_loc, temp, /* needs_null_check */ false); + codegen->GenerateReferenceLoadWithBakerReadBarrier(invoke, + trg_loc, + base, + /* offset */ 0U, + /* index */ offset_loc, + /* scale_factor */ 0U, + temp, + /* needs_null_check */ false, + is_volatile); } else { // Other cases. MemOperand mem_op(base.X(), offset); @@ -821,7 +815,8 @@ static void CreateIntIntIntToIntLocations(ArenaAllocator* arena, HInvoke* invoke locations->SetInAt(0, Location::NoLocation()); // Unused receiver. locations->SetInAt(1, Location::RequiresRegister()); locations->SetInAt(2, Location::RequiresRegister()); - locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); + locations->SetOut(Location::RequiresRegister(), + can_call ? Location::kOutputOverlap : Location::kNoOutputOverlap); } void IntrinsicLocationsBuilderARM64::VisitUnsafeGet(HInvoke* invoke) { @@ -1102,9 +1097,10 @@ void IntrinsicLocationsBuilderARM64::VisitUnsafeCASObject(HInvoke* invoke) { // The UnsafeCASObject intrinsic is missing a read barrier, and // therefore sometimes does not work as expected (b/25883050). // Turn it off temporarily as a quick fix, until the read barrier is - // implemented (see TODO in GenCAS below). + // implemented (see TODO in GenCAS). // - // TODO(rpl): Fix this issue and re-enable this intrinsic with read barriers. + // TODO(rpl): Implement read barrier support in GenCAS and re-enable + // this intrinsic. if (kEmitCompilerReadBarrier) { return; } @@ -1119,6 +1115,15 @@ void IntrinsicCodeGeneratorARM64::VisitUnsafeCASLong(HInvoke* invoke) { GenCas(invoke->GetLocations(), Primitive::kPrimLong, codegen_); } void IntrinsicCodeGeneratorARM64::VisitUnsafeCASObject(HInvoke* invoke) { + // The UnsafeCASObject intrinsic is missing a read barrier, and + // therefore sometimes does not work as expected (b/25883050). + // Turn it off temporarily as a quick fix, until the read barrier is + // implemented (see TODO in GenCAS). + // + // TODO(rpl): Implement read barrier support in GenCAS and re-enable + // this intrinsic. + DCHECK(!kEmitCompilerReadBarrier); + GenCas(invoke->GetLocations(), Primitive::kPrimNot, codegen_); } @@ -2012,6 +2017,12 @@ static constexpr int32_t kSystemArrayCopyThreshold = 128; // We want to use two temporary registers in order to reduce the register pressure in arm64. // So we don't use the CodeGenerator::CreateSystemArrayCopyLocationSummary. void IntrinsicLocationsBuilderARM64::VisitSystemArrayCopy(HInvoke* invoke) { + // TODO(rpl): Implement read barriers in the SystemArrayCopy + // intrinsic and re-enable it (b/29516905). + if (kEmitCompilerReadBarrier) { + return; + } + // Check to see if we have known failures that will cause us to have to bail out // to the runtime, and just generate the runtime call directly. HIntConstant* src_pos = invoke->InputAt(1)->AsIntConstant(); @@ -2064,6 +2075,10 @@ void IntrinsicLocationsBuilderARM64::VisitSystemArrayCopy(HInvoke* invoke) { } void IntrinsicCodeGeneratorARM64::VisitSystemArrayCopy(HInvoke* invoke) { + // TODO(rpl): Implement read barriers in the SystemArrayCopy + // intrinsic and re-enable it (b/29516905). + DCHECK(!kEmitCompilerReadBarrier); + vixl::MacroAssembler* masm = GetVIXLAssembler(); LocationSummary* locations = invoke->GetLocations(); diff --git a/compiler/optimizing/intrinsics_x86.cc b/compiler/optimizing/intrinsics_x86.cc index 4988398c92..031cd1313c 100644 --- a/compiler/optimizing/intrinsics_x86.cc +++ b/compiler/optimizing/intrinsics_x86.cc @@ -60,19 +60,6 @@ bool IntrinsicLocationsBuilderX86::TryDispatch(HInvoke* invoke) { if (res == nullptr) { return false; } - if (kEmitCompilerReadBarrier && res->CanCall()) { - // Generating an intrinsic for this HInvoke may produce an - // IntrinsicSlowPathX86 slow path. Currently this approach - // does not work when using read barriers, as the emitted - // calling sequence will make use of another slow path - // (ReadBarrierForRootSlowPathX86 for HInvokeStaticOrDirect, - // ReadBarrierSlowPathX86 for HInvokeVirtual). So we bail - // out in this case. - // - // TODO: Find a way to have intrinsics work with read barriers. - invoke->SetLocations(nullptr); - return false; - } return res->Intrinsified(); } @@ -1822,8 +1809,9 @@ static void GenUnsafeGet(HInvoke* invoke, if (kEmitCompilerReadBarrier) { if (kUseBakerReadBarrier) { Location temp = locations->GetTemp(0); - codegen->GenerateArrayLoadWithBakerReadBarrier( - invoke, output_loc, base, 0U, offset_loc, temp, /* needs_null_check */ false); + Address src(base, offset, ScaleFactor::TIMES_1, 0); + codegen->GenerateReferenceLoadWithBakerReadBarrier( + invoke, output_loc, base, src, temp, /* needs_null_check */ false); } else { __ movl(output, Address(base, offset, ScaleFactor::TIMES_1, 0)); codegen->GenerateReadBarrierSlow( @@ -1878,16 +1866,17 @@ static void CreateIntIntIntToIntLocations(ArenaAllocator* arena, if (is_volatile) { // Need to use XMM to read volatile. locations->AddTemp(Location::RequiresFpuRegister()); - locations->SetOut(Location::RequiresRegister()); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); } else { locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap); } } else { - locations->SetOut(Location::RequiresRegister()); + locations->SetOut(Location::RequiresRegister(), + can_call ? Location::kOutputOverlap : Location::kNoOutputOverlap); } if (type == Primitive::kPrimNot && kEmitCompilerReadBarrier && kUseBakerReadBarrier) { // We need a temporary register for the read barrier marking slow - // path in InstructionCodeGeneratorX86::GenerateArrayLoadWithBakerReadBarrier. + // path in InstructionCodeGeneratorX86::GenerateReferenceLoadWithBakerReadBarrier. locations->AddTemp(Location::RequiresRegister()); } } @@ -2109,9 +2098,9 @@ void IntrinsicLocationsBuilderX86::VisitUnsafeCASObject(HInvoke* invoke) { // The UnsafeCASObject intrinsic is missing a read barrier, and // therefore sometimes does not work as expected (b/25883050). // Turn it off temporarily as a quick fix, until the read barrier is - // implemented. + // implemented (see TODO in GenCAS). // - // TODO(rpl): Implement a read barrier in GenCAS below and re-enable + // TODO(rpl): Implement read barrier support in GenCAS and re-enable // this intrinsic. if (kEmitCompilerReadBarrier) { return; @@ -2236,6 +2225,15 @@ void IntrinsicCodeGeneratorX86::VisitUnsafeCASLong(HInvoke* invoke) { } void IntrinsicCodeGeneratorX86::VisitUnsafeCASObject(HInvoke* invoke) { + // The UnsafeCASObject intrinsic is missing a read barrier, and + // therefore sometimes does not work as expected (b/25883050). + // Turn it off temporarily as a quick fix, until the read barrier is + // implemented (see TODO in GenCAS). + // + // TODO(rpl): Implement read barrier support in GenCAS and re-enable + // this intrinsic. + DCHECK(!kEmitCompilerReadBarrier); + GenCAS(Primitive::kPrimNot, invoke, codegen_); } diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc index 405b4c02ec..c5b44d4f5c 100644 --- a/compiler/optimizing/intrinsics_x86_64.cc +++ b/compiler/optimizing/intrinsics_x86_64.cc @@ -54,19 +54,6 @@ bool IntrinsicLocationsBuilderX86_64::TryDispatch(HInvoke* invoke) { if (res == nullptr) { return false; } - if (kEmitCompilerReadBarrier && res->CanCall()) { - // Generating an intrinsic for this HInvoke may produce an - // IntrinsicSlowPathX86_64 slow path. Currently this approach - // does not work when using read barriers, as the emitted - // calling sequence will make use of another slow path - // (ReadBarrierForRootSlowPathX86_64 for HInvokeStaticOrDirect, - // ReadBarrierSlowPathX86_64 for HInvokeVirtual). So we bail - // out in this case. - // - // TODO: Find a way to have intrinsics work with read barriers. - invoke->SetLocations(nullptr); - return false; - } return res->Intrinsified(); } @@ -1079,14 +1066,20 @@ void IntrinsicCodeGeneratorX86_64::VisitSystemArrayCopyChar(HInvoke* invoke) { void IntrinsicLocationsBuilderX86_64::VisitSystemArrayCopy(HInvoke* invoke) { + // TODO(rpl): Implement read barriers in the SystemArrayCopy + // intrinsic and re-enable it (b/29516905). + if (kEmitCompilerReadBarrier) { + return; + } + CodeGenerator::CreateSystemArrayCopyLocationSummary(invoke); } -// TODO: Implement read barriers in the SystemArrayCopy intrinsic. -// Note that this code path is not used (yet) because we do not -// intrinsify methods that can go into the IntrinsicSlowPathX86_64 -// slow path. void IntrinsicCodeGeneratorX86_64::VisitSystemArrayCopy(HInvoke* invoke) { + // TODO(rpl): Implement read barriers in the SystemArrayCopy + // intrinsic and re-enable it (b/29516905). + DCHECK(!kEmitCompilerReadBarrier); + X86_64Assembler* assembler = GetAssembler(); LocationSummary* locations = invoke->GetLocations(); @@ -1910,8 +1903,9 @@ static void GenUnsafeGet(HInvoke* invoke, if (kEmitCompilerReadBarrier) { if (kUseBakerReadBarrier) { Location temp = locations->GetTemp(0); - codegen->GenerateArrayLoadWithBakerReadBarrier( - invoke, output_loc, base, 0U, offset_loc, temp, /* needs_null_check */ false); + Address src(base, offset, ScaleFactor::TIMES_1, 0); + codegen->GenerateReferenceLoadWithBakerReadBarrier( + invoke, output_loc, base, src, temp, /* needs_null_check */ false); } else { __ movl(output, Address(base, offset, ScaleFactor::TIMES_1, 0)); codegen->GenerateReadBarrierSlow( @@ -1948,10 +1942,11 @@ static void CreateIntIntIntToIntLocations(ArenaAllocator* arena, locations->SetInAt(0, Location::NoLocation()); // Unused receiver. locations->SetInAt(1, Location::RequiresRegister()); locations->SetInAt(2, Location::RequiresRegister()); - locations->SetOut(Location::RequiresRegister()); + locations->SetOut(Location::RequiresRegister(), + can_call ? Location::kOutputOverlap : Location::kNoOutputOverlap); if (type == Primitive::kPrimNot && kEmitCompilerReadBarrier && kUseBakerReadBarrier) { // We need a temporary register for the read barrier marking slow - // path in InstructionCodeGeneratorX86_64::GenerateArrayLoadWithBakerReadBarrier. + // path in InstructionCodeGeneratorX86_64::GenerateReferenceLoadWithBakerReadBarrier. locations->AddTemp(Location::RequiresRegister()); } } @@ -2135,9 +2130,9 @@ void IntrinsicLocationsBuilderX86_64::VisitUnsafeCASObject(HInvoke* invoke) { // The UnsafeCASObject intrinsic is missing a read barrier, and // therefore sometimes does not work as expected (b/25883050). // Turn it off temporarily as a quick fix, until the read barrier is - // implemented. + // implemented (see TODO in GenCAS). // - // TODO(rpl): Implement a read barrier in GenCAS below and re-enable + // TODO(rpl): Implement read barrier support in GenCAS and re-enable // this intrinsic. if (kEmitCompilerReadBarrier) { return; @@ -2253,6 +2248,15 @@ void IntrinsicCodeGeneratorX86_64::VisitUnsafeCASLong(HInvoke* invoke) { } void IntrinsicCodeGeneratorX86_64::VisitUnsafeCASObject(HInvoke* invoke) { + // The UnsafeCASObject intrinsic is missing a read barrier, and + // therefore sometimes does not work as expected (b/25883050). + // Turn it off temporarily as a quick fix, until the read barrier is + // implemented (see TODO in GenCAS). + // + // TODO(rpl): Implement read barrier support in GenCAS and re-enable + // this intrinsic. + DCHECK(!kEmitCompilerReadBarrier); + GenCAS(Primitive::kPrimNot, invoke, codegen_); } diff --git a/compiler/optimizing/locations.h b/compiler/optimizing/locations.h index 63bbc2cd0a..3f27c911be 100644 --- a/compiler/optimizing/locations.h +++ b/compiler/optimizing/locations.h @@ -38,7 +38,13 @@ std::ostream& operator<<(std::ostream& os, const Location& location); class Location : public ValueObject { public: enum OutputOverlap { + // The liveness of the output overlaps the liveness of one or + // several input(s); the register allocator cannot reuse an + // input's location for the output's location. kOutputOverlap, + // The liveness of the output does not overlap the liveness of any + // input; the register allocator is allowed to reuse an input's + // location for the output's location. kNoOutputOverlap }; @@ -494,6 +500,10 @@ class LocationSummary : public ArenaObject<kArenaAllocLocationSummary> { return inputs_.size(); } + // Set the output location. Argument `overlaps` tells whether the + // output overlaps any of the inputs (if so, it cannot share the + // same register as one of the inputs); it is set to + // `Location::kOutputOverlap` by default for safety. void SetOut(Location location, Location::OutputOverlap overlaps = Location::kOutputOverlap) { DCHECK(output_.IsInvalid()); output_overlaps_ = overlaps; diff --git a/compiler/utils/string_reference.h b/compiler/utils/string_reference.h index 9e1058ea4d..0ab45c86e3 100644 --- a/compiler/utils/string_reference.h +++ b/compiler/utils/string_reference.h @@ -20,12 +20,11 @@ #include <stdint.h> #include "base/logging.h" +#include "dex_file-inl.h" #include "utf-inl.h" namespace art { -class DexFile; - // A string is located by its DexFile and the string_ids_ table index into that DexFile. struct StringReference { StringReference(const DexFile* file, uint32_t index) : dex_file(file), string_index(index) { } @@ -48,13 +47,13 @@ struct StringReferenceValueComparator { sr1.string_index < sr2.string_index, CompareModifiedUtf8ToModifiedUtf8AsUtf16CodePointValues( sr1.dex_file->GetStringData(sr1.dex_file->GetStringId(sr1.string_index)), - sr1.dex_file->GetStringData(sr2.dex_file->GetStringId(sr2.string_index))) < 0); + sr2.dex_file->GetStringData(sr2.dex_file->GetStringId(sr2.string_index))) < 0); return sr1.string_index < sr2.string_index; } else { // Cannot compare indexes, so do the string comparison. return CompareModifiedUtf8ToModifiedUtf8AsUtf16CodePointValues( sr1.dex_file->GetStringData(sr1.dex_file->GetStringId(sr1.string_index)), - sr1.dex_file->GetStringData(sr2.dex_file->GetStringId(sr2.string_index))) < 0; + sr2.dex_file->GetStringData(sr2.dex_file->GetStringId(sr2.string_index))) < 0; } } }; diff --git a/compiler/utils/string_reference_test.cc b/compiler/utils/string_reference_test.cc new file mode 100644 index 0000000000..df5080e93e --- /dev/null +++ b/compiler/utils/string_reference_test.cc @@ -0,0 +1,107 @@ +/* + * 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. + */ + +#include "utils/string_reference.h" + +#include <memory> + +#include "gtest/gtest.h" +#include "utils/test_dex_file_builder.h" + +namespace art { + +TEST(StringReference, ValueComparator) { + // This is a regression test for the StringReferenceValueComparator using the wrong + // dex file to get the string data from a StringId. We construct two dex files with + // just a single string with the same length but different value. This creates dex + // files that have the same layout, so the byte offset read from the StringId in one + // dex file, when used in the other dex file still points to valid string data, except + // that it's the wrong string. Without the fix the strings would then compare equal. + TestDexFileBuilder builder1; + builder1.AddString("String1"); + std::unique_ptr<const DexFile> dex_file1 = builder1.Build("dummy location 1"); + ASSERT_EQ(1u, dex_file1->NumStringIds()); + ASSERT_STREQ("String1", dex_file1->GetStringData(dex_file1->GetStringId(0))); + StringReference sr1(dex_file1.get(), 0); + + TestDexFileBuilder builder2; + builder2.AddString("String2"); + std::unique_ptr<const DexFile> dex_file2 = builder2.Build("dummy location 2"); + ASSERT_EQ(1u, dex_file2->NumStringIds()); + ASSERT_STREQ("String2", dex_file2->GetStringData(dex_file2->GetStringId(0))); + StringReference sr2(dex_file2.get(), 0); + + StringReferenceValueComparator cmp; + EXPECT_TRUE(cmp(sr1, sr2)); // "String1" < "String2" is true. + EXPECT_FALSE(cmp(sr2, sr1)); // "String2" < "String1" is false. +} + +TEST(StringReference, ValueComparator2) { + const char* const kDexFile1Strings[] = { + "", + "abc", + "abcxyz", + }; + const char* const kDexFile2Strings[] = { + "a", + "abc", + "abcdef", + "def", + }; + const bool expectedCmp12[arraysize(kDexFile1Strings)][arraysize(kDexFile2Strings)] = { + { true, true, true, true }, + { false, false, true, true }, + { false, false, false, true }, + }; + const bool expectedCmp21[arraysize(kDexFile2Strings)][arraysize(kDexFile1Strings)] = { + { false, true, true }, + { false, false, true }, + { false, false, true }, + { false, false, false }, + }; + + TestDexFileBuilder builder1; + for (const char* s : kDexFile1Strings) { + builder1.AddString(s); + } + std::unique_ptr<const DexFile> dex_file1 = builder1.Build("dummy location 1"); + ASSERT_EQ(arraysize(kDexFile1Strings), dex_file1->NumStringIds()); + for (size_t index = 0; index != arraysize(kDexFile1Strings); ++index) { + ASSERT_STREQ(kDexFile1Strings[index], dex_file1->GetStringData(dex_file1->GetStringId(index))); + } + + TestDexFileBuilder builder2; + for (const char* s : kDexFile2Strings) { + builder2.AddString(s); + } + std::unique_ptr<const DexFile> dex_file2 = builder2.Build("dummy location 1"); + ASSERT_EQ(arraysize(kDexFile2Strings), dex_file2->NumStringIds()); + for (size_t index = 0; index != arraysize(kDexFile2Strings); ++index) { + ASSERT_STREQ(kDexFile2Strings[index], dex_file2->GetStringData(dex_file2->GetStringId(index))); + } + + StringReferenceValueComparator cmp; + for (size_t index1 = 0; index1 != arraysize(kDexFile1Strings); ++index1) { + for (size_t index2 = 0; index2 != arraysize(kDexFile2Strings); ++index2) { + StringReference sr1(dex_file1.get(), index1); + StringReference sr2(dex_file2.get(), index2); + EXPECT_EQ(expectedCmp12[index1][index2], cmp(sr1, sr2)) << index1 << " " << index2; + EXPECT_EQ(expectedCmp21[index2][index1], cmp(sr2, sr1)) << index1 << " " << index2; + } + } +} + +} // namespace art |