diff options
author | 2020-10-28 15:43:54 +0000 | |
---|---|---|
committer | 2020-11-04 18:06:08 +0000 | |
commit | 01b65526c1dce94abb8ed98d473ddcd2b8fcd692 (patch) | |
tree | edc3f88f666415ffb459bad64a585fa576dc65ab | |
parent | 908759b00ba0d84445636cc7cfcaf830b45e7b73 (diff) |
Implement Reference.getReferent() intrinsic.
Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing --jit
Test: aosp_blueline-userdebug boots.
Test: run-gtests.sh
Test: testrunner.py --target --optimizing --jit
Bug: 170286013
Change-Id: I4762f7c1cf3d61de2215ec8f1d14be80289c2372
-rw-r--r-- | compiler/optimizing/code_generator_arm_vixl.cc | 4 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_arm_vixl.h | 2 | ||||
-rw-r--r-- | compiler/optimizing/intrinsics.cc | 58 | ||||
-rw-r--r-- | compiler/optimizing/intrinsics.h | 4 | ||||
-rw-r--r-- | compiler/optimizing/intrinsics_arm64.cc | 62 | ||||
-rw-r--r-- | compiler/optimizing/intrinsics_arm_vixl.cc | 63 | ||||
-rw-r--r-- | compiler/optimizing/intrinsics_x86.cc | 83 | ||||
-rw-r--r-- | compiler/optimizing/intrinsics_x86_64.cc | 54 | ||||
-rw-r--r-- | runtime/thread.h | 7 |
9 files changed, 308 insertions, 29 deletions
diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc index 00b258685c..1dedfc580c 100644 --- a/compiler/optimizing/code_generator_arm_vixl.cc +++ b/compiler/optimizing/code_generator_arm_vixl.cc @@ -8893,12 +8893,12 @@ void CodeGeneratorARMVIXL::GenerateFieldLoadWithBakerReadBarrier(HInstruction* i Location ref, vixl32::Register obj, uint32_t offset, - Location temp, + Location maybe_temp, bool needs_null_check) { DCHECK_ALIGNED(offset, sizeof(mirror::HeapReference<mirror::Object>)); vixl32::Register base = obj; if (offset >= kReferenceLoadMinFarOffset) { - base = RegisterFrom(temp); + base = RegisterFrom(maybe_temp); static_assert(IsPowerOfTwo(kReferenceLoadMinFarOffset), "Expecting a power of 2."); __ Add(base, obj, Operand(offset & ~(kReferenceLoadMinFarOffset - 1u))); offset &= (kReferenceLoadMinFarOffset - 1u); diff --git a/compiler/optimizing/code_generator_arm_vixl.h b/compiler/optimizing/code_generator_arm_vixl.h index 8f3d41cbf2..23d05ae7df 100644 --- a/compiler/optimizing/code_generator_arm_vixl.h +++ b/compiler/optimizing/code_generator_arm_vixl.h @@ -677,7 +677,7 @@ class CodeGeneratorARMVIXL : public CodeGenerator { Location ref, vixl::aarch32::Register obj, uint32_t offset, - Location temp, + Location maybe_temp, bool needs_null_check); // Fast path implementation of ReadBarrier::Barrier for a heap // reference array load when Baker's read barriers are used. diff --git a/compiler/optimizing/intrinsics.cc b/compiler/optimizing/intrinsics.cc index 1663ee91b4..10d0b8992c 100644 --- a/compiler/optimizing/intrinsics.cc +++ b/compiler/optimizing/intrinsics.cc @@ -146,6 +146,22 @@ static bool CheckIntegerCache(Thread* self, return true; } +static bool CanReferenceBootImageObjects(HInvoke* invoke, const CompilerOptions& compiler_options) { + // Piggyback on the method load kind to determine whether we can use PC-relative addressing + // for AOT. This should cover both the testing config (non-PIC boot image) and codegens that + // reject PC-relative load kinds and fall back to the runtime call. + if (compiler_options.IsAotCompiler() && + !invoke->AsInvokeStaticOrDirect()->HasPcRelativeMethodLoadKind()) { + return false; + } + if (!compiler_options.IsBootImage() && + Runtime::Current()->GetHeap()->GetBootImageSpaces().empty()) { + DCHECK(compiler_options.IsJitCompiler()); + return false; // Running without boot image, cannot use required boot image objects. + } + return true; +} + void IntrinsicVisitor::ComputeIntegerValueOfLocations(HInvoke* invoke, CodeGenerator* codegen, Location return_location, @@ -153,11 +169,7 @@ void IntrinsicVisitor::ComputeIntegerValueOfLocations(HInvoke* invoke, // The intrinsic will call if it needs to allocate a j.l.Integer. LocationSummary::CallKind call_kind = LocationSummary::kCallOnMainOnly; const CompilerOptions& compiler_options = codegen->GetCompilerOptions(); - // Piggyback on the method load kind to determine whether we can use PC-relative addressing - // for AOT. This should cover both the testing config (non-PIC boot image) and codegens that - // reject PC-relative load kinds and fall back to the runtime call. - if (compiler_options.IsAotCompiler() && - !invoke->AsInvokeStaticOrDirect()->HasPcRelativeMethodLoadKind()) { + if (!CanReferenceBootImageObjects(invoke, compiler_options)) { return; } if (compiler_options.IsBootImage()) { @@ -206,9 +218,6 @@ void IntrinsicVisitor::ComputeIntegerValueOfLocations(HInvoke* invoke, } } else { Runtime* runtime = Runtime::Current(); - if (runtime->GetHeap()->GetBootImageSpaces().empty()) { - return; // Running without boot image, cannot use required boot image objects. - } Thread* self = Thread::Current(); ScopedObjectAccess soa(self); ObjPtr<mirror::ObjectArray<mirror::Object>> boot_image_live_objects = GetBootImageLiveObjects(); @@ -244,7 +253,7 @@ void IntrinsicVisitor::ComputeIntegerValueOfLocations(HInvoke* invoke, } } - ArenaAllocator* allocator = invoke->GetBlock()->GetGraph()->GetAllocator(); + ArenaAllocator* allocator = codegen->GetGraph()->GetAllocator(); LocationSummary* locations = new (allocator) LocationSummary(invoke, call_kind, kIntrinsified); if (call_kind == LocationSummary::kCallOnMainOnly) { locations->SetInAt(0, Location::RegisterOrConstant(invoke->InputAt(0))); @@ -354,10 +363,39 @@ IntrinsicVisitor::IntegerValueOfInfo IntrinsicVisitor::ComputeIntegerValueOfInfo return info; } +MemberOffset IntrinsicVisitor::GetReferenceDisableIntrinsicOffset() { + ScopedObjectAccess soa(Thread::Current()); + // The "disableIntrinsic" is the first static field. + ArtField* field = GetClassRoot<mirror::Reference>()->GetStaticField(0); + DCHECK_STREQ(field->GetName(), "disableIntrinsic"); + return field->GetOffset(); +} + +MemberOffset IntrinsicVisitor::GetReferenceSlowPathEnabledOffset() { + ScopedObjectAccess soa(Thread::Current()); + // The "slowPathEnabled" is the second static field. + ArtField* field = GetClassRoot<mirror::Reference>()->GetStaticField(1); + DCHECK_STREQ(field->GetName(), "slowPathEnabled"); + return field->GetOffset(); +} + +void IntrinsicVisitor::CreateReferenceGetReferentLocations(HInvoke* invoke, + CodeGenerator* codegen) { + if (!CanReferenceBootImageObjects(invoke, codegen->GetCompilerOptions())) { + return; + } + + ArenaAllocator* allocator = codegen->GetGraph()->GetAllocator(); + LocationSummary* locations = + new (allocator) LocationSummary(invoke, LocationSummary::kCallOnSlowPath, kIntrinsified); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetOut(Location::RequiresRegister()); +} + void IntrinsicVisitor::AssertNonMovableStringClass() { if (kIsDebugBuild) { ScopedObjectAccess soa(Thread::Current()); - ObjPtr<mirror::Class> string_class = GetClassRoot<art::mirror::String>(); + ObjPtr<mirror::Class> string_class = GetClassRoot<mirror::String>(); CHECK(!art::Runtime::Current()->GetHeap()->IsMovableObject(string_class)); } } diff --git a/compiler/optimizing/intrinsics.h b/compiler/optimizing/intrinsics.h index cc26e41067..a0f9420d95 100644 --- a/compiler/optimizing/intrinsics.h +++ b/compiler/optimizing/intrinsics.h @@ -136,6 +136,10 @@ class IntrinsicVisitor : public ValueObject { static IntegerValueOfInfo ComputeIntegerValueOfInfo( HInvoke* invoke, const CompilerOptions& compiler_options); + static MemberOffset GetReferenceDisableIntrinsicOffset(); + static MemberOffset GetReferenceSlowPathEnabledOffset(); + static void CreateReferenceGetReferentLocations(HInvoke* invoke, CodeGenerator* codegen); + protected: IntrinsicVisitor() {} diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc index a7d5b31820..1c8c5e11e4 100644 --- a/compiler/optimizing/intrinsics_arm64.cc +++ b/compiler/optimizing/intrinsics_arm64.cc @@ -2873,6 +2873,66 @@ void IntrinsicCodeGeneratorARM64::VisitIntegerValueOf(HInvoke* invoke) { } } +void IntrinsicLocationsBuilderARM64::VisitReferenceGetReferent(HInvoke* invoke) { + IntrinsicVisitor::CreateReferenceGetReferentLocations(invoke, codegen_); + + if (kEmitCompilerReadBarrier && kUseBakerReadBarrier && invoke->GetLocations() != nullptr) { + invoke->GetLocations()->AddTemp(Location::RequiresRegister()); + } +} + +void IntrinsicCodeGeneratorARM64::VisitReferenceGetReferent(HInvoke* invoke) { + MacroAssembler* masm = GetVIXLAssembler(); + LocationSummary* locations = invoke->GetLocations(); + + Location obj = locations->InAt(0); + Location out = locations->Out(); + + SlowPathCodeARM64* slow_path = new (GetAllocator()) IntrinsicSlowPathARM64(invoke); + codegen_->AddSlowPath(slow_path); + + if (kEmitCompilerReadBarrier) { + // Check self->GetWeakRefAccessEnabled(). + UseScratchRegisterScope temps(masm); + Register temp = temps.AcquireW(); + __ Ldr(temp, + MemOperand(tr, Thread::WeakRefAccessEnabledOffset<kArm64PointerSize>().Uint32Value())); + __ Cbz(temp, slow_path->GetEntryLabel()); + } + + { + // Load the java.lang.ref.Reference class. + UseScratchRegisterScope temps(masm); + Register temp = temps.AcquireW(); + codegen_->LoadIntrinsicDeclaringClass(temp, invoke); + + // Check static fields java.lang.ref.Reference.{disableIntrinsic,slowPathEnabled} together. + MemberOffset disable_intrinsic_offset = IntrinsicVisitor::GetReferenceDisableIntrinsicOffset(); + DCHECK_ALIGNED(disable_intrinsic_offset.Uint32Value(), 2u); + DCHECK_EQ(disable_intrinsic_offset.Uint32Value() + 1u, + IntrinsicVisitor::GetReferenceSlowPathEnabledOffset().Uint32Value()); + __ Ldrh(temp, HeapOperand(temp, disable_intrinsic_offset.Uint32Value())); + __ Cbnz(temp, slow_path->GetEntryLabel()); + } + + // Load the value from the field. + uint32_t referent_offset = mirror::Reference::ReferentOffset().Uint32Value(); + if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) { + codegen_->GenerateFieldLoadWithBakerReadBarrier(invoke, + out, + WRegisterFrom(obj), + referent_offset, + /*maybe_temp=*/ locations->GetTemp(0), + /*needs_null_check=*/ true, + /*use_load_acquire=*/ true); + } else { + MemOperand field = HeapOperand(WRegisterFrom(obj), referent_offset); + codegen_->LoadAcquire(invoke, WRegisterFrom(out), field, /*needs_null_check=*/ true); + codegen_->MaybeGenerateReadBarrierSlow(invoke, out, out, obj, referent_offset); + } + __ Bind(slow_path->GetExitLabel()); +} + void IntrinsicLocationsBuilderARM64::VisitThreadInterrupted(HInvoke* invoke) { LocationSummary* locations = new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified); @@ -3828,8 +3888,6 @@ void IntrinsicCodeGeneratorARM64::VisitVarHandleSetVolatile(HInvoke* invoke) { GenerateVarHandleSet(invoke, codegen_, /*use_store_release=*/ true); } -UNIMPLEMENTED_INTRINSIC(ARM64, ReferenceGetReferent) - UNIMPLEMENTED_INTRINSIC(ARM64, StringStringIndexOf); UNIMPLEMENTED_INTRINSIC(ARM64, StringStringIndexOfAfter); UNIMPLEMENTED_INTRINSIC(ARM64, StringBufferAppend); diff --git a/compiler/optimizing/intrinsics_arm_vixl.cc b/compiler/optimizing/intrinsics_arm_vixl.cc index 2901c472bc..f629ad3c51 100644 --- a/compiler/optimizing/intrinsics_arm_vixl.cc +++ b/compiler/optimizing/intrinsics_arm_vixl.cc @@ -2991,6 +2991,68 @@ void IntrinsicCodeGeneratorARMVIXL::VisitIntegerValueOf(HInvoke* invoke) { } } +void IntrinsicLocationsBuilderARMVIXL::VisitReferenceGetReferent(HInvoke* invoke) { + IntrinsicVisitor::CreateReferenceGetReferentLocations(invoke, codegen_); +} + +void IntrinsicCodeGeneratorARMVIXL::VisitReferenceGetReferent(HInvoke* invoke) { + ArmVIXLAssembler* assembler = GetAssembler(); + LocationSummary* locations = invoke->GetLocations(); + + Location obj = locations->InAt(0); + Location out = locations->Out(); + + SlowPathCodeARMVIXL* slow_path = new (GetAllocator()) IntrinsicSlowPathARMVIXL(invoke); + codegen_->AddSlowPath(slow_path); + + if (kEmitCompilerReadBarrier) { + // Check self->GetWeakRefAccessEnabled(). + UseScratchRegisterScope temps(assembler->GetVIXLAssembler()); + vixl32::Register temp = temps.Acquire(); + __ Ldr(temp, + MemOperand(tr, Thread::WeakRefAccessEnabledOffset<kArmPointerSize>().Uint32Value())); + __ Cmp(temp, 0); + __ B(eq, slow_path->GetEntryLabel()); + } + + { + // Load the java.lang.ref.Reference class. + UseScratchRegisterScope temps(assembler->GetVIXLAssembler()); + vixl32::Register temp = temps.Acquire(); + codegen_->LoadIntrinsicDeclaringClass(temp, invoke); + + // Check static fields java.lang.ref.Reference.{disableIntrinsic,slowPathEnabled} together. + MemberOffset disable_intrinsic_offset = IntrinsicVisitor::GetReferenceDisableIntrinsicOffset(); + DCHECK_ALIGNED(disable_intrinsic_offset.Uint32Value(), 2u); + DCHECK_EQ(disable_intrinsic_offset.Uint32Value() + 1u, + IntrinsicVisitor::GetReferenceSlowPathEnabledOffset().Uint32Value()); + __ Ldrh(temp, MemOperand(temp, disable_intrinsic_offset.Uint32Value())); + __ Cmp(temp, 0); + __ B(ne, slow_path->GetEntryLabel()); + } + + // Load the value from the field. + uint32_t referent_offset = mirror::Reference::ReferentOffset().Uint32Value(); + if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) { + codegen_->GenerateFieldLoadWithBakerReadBarrier(invoke, + out, + RegisterFrom(obj), + referent_offset, + /*maybe_temp=*/ Location::NoLocation(), + /*needs_null_check=*/ true); + codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny); // `referent` is volatile. + } else { + { + vixl::EmissionCheckScope guard(codegen_->GetVIXLAssembler(), kMaxMacroInstructionSizeInBytes); + __ Ldr(RegisterFrom(out), MemOperand(RegisterFrom(obj), referent_offset)); + codegen_->MaybeRecordImplicitNullCheck(invoke); + } + codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny); // `referent` is volatile. + codegen_->MaybeGenerateReadBarrierSlow(invoke, out, out, obj, referent_offset); + } + __ Bind(slow_path->GetExitLabel()); +} + void IntrinsicLocationsBuilderARMVIXL::VisitThreadInterrupted(HInvoke* invoke) { LocationSummary* locations = new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified); @@ -3049,7 +3111,6 @@ void IntrinsicCodeGeneratorARMVIXL::VisitIntegerDivideUnsigned(HInvoke* invoke) UNIMPLEMENTED_INTRINSIC(ARMVIXL, MathRoundDouble) // Could be done by changing rounding mode, maybe? UNIMPLEMENTED_INTRINSIC(ARMVIXL, UnsafeCASLong) // High register pressure. UNIMPLEMENTED_INTRINSIC(ARMVIXL, SystemArrayCopyChar) -UNIMPLEMENTED_INTRINSIC(ARMVIXL, ReferenceGetReferent) UNIMPLEMENTED_INTRINSIC(ARMVIXL, LongDivideUnsigned) UNIMPLEMENTED_INTRINSIC(ARMVIXL, CRC32Update) UNIMPLEMENTED_INTRINSIC(ARMVIXL, CRC32UpdateBytes) diff --git a/compiler/optimizing/intrinsics_x86.cc b/compiler/optimizing/intrinsics_x86.cc index 4095259f38..cd41e1a13b 100644 --- a/compiler/optimizing/intrinsics_x86.cc +++ b/compiler/optimizing/intrinsics_x86.cc @@ -3014,6 +3014,21 @@ void IntrinsicCodeGeneratorX86::VisitSystemArrayCopy(HInvoke* invoke) { __ Bind(intrinsic_slow_path->GetExitLabel()); } +static void RequestBaseMethodAddressInRegister(HInvoke* invoke) { + LocationSummary* locations = invoke->GetLocations(); + if (locations != nullptr) { + HInvokeStaticOrDirect* invoke_static_or_direct = invoke->AsInvokeStaticOrDirect(); + // Note: The base method address is not present yet when this is called from the + // PCRelativeHandlerVisitor via IsCallFreeIntrinsic() to determine whether to insert it. + if (invoke_static_or_direct->HasSpecialInput()) { + DCHECK(invoke_static_or_direct->InputAt(invoke_static_or_direct->GetSpecialInputIndex()) + ->IsX86ComputeBaseMethodAddress()); + locations->SetInAt(invoke_static_or_direct->GetSpecialInputIndex(), + Location::RequiresRegister()); + } + } +} + void IntrinsicLocationsBuilderX86::VisitIntegerValueOf(HInvoke* invoke) { DCHECK(invoke->IsInvokeStaticOrDirect()); InvokeRuntimeCallingConvention calling_convention; @@ -3022,17 +3037,7 @@ void IntrinsicLocationsBuilderX86::VisitIntegerValueOf(HInvoke* invoke) { codegen_, Location::RegisterLocation(EAX), Location::RegisterLocation(calling_convention.GetRegisterAt(0))); - - LocationSummary* locations = invoke->GetLocations(); - if (locations != nullptr) { - HInvokeStaticOrDirect* invoke_static_or_direct = invoke->AsInvokeStaticOrDirect(); - if (invoke_static_or_direct->HasSpecialInput() && - invoke->InputAt(invoke_static_or_direct->GetSpecialInputIndex()) - ->IsX86ComputeBaseMethodAddress()) { - locations->SetInAt(invoke_static_or_direct->GetSpecialInputIndex(), - Location::RequiresRegister()); - } - } + RequestBaseMethodAddressInRegister(invoke); } void IntrinsicCodeGeneratorX86::VisitIntegerValueOf(HInvoke* invoke) { @@ -3107,6 +3112,61 @@ void IntrinsicCodeGeneratorX86::VisitIntegerValueOf(HInvoke* invoke) { } } +void IntrinsicLocationsBuilderX86::VisitReferenceGetReferent(HInvoke* invoke) { + IntrinsicVisitor::CreateReferenceGetReferentLocations(invoke, codegen_); + RequestBaseMethodAddressInRegister(invoke); +} + +void IntrinsicCodeGeneratorX86::VisitReferenceGetReferent(HInvoke* invoke) { + X86Assembler* assembler = GetAssembler(); + LocationSummary* locations = invoke->GetLocations(); + + Location obj = locations->InAt(0); + Location out = locations->Out(); + + SlowPathCode* slow_path = new (GetAllocator()) IntrinsicSlowPathX86(invoke); + codegen_->AddSlowPath(slow_path); + + if (kEmitCompilerReadBarrier) { + // Check self->GetWeakRefAccessEnabled(). + ThreadOffset32 offset = Thread::WeakRefAccessEnabledOffset<kX86PointerSize>(); + __ fs()->cmpl(Address::Absolute(offset), Immediate(0)); + __ j(kEqual, slow_path->GetEntryLabel()); + } + + // Load the java.lang.ref.Reference class, use the output register as a temporary. + codegen_->LoadIntrinsicDeclaringClass(out.AsRegister<Register>(), + invoke->AsInvokeStaticOrDirect()); + + // Check static fields java.lang.ref.Reference.{disableIntrinsic,slowPathEnabled} together. + MemberOffset disable_intrinsic_offset = IntrinsicVisitor::GetReferenceDisableIntrinsicOffset(); + DCHECK_ALIGNED(disable_intrinsic_offset.Uint32Value(), 2u); + DCHECK_EQ(disable_intrinsic_offset.Uint32Value() + 1u, + IntrinsicVisitor::GetReferenceSlowPathEnabledOffset().Uint32Value()); + __ cmpw(Address(out.AsRegister<Register>(), disable_intrinsic_offset.Uint32Value()), + Immediate(0)); + __ j(kNotEqual, slow_path->GetEntryLabel()); + + // Load the value from the field. + uint32_t referent_offset = mirror::Reference::ReferentOffset().Uint32Value(); + if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) { + codegen_->GenerateFieldLoadWithBakerReadBarrier(invoke, + out, + obj.AsRegister<Register>(), + referent_offset, + /*needs_null_check=*/ true); + // Note that the fence is a no-op, thanks to the x86 memory model. + codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny); // `referent` is volatile. + } else { + __ movl(out.AsRegister<Register>(), Address(obj.AsRegister<Register>(), referent_offset)); + codegen_->MaybeRecordImplicitNullCheck(invoke); + // Note that the fence is a no-op, thanks to the x86 memory model. + codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny); // `referent` is volatile. + codegen_->MaybeGenerateReadBarrierSlow(invoke, out, out, obj, referent_offset); + } + __ Bind(slow_path->GetExitLabel()); +} + void IntrinsicLocationsBuilderX86::VisitThreadInterrupted(HInvoke* invoke) { LocationSummary* locations = new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified); @@ -4499,7 +4559,6 @@ void IntrinsicCodeGeneratorX86::VisitVarHandleGetAndBitwiseAndRelease(HInvoke* i } UNIMPLEMENTED_INTRINSIC(X86, MathRoundDouble) -UNIMPLEMENTED_INTRINSIC(X86, ReferenceGetReferent) UNIMPLEMENTED_INTRINSIC(X86, FloatIsInfinite) UNIMPLEMENTED_INTRINSIC(X86, DoubleIsInfinite) UNIMPLEMENTED_INTRINSIC(X86, IntegerHighestOneBit) diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc index 985f09590c..c22fdd9092 100644 --- a/compiler/optimizing/intrinsics_x86_64.cc +++ b/compiler/optimizing/intrinsics_x86_64.cc @@ -2659,6 +2659,59 @@ void IntrinsicCodeGeneratorX86_64::VisitIntegerValueOf(HInvoke* invoke) { } } +void IntrinsicLocationsBuilderX86_64::VisitReferenceGetReferent(HInvoke* invoke) { + IntrinsicVisitor::CreateReferenceGetReferentLocations(invoke, codegen_); +} + +void IntrinsicCodeGeneratorX86_64::VisitReferenceGetReferent(HInvoke* invoke) { + X86_64Assembler* assembler = GetAssembler(); + LocationSummary* locations = invoke->GetLocations(); + + Location obj = locations->InAt(0); + Location out = locations->Out(); + + SlowPathCode* slow_path = new (GetAllocator()) IntrinsicSlowPathX86_64(invoke); + codegen_->AddSlowPath(slow_path); + + if (kEmitCompilerReadBarrier) { + // Check self->GetWeakRefAccessEnabled(). + ThreadOffset64 offset = Thread::WeakRefAccessEnabledOffset<kX86_64PointerSize>(); + __ gs()->cmpl(Address::Absolute(offset, /* no_rip= */ true), Immediate(0)); + __ j(kEqual, slow_path->GetEntryLabel()); + } + + // Load the java.lang.ref.Reference class, use the output register as a temporary. + codegen_->LoadIntrinsicDeclaringClass(out.AsRegister<CpuRegister>(), invoke); + + // Check static fields java.lang.ref.Reference.{disableIntrinsic,slowPathEnabled} together. + MemberOffset disable_intrinsic_offset = IntrinsicVisitor::GetReferenceDisableIntrinsicOffset(); + DCHECK_ALIGNED(disable_intrinsic_offset.Uint32Value(), 2u); + DCHECK_EQ(disable_intrinsic_offset.Uint32Value() + 1u, + IntrinsicVisitor::GetReferenceSlowPathEnabledOffset().Uint32Value()); + __ cmpw(Address(out.AsRegister<CpuRegister>(), disable_intrinsic_offset.Uint32Value()), + Immediate(0)); + __ j(kNotEqual, slow_path->GetEntryLabel()); + + // Load the value from the field. + uint32_t referent_offset = mirror::Reference::ReferentOffset().Uint32Value(); + if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) { + codegen_->GenerateFieldLoadWithBakerReadBarrier(invoke, + out, + obj.AsRegister<CpuRegister>(), + referent_offset, + /*needs_null_check=*/ true); + // Note that the fence is a no-op, thanks to the x86-64 memory model. + codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny); // `referent` is volatile. + } else { + __ movl(out.AsRegister<CpuRegister>(), Address(obj.AsRegister<CpuRegister>(), referent_offset)); + codegen_->MaybeRecordImplicitNullCheck(invoke); + // Note that the fence is a no-op, thanks to the x86-64 memory model. + codegen_->GenerateMemoryBarrier(MemBarrierKind::kLoadAny); // `referent` is volatile. + codegen_->MaybeGenerateReadBarrierSlow(invoke, out, out, obj, referent_offset); + } + __ Bind(slow_path->GetExitLabel()); +} + void IntrinsicLocationsBuilderX86_64::VisitThreadInterrupted(HInvoke* invoke) { LocationSummary* locations = new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified); @@ -2723,7 +2776,6 @@ void IntrinsicCodeGeneratorX86_64::VisitIntegerDivideUnsigned(HInvoke* invoke) { } -UNIMPLEMENTED_INTRINSIC(X86_64, ReferenceGetReferent) UNIMPLEMENTED_INTRINSIC(X86_64, FloatIsInfinite) UNIMPLEMENTED_INTRINSIC(X86_64, DoubleIsInfinite) UNIMPLEMENTED_INTRINSIC(X86_64, CRC32Update) diff --git a/runtime/thread.h b/runtime/thread.h index 8cd16c3be7..b23f6470eb 100644 --- a/runtime/thread.h +++ b/runtime/thread.h @@ -689,6 +689,13 @@ class Thread { } template<PointerSize pointer_size> + static constexpr ThreadOffset<pointer_size> WeakRefAccessEnabledOffset() { + return ThreadOffset<pointer_size>( + OFFSETOF_MEMBER(Thread, tls32_) + + OFFSETOF_MEMBER(tls_32bit_sized_values, weak_ref_access_enabled)); + } + + template<PointerSize pointer_size> static constexpr ThreadOffset<pointer_size> ThreadFlagsOffset() { return ThreadOffset<pointer_size>( OFFSETOF_MEMBER(Thread, tls32_) + |