summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVladimir Marko <vmarko@google.com>2024-04-30 13:05:35 +0000
committerVladimĂ­r Marko <vmarko@google.com>2024-05-03 12:55:19 +0000
commit721bbf2bfd6ffe689067df5657059925e038bb0d (patch)
tree661c70929bc5552a37937a2966c381bd10fc1190
parentb3d88b3f4b47b7635cbdab54dfdcbf866b9813ff (diff)
downloadart-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.cc67
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