From d8c052ac0aa3382c4807add33afa32580ffeecbb Mon Sep 17 00:00:00 2001 From: TatWai Chong Date: Wed, 2 Nov 2016 16:12:48 +0800 Subject: [PATCH] ART: Reference.getReferent intrinsic for arm and arm64 Test: m test-art-host Test: m test-art-target Test: export ART_HEAP_POISONING=true; m test-art-host Test: export ART_HEAP_POISONING=true; m test-art-target Bug: 32535355 Change-Id: Ie63317689dd9e03a24e701c30411f8014970173a --- compiler/optimizing/code_generator_arm.cc | 11 +++-- compiler/optimizing/code_generator_arm.h | 1 + compiler/optimizing/code_generator_arm64.cc | 9 +++- compiler/optimizing/code_generator_arm64.h | 1 + compiler/optimizing/code_generator_arm_vixl.cc | 8 +++- compiler/optimizing/code_generator_arm_vixl.h | 1 + compiler/optimizing/intrinsics_arm.cc | 53 ++++++++++++++++++++++- compiler/optimizing/intrinsics_arm64.cc | 60 +++++++++++++++++++++++++- compiler/optimizing/intrinsics_arm_vixl.cc | 55 ++++++++++++++++++++++- 9 files changed, 191 insertions(+), 8 deletions(-) diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index 8a7f6d3a3..e469b1d27 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -7166,8 +7166,7 @@ Register CodeGeneratorARM::GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOr // save one load. However, since this is just an intrinsic slow path we prefer this // simple and more robust approach rather that trying to determine if that's the case. SlowPathCode* slow_path = GetCurrentSlowPath(); - DCHECK(slow_path != nullptr); // For intrinsified invokes the call is emitted on the slow path. - if (slow_path->IsCoreRegisterSaved(location.AsRegister())) { + if (slow_path != nullptr && slow_path->IsCoreRegisterSaved(location.AsRegister())) { int stack_offset = slow_path->GetStackOffsetOfCoreRegister(location.AsRegister()); __ LoadFromOffset(kLoadWord, temp, SP, stack_offset); return temp; @@ -7175,7 +7174,8 @@ Register CodeGeneratorARM::GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOr return location.AsRegister(); } -void CodeGeneratorARM::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) { +Location CodeGeneratorARM::GenerateCalleeMethodStaticOrDirectCall(HInvokeStaticOrDirect* invoke, + Location temp) { Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp. switch (invoke->GetMethodLoadKind()) { case HInvokeStaticOrDirect::MethodLoadKind::kStringInit: { @@ -7224,6 +7224,11 @@ void CodeGeneratorARM::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, break; } } + return callee_method; +} + +void CodeGeneratorARM::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) { + Location callee_method = GenerateCalleeMethodStaticOrDirectCall(invoke, temp); switch (invoke->GetCodePtrLocation()) { case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf: diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h index 643585132..0376f0394 100644 --- a/compiler/optimizing/code_generator_arm.h +++ b/compiler/optimizing/code_generator_arm.h @@ -456,6 +456,7 @@ class CodeGeneratorARM : public CodeGenerator { const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info, HInvokeStaticOrDirect* invoke) OVERRIDE; + Location GenerateCalleeMethodStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp); void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) OVERRIDE; void GenerateVirtualCall(HInvokeVirtual* invoke, Location temp) OVERRIDE; diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc index 5c33fe1a7..0fdfeaf4f 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -3974,7 +3974,8 @@ HInvokeStaticOrDirect::DispatchInfo CodeGeneratorARM64::GetSupportedInvokeStatic return desired_dispatch_info; } -void CodeGeneratorARM64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) { +Location CodeGeneratorARM64::GenerateCalleeMethodStaticOrDirectCall(HInvokeStaticOrDirect* invoke, + Location temp) { // Make sure that ArtMethod* is passed in kArtMethodRegister as per the calling convention. Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp. switch (invoke->GetMethodLoadKind()) { @@ -4028,6 +4029,12 @@ void CodeGeneratorARM64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invok break; } } + return callee_method; +} + +void CodeGeneratorARM64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) { + // All registers are assumed to be correctly set up. + Location callee_method = GenerateCalleeMethodStaticOrDirectCall(invoke, temp); switch (invoke->GetCodePtrLocation()) { case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf: diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h index 8f33b6bec..69b1be4ac 100644 --- a/compiler/optimizing/code_generator_arm64.h +++ b/compiler/optimizing/code_generator_arm64.h @@ -527,6 +527,7 @@ class CodeGeneratorARM64 : public CodeGenerator { const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info, HInvokeStaticOrDirect* invoke) OVERRIDE; + Location GenerateCalleeMethodStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp); void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) OVERRIDE; void GenerateVirtualCall(HInvokeVirtual* invoke, Location temp) OVERRIDE; diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc index 00ad3e34b..9f2720e46 100644 --- a/compiler/optimizing/code_generator_arm_vixl.cc +++ b/compiler/optimizing/code_generator_arm_vixl.cc @@ -7269,7 +7269,7 @@ vixl32::Register CodeGeneratorARMVIXL::GetInvokeStaticOrDirectExtraParameter( return RegisterFrom(location); } -void CodeGeneratorARMVIXL::GenerateStaticOrDirectCall( +Location CodeGeneratorARMVIXL::GenerateCalleeMethodStaticOrDirectCall( HInvokeStaticOrDirect* invoke, Location temp) { Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp. switch (invoke->GetMethodLoadKind()) { @@ -7320,6 +7320,12 @@ void CodeGeneratorARMVIXL::GenerateStaticOrDirectCall( break; } } + return callee_method; +} + +void CodeGeneratorARMVIXL::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, + Location temp) { + Location callee_method = GenerateCalleeMethodStaticOrDirectCall(invoke, temp); switch (invoke->GetCodePtrLocation()) { case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf: diff --git a/compiler/optimizing/code_generator_arm_vixl.h b/compiler/optimizing/code_generator_arm_vixl.h index 297d63cef..abeadd5d1 100644 --- a/compiler/optimizing/code_generator_arm_vixl.h +++ b/compiler/optimizing/code_generator_arm_vixl.h @@ -537,6 +537,7 @@ class CodeGeneratorARMVIXL : public CodeGenerator { const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info, HInvokeStaticOrDirect* invoke) OVERRIDE; + Location GenerateCalleeMethodStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp); void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) OVERRIDE; void GenerateVirtualCall(HInvokeVirtual* invoke, Location temp) OVERRIDE; diff --git a/compiler/optimizing/intrinsics_arm.cc b/compiler/optimizing/intrinsics_arm.cc index 8f64faeac..c262cf983 100644 --- a/compiler/optimizing/intrinsics_arm.cc +++ b/compiler/optimizing/intrinsics_arm.cc @@ -2592,6 +2592,58 @@ void IntrinsicCodeGeneratorARM::VisitDoubleIsInfinite(HInvoke* invoke) { __ Lsr(out, out, 5); } +void IntrinsicLocationsBuilderARM::VisitReferenceGetReferent(HInvoke* invoke) { + if (kEmitCompilerReadBarrier) { + // Do not intrinsify this call with the read barrier configuration. + return; + } + LocationSummary* locations = new (arena_) LocationSummary(invoke, + LocationSummary::kCallOnSlowPath, + kIntrinsified); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetOut(Location::SameAsFirstInput()); + locations->AddTemp(Location::RequiresRegister()); +} + +void IntrinsicCodeGeneratorARM::VisitReferenceGetReferent(HInvoke* invoke) { + DCHECK(!kEmitCompilerReadBarrier); + ArmAssembler* const assembler = GetAssembler(); + LocationSummary* locations = invoke->GetLocations(); + + Register obj = locations->InAt(0).AsRegister(); + Register out = locations->Out().AsRegister(); + + SlowPathCode* slow_path = new (GetAllocator()) IntrinsicSlowPathARM(invoke); + codegen_->AddSlowPath(slow_path); + + // Load ArtMethod first. + HInvokeStaticOrDirect* invoke_direct = invoke->AsInvokeStaticOrDirect(); + DCHECK(invoke_direct != nullptr); + Register temp = codegen_->GenerateCalleeMethodStaticOrDirectCall( + invoke_direct, locations->GetTemp(0)).AsRegister(); + + // Now get declaring class. + __ ldr(temp, Address(temp, ArtMethod::DeclaringClassOffset().Int32Value())); + + uint32_t slow_path_flag_offset = codegen_->GetReferenceSlowFlagOffset(); + uint32_t disable_flag_offset = codegen_->GetReferenceDisableFlagOffset(); + DCHECK_NE(slow_path_flag_offset, 0u); + DCHECK_NE(disable_flag_offset, 0u); + DCHECK_NE(slow_path_flag_offset, disable_flag_offset); + + // Check static flags that prevent using intrinsic. + __ ldr(IP, Address(temp, disable_flag_offset)); + __ ldr(temp, Address(temp, slow_path_flag_offset)); + __ orr(IP, IP, ShifterOperand(temp)); + __ CompareAndBranchIfNonZero(IP, slow_path->GetEntryLabel()); + + // Fast path. + __ ldr(out, Address(obj, mirror::Reference::ReferentOffset().Int32Value())); + codegen_->MaybeRecordImplicitNullCheck(invoke); + __ MaybeUnpoisonHeapReference(out); + __ Bind(slow_path->GetExitLabel()); +} + UNIMPLEMENTED_INTRINSIC(ARM, MathMinDoubleDouble) UNIMPLEMENTED_INTRINSIC(ARM, MathMinFloatFloat) UNIMPLEMENTED_INTRINSIC(ARM, MathMaxDoubleDouble) @@ -2605,7 +2657,6 @@ UNIMPLEMENTED_INTRINSIC(ARM, MathRoundDouble) // Could be done by changing rou UNIMPLEMENTED_INTRINSIC(ARM, MathRoundFloat) // Could be done by changing rounding mode, maybe? UNIMPLEMENTED_INTRINSIC(ARM, UnsafeCASLong) // High register pressure. UNIMPLEMENTED_INTRINSIC(ARM, SystemArrayCopyChar) -UNIMPLEMENTED_INTRINSIC(ARM, ReferenceGetReferent) UNIMPLEMENTED_INTRINSIC(ARM, IntegerHighestOneBit) UNIMPLEMENTED_INTRINSIC(ARM, LongHighestOneBit) UNIMPLEMENTED_INTRINSIC(ARM, IntegerLowestOneBit) diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc index d8a896e92..bbf826ce7 100644 --- a/compiler/optimizing/intrinsics_arm64.cc +++ b/compiler/optimizing/intrinsics_arm64.cc @@ -2773,7 +2773,65 @@ void IntrinsicCodeGeneratorARM64::VisitDoubleIsInfinite(HInvoke* invoke) { GenIsInfinite(invoke->GetLocations(), /* is64bit */ true, GetVIXLAssembler()); } -UNIMPLEMENTED_INTRINSIC(ARM64, ReferenceGetReferent) +void IntrinsicLocationsBuilderARM64::VisitReferenceGetReferent(HInvoke* invoke) { + if (kEmitCompilerReadBarrier) { + // Do not intrinsify this call with the read barrier configuration. + return; + } + LocationSummary* locations = new (arena_) LocationSummary(invoke, + LocationSummary::kCallOnSlowPath, + kIntrinsified); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetOut(Location::SameAsFirstInput()); + locations->AddTemp(Location::RequiresRegister()); +} + +void IntrinsicCodeGeneratorARM64::VisitReferenceGetReferent(HInvoke* invoke) { + DCHECK(!kEmitCompilerReadBarrier); + MacroAssembler* masm = GetVIXLAssembler(); + LocationSummary* locations = invoke->GetLocations(); + + Register obj = InputRegisterAt(invoke, 0); + Register out = OutputRegister(invoke); + + SlowPathCodeARM64* slow_path = new (GetAllocator()) IntrinsicSlowPathARM64(invoke); + codegen_->AddSlowPath(slow_path); + + // Load ArtMethod first. + HInvokeStaticOrDirect* invoke_direct = invoke->AsInvokeStaticOrDirect(); + DCHECK(invoke_direct != nullptr); + Register temp0 = XRegisterFrom(codegen_->GenerateCalleeMethodStaticOrDirectCall( + invoke_direct, locations->GetTemp(0))); + + // Now get declaring class. + __ Ldr(temp0.W(), MemOperand(temp0, ArtMethod::DeclaringClassOffset().Int32Value())); + + uint32_t slow_path_flag_offset = codegen_->GetReferenceSlowFlagOffset(); + uint32_t disable_flag_offset = codegen_->GetReferenceDisableFlagOffset(); + DCHECK_NE(slow_path_flag_offset, 0u); + DCHECK_NE(disable_flag_offset, 0u); + DCHECK_NE(slow_path_flag_offset, disable_flag_offset); + + // Check static flags that prevent using intrinsic. + if (slow_path_flag_offset == disable_flag_offset + 1) { + // Load two adjacent flags in one 64-bit load. + __ Ldr(temp0, MemOperand(temp0, disable_flag_offset)); + } else { + UseScratchRegisterScope temps(masm); + Register temp1 = temps.AcquireW(); + __ Ldr(temp1.W(), MemOperand(temp0, disable_flag_offset)); + __ Ldr(temp0.W(), MemOperand(temp0, slow_path_flag_offset)); + __ Orr(temp0, temp1, temp0); + } + __ Cbnz(temp0, slow_path->GetEntryLabel()); + + // Fast path. + __ Ldr(out, HeapOperand(obj, mirror::Reference::ReferentOffset().Int32Value())); + codegen_->MaybeRecordImplicitNullCheck(invoke); + codegen_->GetAssembler()->MaybeUnpoisonHeapReference(out); + __ Bind(slow_path->GetExitLabel()); +} + UNIMPLEMENTED_INTRINSIC(ARM64, IntegerHighestOneBit) UNIMPLEMENTED_INTRINSIC(ARM64, LongHighestOneBit) UNIMPLEMENTED_INTRINSIC(ARM64, IntegerLowestOneBit) diff --git a/compiler/optimizing/intrinsics_arm_vixl.cc b/compiler/optimizing/intrinsics_arm_vixl.cc index 85e84d8d2..68c2d2e36 100644 --- a/compiler/optimizing/intrinsics_arm_vixl.cc +++ b/compiler/optimizing/intrinsics_arm_vixl.cc @@ -2688,6 +2688,60 @@ void IntrinsicCodeGeneratorARMVIXL::VisitDoubleIsInfinite(HInvoke* invoke) { __ Lsr(out, out, 5); } +void IntrinsicLocationsBuilderARMVIXL::VisitReferenceGetReferent(HInvoke* invoke) { + if (kEmitCompilerReadBarrier) { + // Do not intrinsify this call with the read barrier configuration. + return; + } + LocationSummary* locations = new (arena_) LocationSummary(invoke, + LocationSummary::kCallOnSlowPath, + kIntrinsified); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetOut(Location::SameAsFirstInput()); + locations->AddTemp(Location::RequiresRegister()); +} + +void IntrinsicCodeGeneratorARMVIXL::VisitReferenceGetReferent(HInvoke* invoke) { + DCHECK(!kEmitCompilerReadBarrier); + ArmVIXLAssembler* assembler = GetAssembler(); + LocationSummary* locations = invoke->GetLocations(); + + vixl32::Register obj = InputRegisterAt(invoke, 0); + vixl32::Register out = OutputRegister(invoke); + + SlowPathCodeARMVIXL* slow_path = new (GetAllocator()) IntrinsicSlowPathARMVIXL(invoke); + codegen_->AddSlowPath(slow_path); + + // Load ArtMethod first. + HInvokeStaticOrDirect* invoke_direct = invoke->AsInvokeStaticOrDirect(); + DCHECK(invoke_direct != nullptr); + vixl32::Register temp0 = RegisterFrom(codegen_->GenerateCalleeMethodStaticOrDirectCall( + invoke_direct, locations->GetTemp(0))); + + // Now get declaring class. + __ Ldr(temp0, MemOperand(temp0, ArtMethod::DeclaringClassOffset().Int32Value())); + + uint32_t slow_path_flag_offset = codegen_->GetReferenceSlowFlagOffset(); + uint32_t disable_flag_offset = codegen_->GetReferenceDisableFlagOffset(); + DCHECK_NE(slow_path_flag_offset, 0u); + DCHECK_NE(disable_flag_offset, 0u); + DCHECK_NE(slow_path_flag_offset, disable_flag_offset); + + // Check static flags that prevent using intrinsic. + UseScratchRegisterScope temps(assembler->GetVIXLAssembler()); + vixl32::Register temp1 = temps.Acquire(); + __ Ldr(temp1, MemOperand(temp0, disable_flag_offset)); + __ Ldr(temp0, MemOperand(temp0, slow_path_flag_offset)); + __ Orr(temp0, temp1, temp0); + __ CompareAndBranchIfNonZero(temp0, slow_path->GetEntryLabel()); + + // Fast path. + __ Ldr(out, MemOperand(obj, mirror::Reference::ReferentOffset().Int32Value())); + codegen_->MaybeRecordImplicitNullCheck(invoke); + assembler->MaybeUnpoisonHeapReference(out); + __ Bind(slow_path->GetExitLabel()); +} + UNIMPLEMENTED_INTRINSIC(ARMVIXL, MathMinDoubleDouble) UNIMPLEMENTED_INTRINSIC(ARMVIXL, MathMinFloatFloat) UNIMPLEMENTED_INTRINSIC(ARMVIXL, MathMaxDoubleDouble) @@ -2701,7 +2755,6 @@ UNIMPLEMENTED_INTRINSIC(ARMVIXL, MathRoundDouble) // Could be done by changing UNIMPLEMENTED_INTRINSIC(ARMVIXL, MathRoundFloat) // 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, IntegerHighestOneBit) UNIMPLEMENTED_INTRINSIC(ARMVIXL, LongHighestOneBit) UNIMPLEMENTED_INTRINSIC(ARMVIXL, IntegerLowestOneBit) -- 2.11.0