Faster class retrieval in nterp.
Split `NterpGetClassOrAllocateObject` to two individual
functions to avoid a slow `switch` and an `if`.
Also deduplicate exception throwing code in nterp.
Test: testrunner.py --host --interpreter --jit
Test: testrunner.py --target --interpreter --jit
Change-Id: I927af8f534c43d0bd760f555c0de1dd220f7df93
diff --git a/runtime/interpreter/mterp/nterp.cc b/runtime/interpreter/mterp/nterp.cc
index 753dcc1..2498319 100644
--- a/runtime/interpreter/mterp/nterp.cc
+++ b/runtime/interpreter/mterp/nterp.cc
@@ -453,63 +453,71 @@
return resolved_field->GetOffset().Uint32Value();
}
-extern "C" mirror::Object* NterpGetClassOrAllocateObject(Thread* self,
- ArtMethod* caller,
- uint16_t* dex_pc_ptr)
+extern "C" mirror::Object* NterpGetClass(Thread* self, ArtMethod* caller, uint16_t* dex_pc_ptr)
REQUIRES_SHARED(Locks::mutator_lock_) {
UpdateHotness(caller);
const Instruction* inst = Instruction::At(dex_pc_ptr);
- dex::TypeIndex index;
- switch (inst->Opcode()) {
- case Instruction::NEW_INSTANCE:
- index = dex::TypeIndex(inst->VRegB_21c());
- break;
- case Instruction::CHECK_CAST:
- index = dex::TypeIndex(inst->VRegB_21c());
- break;
- case Instruction::INSTANCE_OF:
- index = dex::TypeIndex(inst->VRegC_22c());
- break;
- case Instruction::CONST_CLASS:
- index = dex::TypeIndex(inst->VRegB_21c());
- break;
- case Instruction::NEW_ARRAY:
- index = dex::TypeIndex(inst->VRegC_22c());
- break;
- default:
- LOG(FATAL) << "Unreachable";
- }
+ Instruction::Code opcode = inst->Opcode();
+ DCHECK(opcode == Instruction::CHECK_CAST ||
+ opcode == Instruction::INSTANCE_OF ||
+ opcode == Instruction::CONST_CLASS ||
+ opcode == Instruction::NEW_ARRAY);
+
+ // In release mode, this is just a simple load.
+ // In debug mode, this checks that we're using the correct instruction format.
+ dex::TypeIndex index = dex::TypeIndex(
+ (opcode == Instruction::CHECK_CAST || opcode == Instruction::CONST_CLASS)
+ ? inst->VRegB_21c()
+ : inst->VRegC_22c());
+
ObjPtr<mirror::Class> c =
ResolveVerifyAndClinit(index,
caller,
self,
/* can_run_clinit= */ false,
/* verify_access= */ !caller->SkipAccessChecks());
- if (c == nullptr) {
+ if (UNLIKELY(c == nullptr)) {
DCHECK(self->IsExceptionPending());
return nullptr;
}
- if (inst->Opcode() == Instruction::NEW_INSTANCE) {
- gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
- if (UNLIKELY(c->IsStringClass())) {
- // We don't cache the class for strings as we need to special case their
- // allocation.
- return mirror::String::AllocEmptyString(self, allocator_type).Ptr();
- } else {
- if (!c->IsFinalizable() && c->IsInstantiable()) {
- // Cache non-finalizable classes for next calls.
- UpdateCache(self, dex_pc_ptr, c.Ptr());
- }
- return AllocObjectFromCode(c, self, allocator_type).Ptr();
- }
- } else {
- // For all other cases, cache the class.
- UpdateCache(self, dex_pc_ptr, c.Ptr());
- }
+ UpdateCache(self, dex_pc_ptr, c.Ptr());
return c.Ptr();
}
+extern "C" mirror::Object* NterpAllocateObject(Thread* self,
+ ArtMethod* caller,
+ uint16_t* dex_pc_ptr)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ UpdateHotness(caller);
+ const Instruction* inst = Instruction::At(dex_pc_ptr);
+ DCHECK_EQ(inst->Opcode(), Instruction::NEW_INSTANCE);
+ dex::TypeIndex index = dex::TypeIndex(inst->VRegB_21c());
+ ObjPtr<mirror::Class> c =
+ ResolveVerifyAndClinit(index,
+ caller,
+ self,
+ /* can_run_clinit= */ false,
+ /* verify_access= */ !caller->SkipAccessChecks());
+ if (UNLIKELY(c == nullptr)) {
+ DCHECK(self->IsExceptionPending());
+ return nullptr;
+ }
+
+ gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
+ if (UNLIKELY(c->IsStringClass())) {
+ // We don't cache the class for strings as we need to special case their
+ // allocation.
+ return mirror::String::AllocEmptyString(self, allocator_type).Ptr();
+ } else {
+ if (!c->IsFinalizable() && c->IsInstantiable()) {
+ // Cache non-finalizable classes for next calls.
+ UpdateCache(self, dex_pc_ptr, c.Ptr());
+ }
+ return AllocObjectFromCode(c, self, allocator_type).Ptr();
+ }
+}
+
extern "C" mirror::Object* NterpLoadObject(Thread* self, ArtMethod* caller, uint16_t* dex_pc_ptr)
REQUIRES_SHARED(Locks::mutator_lock_) {
const Instruction* inst = Instruction::At(dex_pc_ptr);