diff options
author | Vladimir Marko <vmarko@google.com> | 2024-04-30 13:05:35 +0000 |
---|---|---|
committer | VladimĂr Marko <vmarko@google.com> | 2024-05-03 12:55:19 +0000 |
commit | 721bbf2bfd6ffe689067df5657059925e038bb0d (patch) | |
tree | 661c70929bc5552a37937a2966c381bd10fc1190 | |
parent | b3d88b3f4b47b7635cbdab54dfdcbf866b9813ff (diff) | |
download | art-721bbf2bfd6ffe689067df5657059925e038bb0d.tar.gz |
riscv64: Fast-path for `HInstanceOf`/`kInterfaceCheck`.
Test: run-gtests.sh
Test: testrunner.py --target --optimizing
Bug: 333690895
Change-Id: I907b240cf65b1e1eb9d1bc24db9020cafa868df0
-rw-r--r-- | compiler/optimizing/code_generator_riscv64.cc | 67 |
1 files changed, 56 insertions, 11 deletions
diff --git a/compiler/optimizing/code_generator_riscv64.cc b/compiler/optimizing/code_generator_riscv64.cc index c870db662c..29594e94c1 100644 --- a/compiler/optimizing/code_generator_riscv64.cc +++ b/compiler/optimizing/code_generator_riscv64.cc @@ -3382,7 +3382,7 @@ TypeCheckKind type_check_kind = instruction->GetTypeCheckKind(); kWithoutReadBarrier); XRegister temp2 = maybe_temp2_loc.AsRegister<XRegister>(); XRegister temp3 = maybe_temp3_loc.AsRegister<XRegister>(); - // Iftable is never null. + // Load the size of the `IfTable`. The `Class::iftable_` is never null. __ Loadw(temp2, temp, array_length_offset); // Loop through the iftable and check if any class matches. Riscv64Label loop; @@ -3841,15 +3841,16 @@ void LocationsBuilderRISCV64::VisitInstanceOf(HInstanceOf* instruction) { case TypeCheckKind::kExactCheck: case TypeCheckKind::kAbstractClassCheck: case TypeCheckKind::kClassHierarchyCheck: - case TypeCheckKind::kArrayObjectCheck: { + case TypeCheckKind::kArrayObjectCheck: + case TypeCheckKind::kInterfaceCheck: { bool needs_read_barrier = codegen_->InstanceOfNeedsReadBarrier(instruction); call_kind = needs_read_barrier ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall; - baker_read_barrier_slow_path = kUseBakerReadBarrier && needs_read_barrier; + baker_read_barrier_slow_path = (kUseBakerReadBarrier && needs_read_barrier) && + (type_check_kind != TypeCheckKind::kInterfaceCheck); break; } case TypeCheckKind::kArrayCheck: case TypeCheckKind::kUnresolvedCheck: - case TypeCheckKind::kInterfaceCheck: call_kind = LocationSummary::kCallOnSlowPath; break; case TypeCheckKind::kBitstringCheck: @@ -3889,10 +3890,14 @@ void InstructionCodeGeneratorRISCV64::VisitInstanceOf(HInstanceOf* instruction) const size_t num_temps = NumberOfInstanceOfTemps(codegen_->EmitReadBarrier(), type_check_kind); DCHECK_LE(num_temps, 1u); Location maybe_temp_loc = (num_temps >= 1) ? locations->GetTemp(0) : Location::NoLocation(); - uint32_t class_offset = mirror::Object::ClassOffset().Int32Value(); - uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value(); - uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value(); - uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value(); + const uint32_t class_offset = mirror::Object::ClassOffset().Int32Value(); + const uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value(); + const uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value(); + const uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value(); + const uint32_t iftable_offset = mirror::Class::IfTableOffset().Uint32Value(); + const uint32_t array_length_offset = mirror::Array::LengthOffset().Uint32Value(); + const uint32_t object_array_data_offset = + mirror::Array::DataOffset(kHeapReferenceSize).Uint32Value(); Riscv64Label done; SlowPathCodeRISCV64* slow_path = nullptr; @@ -3999,11 +4004,51 @@ void InstructionCodeGeneratorRISCV64::VisitInstanceOf(HInstanceOf* instruction) break; } - case TypeCheckKind::kUnresolvedCheck: case TypeCheckKind::kInterfaceCheck: { + if (codegen_->InstanceOfNeedsReadBarrier(instruction)) { + DCHECK(locations->OnlyCallsOnSlowPath()); + slow_path = new (codegen_->GetScopedAllocator()) TypeCheckSlowPathRISCV64( + instruction, /* is_fatal= */ false); + codegen_->AddSlowPath(slow_path); + if (codegen_->EmitNonBakerReadBarrier()) { + __ J(slow_path->GetEntryLabel()); + break; + } + // For Baker read barrier, take the slow path while marking. + __ Loadw(out, TR, Thread::IsGcMarkingOffset<kRiscv64PointerSize>().Int32Value()); + __ Bnez(out, slow_path->GetEntryLabel()); + } + + // Fast-path without read barriers. + ScratchRegisterScope srs(GetAssembler()); + XRegister temp = srs.AllocateXRegister(); + // /* HeapReference<Class> */ temp = obj->klass_ + __ Loadwu(temp, obj, class_offset); + codegen_->MaybeUnpoisonHeapReference(temp); + // /* HeapReference<Class> */ temp = temp->iftable_ + __ Loadwu(temp, temp, iftable_offset); + codegen_->MaybeUnpoisonHeapReference(temp); + // Load the size of the `IfTable`. The `Class::iftable_` is never null. + __ Loadw(out, temp, array_length_offset); + // Loop through the `IfTable` and check if any class matches. + Riscv64Label loop; + XRegister temp2 = srs.AllocateXRegister(); + __ Bind(&loop); + __ Beqz(out, &done); // If taken, the result in `out` is already 0 (false). + __ Loadwu(temp2, temp, object_array_data_offset); + codegen_->MaybeUnpoisonHeapReference(temp2); + // Go to next interface. + __ Addi(temp, temp, 2 * kHeapReferenceSize); + __ Addi(out, out, -2); + // Compare the classes and continue the loop if they do not match. + __ Bne(cls.AsRegister<XRegister>(), temp2, &loop); + __ LoadConst32(out, 1); + break; + } + + case TypeCheckKind::kUnresolvedCheck: { // Note that we indeed only call on slow path, but we always go - // into the slow path for the unresolved and interface check - // cases. + // into the slow path for the unresolved check case. // // We cannot directly call the InstanceofNonTrivial runtime // entry point without resorting to a type checking slow path |