summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Vladimír Marko <vmarko@google.com> 2024-10-25 14:51:37 +0000
committer Vladimír Marko <vmarko@google.com> 2024-10-29 06:27:57 +0000
commit96f1c792b093c3a07cc960046419047f390d049c (patch)
tree099b49eaf382e98b3a9f8927397478ceeec3bbbb
parent7472fab1e4e6d2c01c1258ec81563414eecb0026 (diff)
Reland "verifier: Cache types by type index."
This reverts commit de7910029c3400a11070e818ae1463614c302a16. Reason for revert: Relanding with a fix - keep forced class resolution in `MethodVerifier<>::ResolveClass<>()`. Test: m test-art-host-gtest Test: testrunner.py --host --optimizing --jit-on-first-use Bug: 181943478 Change-Id: Ibdf8b5515ca6c3e4106e1a09700ca65565ce36bb
-rw-r--r--dex2oat/verifier_deps_test.cc6
-rw-r--r--openjdkjvmti/ti_method.cc10
-rw-r--r--runtime/verifier/class_verifier.cc4
-rw-r--r--runtime/verifier/method_verifier.cc280
-rw-r--r--runtime/verifier/method_verifier.h8
-rw-r--r--runtime/verifier/reg_type.cc7
-rw-r--r--runtime/verifier/reg_type_cache-inl.h29
-rw-r--r--runtime/verifier/reg_type_cache.cc101
-rw-r--r--runtime/verifier/reg_type_cache.h41
-rw-r--r--runtime/verifier/reg_type_test.cc145
10 files changed, 325 insertions, 306 deletions
diff --git a/dex2oat/verifier_deps_test.cc b/dex2oat/verifier_deps_test.cc
index 46e40902de..686f18803c 100644
--- a/dex2oat/verifier_deps_test.cc
+++ b/dex2oat/verifier_deps_test.cc
@@ -162,14 +162,14 @@ class VerifierDepsTest : public CommonCompilerDriverTest {
method.GetInvokeType(class_def->access_flags_));
CHECK(resolved_method != nullptr);
if (method_name == resolved_method->GetName()) {
- RegTypeCache reg_types(soa.Self(), class_linker_, Runtime::Current()->GetArenaPool());
+ ArenaPool* arena_pool = Runtime::Current()->GetArenaPool();
+ RegTypeCache reg_types(
+ soa.Self(), class_linker_, arena_pool, class_loader_handle, primary_dex_file_);
std::unique_ptr<MethodVerifier> verifier(
MethodVerifier::CreateVerifier(soa.Self(),
&reg_types,
callbacks_->GetVerifierDeps(),
- primary_dex_file_,
dex_cache_handle,
- class_loader_handle,
*class_def,
method.GetCodeItem(),
method.GetIndex(),
diff --git a/openjdkjvmti/ti_method.cc b/openjdkjvmti/ti_method.cc
index 6150a4692b..bf89b6e476 100644
--- a/openjdkjvmti/ti_method.cc
+++ b/openjdkjvmti/ti_method.cc
@@ -642,15 +642,19 @@ class CommonLocalVariableClosure : public art::Closure {
art::Runtime* runtime = art::Runtime::Current();
art::ClassLinker* class_linker = runtime->GetClassLinker();
art::ArenaPool* arena_pool = runtime->GetArenaPool();
- art::verifier::RegTypeCache reg_types(
- self, class_linker, arena_pool, /* can_load_classes= */ false, /* can_suspend= */ false);
+ art::verifier::RegTypeCache reg_types(self,
+ class_linker,
+ arena_pool,
+ class_loader,
+ dex_cache->GetDexFile(),
+ /* can_load_classes= */ false,
+ /* can_suspend= */ false);
std::unique_ptr<art::verifier::MethodVerifier> verifier(
art::verifier::MethodVerifier::CalculateVerificationInfo(
self,
&reg_types,
method,
dex_cache,
- class_loader,
dex_pc));
if (verifier == nullptr) {
JVMTI_LOG(WARNING, jvmti_) << "Unable to extract verification information from "
diff --git a/runtime/verifier/class_verifier.cc b/runtime/verifier/class_verifier.cc
index d6fd64e376..07202901fc 100644
--- a/runtime/verifier/class_verifier.cc
+++ b/runtime/verifier/class_verifier.cc
@@ -113,7 +113,7 @@ FailureKind ClassVerifier::VerifyClass(Thread* self,
if (accessor.NumMethods() != 0u) {
ArenaPool* arena_pool = Runtime::Current()->GetArenaPool();
- RegTypeCache reg_types(self, linker, arena_pool);
+ RegTypeCache reg_types(self, linker, arena_pool, class_loader, dex_file);
for (const ClassAccessor::Method& method : accessor.GetMethods()) {
int64_t* previous_idx = &previous_method_idx[method.IsStaticOrDirect() ? 0u : 1u];
self->AllowThreadSuspension();
@@ -131,9 +131,7 @@ FailureKind ClassVerifier::VerifyClass(Thread* self,
&reg_types,
verifier_deps,
method_idx,
- dex_file,
dex_cache,
- class_loader,
class_def,
method.GetCodeItem(),
method.GetAccessFlags(),
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index f8f4c8d8f9..52907beb5d 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -133,12 +133,10 @@ class MethodVerifier final : public ::art::verifier::MethodVerifier {
ArenaPool* arena_pool,
RegTypeCache* reg_types,
VerifierDeps* verifier_deps,
- const DexFile* dex_file,
const dex::CodeItem* code_item,
uint32_t method_idx,
bool aot_mode,
Handle<mirror::DexCache> dex_cache,
- Handle<mirror::ClassLoader> class_loader,
const dex::ClassDef& class_def,
uint32_t access_flags,
bool verify_to_dump,
@@ -147,7 +145,6 @@ class MethodVerifier final : public ::art::verifier::MethodVerifier {
arena_pool,
reg_types,
verifier_deps,
- dex_file,
class_def,
code_item,
method_idx,
@@ -155,7 +152,7 @@ class MethodVerifier final : public ::art::verifier::MethodVerifier {
method_access_flags_(access_flags),
return_type_(nullptr),
dex_cache_(dex_cache),
- class_loader_(class_loader),
+ class_loader_(reg_types->GetClassLoader()),
declaring_class_(nullptr),
interesting_dex_pc_(-1),
monitor_enter_dex_pcs_(nullptr),
@@ -163,6 +160,9 @@ class MethodVerifier final : public ::art::verifier::MethodVerifier {
allow_thread_suspension_(reg_types->CanSuspend()),
is_constructor_(false),
api_level_(api_level == 0 ? std::numeric_limits<uint32_t>::max() : api_level) {
+ DCHECK_EQ(dex_cache->GetDexFile(), reg_types->GetDexFile())
+ << dex_cache->GetDexFile()->GetLocation() << " / "
+ << reg_types->GetDexFile()->GetLocation();
}
void FinalAbstractClassError(ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_) {
@@ -671,9 +671,7 @@ class MethodVerifier final : public ::art::verifier::MethodVerifier {
const RegType& GetDeclaringClass() REQUIRES_SHARED(Locks::mutator_lock_) {
if (declaring_class_ == nullptr) {
const dex::MethodId& method_id = dex_file_->GetMethodId(dex_method_idx_);
- const char* descriptor
- = dex_file_->GetTypeDescriptor(dex_file_->GetTypeId(method_id.class_idx_));
- declaring_class_ = &reg_types_.FromDescriptor(class_loader_, descriptor);
+ declaring_class_ = &reg_types_.FromTypeIndex(method_id.class_idx_);
}
return *declaring_class_;
}
@@ -2521,7 +2519,7 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid fill-array-data for array of type "
<< array_type;
} else {
- const RegType& component_type = reg_types_.GetComponentType(array_type, class_loader_);
+ const RegType& component_type = reg_types_.GetComponentType(array_type);
DCHECK(!component_type.IsConflict());
if (component_type.IsNonZeroReferenceTypes()) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid fill-array-data with component type "
@@ -2846,12 +2844,11 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g
ArtMethod* called_method = VerifyInvocationArgs(inst, type, is_range);
uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
const dex::MethodId& method_id = dex_file_->GetMethodId(method_idx);
- dex::TypeIndex return_type_idx =
- dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
- const char* return_type_descriptor = dex_file_->GetTypeDescriptor(return_type_idx);
+ dex::TypeIndex return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
DCHECK_IMPLIES(called_method != nullptr,
- called_method->GetReturnTypeDescriptorView() == return_type_descriptor);
- const RegType& return_type = reg_types_.FromDescriptor(class_loader_, return_type_descriptor);
+ called_method->GetReturnTypeDescriptorView() ==
+ dex_file_->GetTypeDescriptorView(return_type_idx));
+ const RegType& return_type = reg_types_.FromTypeIndex(return_type_idx);
if (!return_type.IsLowHalf()) {
work_line_->SetResultRegisterType(this, return_type);
} else {
@@ -2866,11 +2863,10 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g
ArtMethod* called_method = VerifyInvocationArgs(inst, METHOD_DIRECT, is_range);
uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
const dex::MethodId& method_id = dex_file_->GetMethodId(method_idx);
- dex::TypeIndex return_type_idx =
- dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
- const char* return_type_descriptor = dex_file_->GetTypeDescriptor(return_type_idx);
+ dex::TypeIndex return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
DCHECK_IMPLIES(called_method != nullptr,
- called_method->GetReturnTypeDescriptorView() == return_type_descriptor);
+ called_method->GetReturnTypeDescriptorView() ==
+ dex_file_->GetTypeDescriptorView(return_type_idx));
bool is_constructor = (called_method != nullptr)
? called_method->IsConstructor()
: dex_file_->GetStringView(method_id.name_idx_) == "<init>";
@@ -2914,7 +2910,7 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g
*/
work_line_->MarkRefsAsInitialized(this, this_type);
}
- const RegType& return_type = reg_types_.FromDescriptor(class_loader_, return_type_descriptor);
+ const RegType& return_type = reg_types_.FromTypeIndex(return_type_idx);
if (!return_type.IsLowHalf()) {
work_line_->SetResultRegisterType(this, return_type);
} else {
@@ -2925,27 +2921,23 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g
}
case Instruction::INVOKE_STATIC:
case Instruction::INVOKE_STATIC_RANGE: {
- bool is_range = (inst->Opcode() == Instruction::INVOKE_STATIC_RANGE);
- ArtMethod* called_method = VerifyInvocationArgs(inst, METHOD_STATIC, is_range);
- const char* descriptor;
- if (called_method == nullptr) {
- uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
- const dex::MethodId& method_id = dex_file_->GetMethodId(method_idx);
- dex::TypeIndex return_type_idx =
- dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
- descriptor = dex_file_->GetTypeDescriptor(return_type_idx);
- } else {
- descriptor = called_method->GetReturnTypeDescriptor();
- }
- const RegType& return_type = reg_types_.FromDescriptor(class_loader_, descriptor);
- if (!return_type.IsLowHalf()) {
- work_line_->SetResultRegisterType(this, return_type);
- } else {
- work_line_->SetResultRegisterTypeWide(return_type, return_type.HighHalf(&reg_types_));
- }
- just_set_result = true;
+ bool is_range = (inst->Opcode() == Instruction::INVOKE_STATIC_RANGE);
+ ArtMethod* called_method = VerifyInvocationArgs(inst, METHOD_STATIC, is_range);
+ uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
+ const dex::MethodId& method_id = dex_file_->GetMethodId(method_idx);
+ dex::TypeIndex return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
+ DCHECK_IMPLIES(called_method != nullptr,
+ called_method->GetReturnTypeDescriptorView() ==
+ dex_file_->GetTypeDescriptorView(return_type_idx));
+ const RegType& return_type = reg_types_.FromTypeIndex(return_type_idx);
+ if (!return_type.IsLowHalf()) {
+ work_line_->SetResultRegisterType(this, return_type);
+ } else {
+ work_line_->SetResultRegisterTypeWide(return_type, return_type.HighHalf(&reg_types_));
}
+ just_set_result = true;
break;
+ }
case Instruction::INVOKE_INTERFACE:
case Instruction::INVOKE_INTERFACE_RANGE: {
bool is_range = (inst->Opcode() == Instruction::INVOKE_INTERFACE_RANGE);
@@ -2982,17 +2974,13 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g
* We don't have an object instance, so we can't find the concrete method. However, all of
* the type information is in the abstract method, so we're good.
*/
- const char* descriptor;
- if (abs_method == nullptr) {
- uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
- const dex::MethodId& method_id = dex_file_->GetMethodId(method_idx);
- dex::TypeIndex return_type_idx =
- dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
- descriptor = dex_file_->GetTypeDescriptor(return_type_idx);
- } else {
- descriptor = abs_method->GetReturnTypeDescriptor();
- }
- const RegType& return_type = reg_types_.FromDescriptor(class_loader_, descriptor);
+ uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
+ const dex::MethodId& method_id = dex_file_->GetMethodId(method_idx);
+ dex::TypeIndex return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
+ DCHECK_IMPLIES(abs_method != nullptr,
+ abs_method->GetReturnTypeDescriptorView() ==
+ dex_file_->GetTypeDescriptorView(return_type_idx));
+ const RegType& return_type = reg_types_.FromTypeIndex(return_type_idx);
if (!return_type.IsLowHalf()) {
work_line_->SetResultRegisterType(this, return_type);
} else {
@@ -3020,12 +3008,9 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g
DCHECK(HasFailures());
break;
}
- const uint16_t vRegH = (is_range) ? inst->VRegH_4rcc() : inst->VRegH_45cc();
- const dex::ProtoIndex proto_idx(vRegH);
- const char* return_descriptor =
- dex_file_->GetReturnTypeDescriptor(dex_file_->GetProtoId(proto_idx));
+ const dex::ProtoIndex proto_idx((is_range) ? inst->VRegH_4rcc() : inst->VRegH_45cc());
const RegType& return_type =
- reg_types_.FromDescriptor(class_loader_, return_descriptor);
+ reg_types_.FromTypeIndex(dex_file_->GetProtoId(proto_idx).return_type_idx_);
if (!return_type.IsLowHalf()) {
work_line_->SetResultRegisterType(this, return_type);
} else {
@@ -3054,11 +3039,9 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g
DexFileParameterIterator param_it(*dex_file_, proto_id);
// Treat method as static as it has yet to be determined.
VerifyInvocationArgsFromIterator(&param_it, inst, METHOD_STATIC, is_range, nullptr);
- const char* return_descriptor = dex_file_->GetReturnTypeDescriptor(proto_id);
// Step 3. Propagate return type information
- const RegType& return_type =
- reg_types_.FromDescriptor(class_loader_, return_descriptor);
+ const RegType& return_type = reg_types_.FromTypeIndex(proto_id.return_type_idx_);
if (!return_type.IsLowHalf()) {
work_line_->SetResultRegisterType(this, return_type);
} else {
@@ -3544,31 +3527,31 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g
template <bool kVerifierDebug>
template <CheckAccess C>
const RegType& MethodVerifier<kVerifierDebug>::ResolveClass(dex::TypeIndex class_idx) {
- ClassLinker* linker = GetClassLinker();
- ObjPtr<mirror::Class> klass = CanLoadClasses()
- ? linker->ResolveType(class_idx, dex_cache_, class_loader_)
- : linker->LookupResolvedType(class_idx, dex_cache_.Get(), class_loader_.Get());
- if (CanLoadClasses() && klass == nullptr) {
- DCHECK(self_->IsExceptionPending());
- self_->ClearException();
- }
- const RegType* result = nullptr;
- if (klass != nullptr) {
- result = reg_types_.FindClass(klass);
- if (result == nullptr) {
- const char* descriptor = dex_file_->GetTypeDescriptor(class_idx);
- result = reg_types_.InsertClass(descriptor, klass);
+ // FIXME: `RegTypeCache` can currently return a few fundamental classes such as j.l.Object
+ // or j.l.Class without resolving them using the current class loader and recording them
+ // in the corresponding `ClassTable`. The subsequent method and field lookup by callers of
+ // `ResolveClass<>()` can then put their methods and fields to the `DexCache` which should
+ // not be done for classes that are not in the `ClassTable`, potentially leading to crashes.
+ // For now, we force the class resolution here to avoid the inconsistency.
+ // Note that there's nothing we can do if we cannot load classes. (The only code path that
+ // does not allow loading classes is `FindLocksAtDexPc()` which should really need only to
+ // distinguish between reference and non-reference types and track locking. All the other
+ // work, including class lookup, is unnecessary as the class has already been verified.)
+ if (CanLoadClasses()) {
+ ClassLinker* linker = GetClassLinker();
+ ObjPtr<mirror::Class> klass = linker->ResolveType(class_idx, dex_cache_, class_loader_);
+ if (klass == nullptr) {
+ DCHECK(self_->IsExceptionPending());
+ self_->ClearException();
}
- } else {
- const char* descriptor = dex_file_->GetTypeDescriptor(class_idx);
- result = &reg_types_.FromDescriptor(class_loader_, descriptor);
}
- DCHECK(result != nullptr);
- if (result->IsConflict()) {
+
+ const RegType& result = reg_types_.FromTypeIndex(class_idx);
+ if (result.IsConflict()) {
const char* descriptor = dex_file_->GetTypeDescriptor(class_idx);
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "accessing broken descriptor '" << descriptor
<< "' in " << GetDeclaringClass();
- return *result;
+ return result;
}
// If requested, check if access is allowed. Unresolved types are included in this check, as the
@@ -3577,23 +3560,23 @@ const RegType& MethodVerifier<kVerifierDebug>::ResolveClass(dex::TypeIndex class
//
// Note: we do this for unresolved classes to trigger re-verification at runtime.
if (C != CheckAccess::kNo &&
- result->IsNonZeroReferenceTypes() &&
+ result.IsNonZeroReferenceTypes() &&
((C == CheckAccess::kYes && IsSdkVersionSetAndAtLeast(api_level_, SdkVersion::kP))
- || !result->IsUnresolvedTypes())) {
+ || !result.IsUnresolvedTypes())) {
const RegType& referrer = GetDeclaringClass();
if ((IsSdkVersionSetAndAtLeast(api_level_, SdkVersion::kP) || !referrer.IsUnresolvedTypes()) &&
- !referrer.CanAccess(*result)) {
+ !referrer.CanAccess(result)) {
if (IsAotMode()) {
Fail(VERIFY_ERROR_ACCESS_CLASS);
VLOG(verifier)
- << "(possibly) illegal class access: '" << referrer << "' -> '" << *result << "'";
+ << "(possibly) illegal class access: '" << referrer << "' -> '" << result << "'";
} else {
Fail(VERIFY_ERROR_ACCESS_CLASS)
- << "(possibly) illegal class access: '" << referrer << "' -> '" << *result << "'";
+ << "(possibly) illegal class access: '" << referrer << "' -> '" << result << "'";
}
}
}
- return *result;
+ return result;
}
template <bool kVerifierDebug>
@@ -3880,13 +3863,11 @@ ArtMethod* MethodVerifier<kVerifierDebug>::VerifyInvocationArgsFromIterator(
// postponed to runtime).
if (res_method != nullptr && !res_method->IsMiranda()) {
ObjPtr<mirror::Class> klass = res_method->GetDeclaringClass();
- std::string temp;
- res_method_class = &reg_types_.FromClass(klass->GetDescriptor(&temp), klass);
+ res_method_class = &reg_types_.FromClass(klass);
} else {
const uint32_t method_idx = GetMethodIdxOfInvoke(inst);
const dex::TypeIndex class_idx = dex_file_->GetMethodId(method_idx).class_idx_;
- res_method_class =
- &reg_types_.FromDescriptor(class_loader_, dex_file_->GetTypeDescriptor(class_idx));
+ res_method_class = &reg_types_.FromTypeIndex(class_idx);
}
if (!res_method_class->IsAssignableFrom(adjusted_type, this)) {
Fail(adjusted_type.IsUnresolvedTypes()
@@ -3915,15 +3896,7 @@ ArtMethod* MethodVerifier<kVerifierDebug>::VerifyInvocationArgsFromIterator(
return nullptr;
}
- const char* param_descriptor = it->GetDescriptor();
-
- if (param_descriptor == nullptr) {
- Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Rejecting invocation because of missing signature "
- "component";
- return nullptr;
- }
-
- const RegType& reg_type = reg_types_.FromDescriptor(class_loader_, param_descriptor);
+ const RegType& reg_type = reg_types_.FromTypeIndex(it->GetTypeIdx());
uint32_t get_reg = is_range ? inst->VRegC() + static_cast<uint32_t>(sig_registers) :
arg[sig_registers];
if (reg_type.IsIntegralTypes()) {
@@ -4034,32 +4007,6 @@ bool MethodVerifier<kVerifierDebug>::CheckCallSite(uint32_t call_site_idx) {
return true;
}
-class MethodParamListDescriptorIterator {
- public:
- explicit MethodParamListDescriptorIterator(ArtMethod* res_method) :
- res_method_(res_method), pos_(0), params_(res_method->GetParameterTypeList()),
- params_size_(params_ == nullptr ? 0 : params_->Size()) {
- }
-
- bool HasNext() {
- return pos_ < params_size_;
- }
-
- void Next() {
- ++pos_;
- }
-
- const char* GetDescriptor() REQUIRES_SHARED(Locks::mutator_lock_) {
- return res_method_->GetTypeDescriptorFromTypeIdx(params_->GetTypeItem(pos_).type_idx_);
- }
-
- private:
- ArtMethod* res_method_;
- size_t pos_;
- const dex::TypeList* params_;
- const size_t params_size_;
-};
-
template <bool kVerifierDebug>
ArtMethod* MethodVerifier<kVerifierDebug>::VerifyInvocationArgs(
const Instruction* inst, MethodType method_type, bool is_range) {
@@ -4079,8 +4026,7 @@ ArtMethod* MethodVerifier<kVerifierDebug>::VerifyInvocationArgs(
// has a vtable entry for the target method. Or the target is on a interface.
if (method_type == METHOD_SUPER) {
dex::TypeIndex class_idx = dex_file_->GetMethodId(method_idx).class_idx_;
- const RegType& reference_type =
- reg_types_.FromDescriptor(class_loader_, dex_file_->GetTypeDescriptor(class_idx));
+ const RegType& reference_type = reg_types_.FromTypeIndex(class_idx);
if (reference_type.IsUnresolvedTypes()) {
// We cannot differentiate on whether this is a class change error or just
// a missing method. This will be handled at runtime.
@@ -4126,19 +4072,17 @@ ArtMethod* MethodVerifier<kVerifierDebug>::VerifyInvocationArgs(
}
}
- ArtMethod* verified_method;
+ dex::ProtoIndex proto_idx;
if (UNLIKELY(method_type == METHOD_POLYMORPHIC)) {
// Process the signature of the calling site that is invoking the method handle.
- dex::ProtoIndex proto_idx(inst->VRegH());
- DexFileParameterIterator it(*dex_file_, dex_file_->GetProtoId(proto_idx));
- verified_method =
- VerifyInvocationArgsFromIterator(&it, inst, method_type, is_range, res_method);
+ proto_idx = dex::ProtoIndex(inst->VRegH());
} else {
// Process the target method's signature.
- MethodParamListDescriptorIterator it(res_method);
- verified_method =
- VerifyInvocationArgsFromIterator(&it, inst, method_type, is_range, res_method);
+ proto_idx = dex_file_->GetMethodId(method_idx).proto_idx_;
}
+ DexFileParameterIterator it(*dex_file_, dex_file_->GetProtoId(proto_idx));
+ ArtMethod* verified_method =
+ VerifyInvocationArgsFromIterator(&it, inst, method_type, is_range, res_method);
if (verified_method != nullptr && !verified_method->GetDeclaringClass()->IsInterface()) {
CheckForFinalAbstractClass(res_method->GetDeclaringClass());
@@ -4261,7 +4205,7 @@ void MethodVerifier<kVerifierDebug>::VerifyNewArray(const Instruction* inst,
DCHECK(!res_type.IsUnresolvedMergedReference());
// Verify each register. If "arg_count" is bad, VerifyRegisterType() will run off the end of
// the list and fail. It's legal, if silly, for arg_count to be zero.
- const RegType& expected_type = reg_types_.GetComponentType(res_type, class_loader_);
+ const RegType& expected_type = reg_types_.GetComponentType(res_type);
uint32_t arg_count = (is_range) ? inst->VRegA_3rc() : inst->VRegA_35c();
uint32_t arg[5];
if (!is_range) {
@@ -4324,7 +4268,7 @@ void MethodVerifier<kVerifierDebug>::VerifyAGet(const Instruction* inst,
}
} else {
/* verify the class */
- const RegType& component_type = reg_types_.GetComponentType(array_type, class_loader_);
+ const RegType& component_type = reg_types_.GetComponentType(array_type);
if (!component_type.IsReferenceTypes() && !is_primitive) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "primitive array type " << array_type
<< " source for aget-object";
@@ -4446,7 +4390,7 @@ void MethodVerifier<kVerifierDebug>::VerifyAPut(const Instruction* inst,
<< " because of missing class";
}
} else {
- const RegType& component_type = reg_types_.GetComponentType(array_type, class_loader_);
+ const RegType& component_type = reg_types_.GetComponentType(array_type);
const uint32_t vregA = inst->VRegA_23x();
if (is_primitive) {
VerifyPrimitivePut(component_type, insn_type, vregA);
@@ -4546,8 +4490,7 @@ ArtField* MethodVerifier<kVerifierDebug>::GetInstanceField(const RegType& obj_ty
// Fall through into a few last soft failure checks below.
} else {
ObjPtr<mirror::Class> klass = field->GetDeclaringClass();
- std::string temp;
- const RegType& field_klass = reg_types_.FromClass(klass->GetDescriptor(&temp), klass);
+ const RegType& field_klass = reg_types_.FromClass(klass);
if (obj_type.IsUninitializedTypes()) {
// Field accesses through uninitialized references are only allowable for constructors where
// the field is declared in this class.
@@ -4667,12 +4610,10 @@ void MethodVerifier<kVerifierDebug>::VerifyISFieldAccess(const Instruction* inst
// Note: see b/34966607. This and above may be changed in the future.
if (kAccType == FieldAccessType::kAccPut) {
const dex::FieldId& field_id = dex_file_->GetFieldId(field_idx);
- const char* field_class_descriptor = dex_file_->GetFieldDeclaringClassDescriptor(field_id);
- const RegType* field_class_type =
- &reg_types_.FromDescriptor(class_loader_, field_class_descriptor);
- if (!field_class_type->Equals(GetDeclaringClass())) {
+ const RegType& field_class_type = reg_types_.FromTypeIndex(field_id.class_idx_);
+ if (!field_class_type.Equals(GetDeclaringClass())) {
Fail(VERIFY_ERROR_ACCESS_FIELD) << "could not check field put for final field modify of "
- << field_class_descriptor
+ << dex_file_->GetFieldDeclaringClassDescriptor(field_id)
<< "."
<< dex_file_->GetFieldName(field_id)
<< " from other class "
@@ -4681,8 +4622,7 @@ void MethodVerifier<kVerifierDebug>::VerifyISFieldAccess(const Instruction* inst
}
}
const dex::FieldId& field_id = dex_file_->GetFieldId(field_idx);
- const char* type_descriptor = dex_file_->GetFieldTypeDescriptor(field_id);
- const RegType& field_type = reg_types_.FromDescriptor(class_loader_, type_descriptor);
+ const RegType& field_type = reg_types_.FromTypeIndex(field_id.type_idx_);
const uint32_t vregA = (is_static) ? inst->VRegA_21c() : inst->VRegA_22c();
static_assert(kAccType == FieldAccessType::kAccPut || kAccType == FieldAccessType::kAccGet,
"Unexpected third access type");
@@ -4798,9 +4738,7 @@ const RegType& MethodVerifier<kVerifierDebug>::GetMethodReturnType() {
if (return_type_ == nullptr) {
const dex::MethodId& method_id = dex_file_->GetMethodId(dex_method_idx_);
const dex::ProtoId& proto_id = dex_file_->GetMethodPrototype(method_id);
- dex::TypeIndex return_type_idx = proto_id.return_type_idx_;
- const char* descriptor = dex_file_->GetTypeDescriptor(dex_file_->GetTypeId(return_type_idx));
- return_type_ = &reg_types_.FromDescriptor(class_loader_, descriptor);
+ return_type_ = &reg_types_.FromTypeIndex(proto_id.return_type_idx_);
}
return *return_type_;
}
@@ -4877,7 +4815,6 @@ MethodVerifier::MethodVerifier(Thread* self,
ArenaPool* arena_pool,
RegTypeCache* reg_types,
VerifierDeps* verifier_deps,
- const DexFile* dex_file,
const dex::ClassDef& class_def,
const dex::CodeItem* code_item,
uint32_t dex_method_idx,
@@ -4889,9 +4826,9 @@ MethodVerifier::MethodVerifier(Thread* self,
reg_table_(allocator_),
work_insn_idx_(dex::kDexNoIndex),
dex_method_idx_(dex_method_idx),
- dex_file_(dex_file),
+ dex_file_(reg_types->GetDexFile()),
class_def_(class_def),
- code_item_accessor_(*dex_file, code_item),
+ code_item_accessor_(*dex_file_, code_item),
flags_{ .have_pending_hard_failure_ = false, .have_pending_runtime_throw_failure_ = false },
const_flags_{ .aot_mode_ = aot_mode, .can_load_classes_ = reg_types->CanLoadClasses() },
encountered_failure_types_(0),
@@ -4908,9 +4845,7 @@ MethodVerifier::FailureData MethodVerifier::VerifyMethod(Thread* self,
RegTypeCache* reg_types,
VerifierDeps* verifier_deps,
uint32_t method_idx,
- const DexFile* dex_file,
Handle<mirror::DexCache> dex_cache,
- Handle<mirror::ClassLoader> class_loader,
const dex::ClassDef& class_def,
const dex::CodeItem* code_item,
uint32_t method_access_flags,
@@ -4924,9 +4859,7 @@ MethodVerifier::FailureData MethodVerifier::VerifyMethod(Thread* self,
reg_types,
verifier_deps,
method_idx,
- dex_file,
dex_cache,
- class_loader,
class_def,
code_item,
method_access_flags,
@@ -4940,9 +4873,7 @@ MethodVerifier::FailureData MethodVerifier::VerifyMethod(Thread* self,
reg_types,
verifier_deps,
method_idx,
- dex_file,
dex_cache,
- class_loader,
class_def,
code_item,
method_access_flags,
@@ -4976,9 +4907,7 @@ MethodVerifier::FailureData MethodVerifier::VerifyMethod(Thread* self,
RegTypeCache* reg_types,
VerifierDeps* verifier_deps,
uint32_t method_idx,
- const DexFile* dex_file,
Handle<mirror::DexCache> dex_cache,
- Handle<mirror::ClassLoader> class_loader,
const dex::ClassDef& class_def,
const dex::CodeItem* code_item,
uint32_t method_access_flags,
@@ -4993,12 +4922,10 @@ MethodVerifier::FailureData MethodVerifier::VerifyMethod(Thread* self,
arena_pool,
reg_types,
verifier_deps,
- dex_file,
code_item,
method_idx,
aot_mode,
dex_cache,
- class_loader,
class_def,
method_access_flags,
/* verify_to_dump= */ false,
@@ -5010,8 +4937,9 @@ MethodVerifier::FailureData MethodVerifier::VerifyMethod(Thread* self,
if (verifier.failures_.size() != 0) {
if (VLOG_IS_ON(verifier)) {
- verifier.DumpFailures(VLOG_STREAM(verifier) << "Soft verification failures in "
- << dex_file->PrettyMethod(method_idx) << "\n");
+ verifier.DumpFailures(VLOG_STREAM(verifier)
+ << "Soft verification failures in "
+ << reg_types->GetDexFile()->PrettyMethod(method_idx) << "\n");
}
if (kVerifierDebug) {
LOG(INFO) << verifier.info_messages_.str();
@@ -5050,9 +4978,9 @@ MethodVerifier::FailureData MethodVerifier::VerifyMethod(Thread* self,
LOG(FATAL) << "Unsupported log-level " << static_cast<uint32_t>(log_level);
UNREACHABLE();
}
- verifier.DumpFailures(LOG_STREAM(severity) << "Verification error in "
- << dex_file->PrettyMethod(method_idx)
- << "\n");
+ verifier.DumpFailures(LOG_STREAM(severity)
+ << "Verification error in "
+ << reg_types->GetDexFile()->PrettyMethod(method_idx) << "\n");
}
if (hard_failure_msg != nullptr) {
CHECK(!verifier.failure_messages_.empty());
@@ -5080,7 +5008,7 @@ MethodVerifier::FailureData MethodVerifier::VerifyMethod(Thread* self,
if (duration_ns > MsToNs(Runtime::Current()->GetVerifierLoggingThresholdMs())) {
double bytecodes_per_second =
verifier.code_item_accessor_.InsnsSizeInCodeUnits() / (duration_ns * 1e-9);
- LOG(WARNING) << "Verification of " << dex_file->PrettyMethod(method_idx)
+ LOG(WARNING) << "Verification of " << reg_types->GetDexFile()->PrettyMethod(method_idx)
<< " took " << PrettyDuration(duration_ns)
<< (impl::IsLargeMethod(verifier.CodeItem()) ? " (large method)" : "")
<< " (" << StringPrintf("%.2f", bytecodes_per_second) << " bytecodes/s)"
@@ -5097,7 +5025,6 @@ MethodVerifier* MethodVerifier::CalculateVerificationInfo(
RegTypeCache* reg_types,
ArtMethod* method,
Handle<mirror::DexCache> dex_cache,
- Handle<mirror::ClassLoader> class_loader,
uint32_t dex_pc) {
Runtime* runtime = Runtime::Current();
std::unique_ptr<impl::MethodVerifier<false>> verifier(
@@ -5105,12 +5032,10 @@ MethodVerifier* MethodVerifier::CalculateVerificationInfo(
runtime->GetArenaPool(),
reg_types,
/* verifier_deps= */ nullptr,
- method->GetDexFile(),
method->GetCodeItem(),
method->GetDexMethodIndex(),
runtime->IsAotCompiler(),
dex_cache,
- class_loader,
*method->GetDeclaringClass()->GetClassDef(),
method->GetAccessFlags(),
/* verify_to_dump= */ false,
@@ -5145,18 +5070,16 @@ void MethodVerifier::VerifyMethodAndDump(Thread* self,
Runtime* runtime = Runtime::Current();
ClassLinker* class_linker = runtime->GetClassLinker();
ArenaPool* arena_pool = runtime->GetArenaPool();
- RegTypeCache reg_types(self, class_linker, arena_pool);
+ RegTypeCache reg_types(self, class_linker, arena_pool, class_loader, dex_file);
impl::MethodVerifier<false> verifier(
self,
arena_pool,
&reg_types,
/* verifier_deps= */ nullptr,
- dex_file,
code_item,
dex_method_idx,
runtime->IsAotCompiler(),
dex_cache,
- class_loader,
class_def,
method_access_flags,
/* verify_to_dump= */ true,
@@ -5183,18 +5106,21 @@ void MethodVerifier::FindLocksAtDexPc(
Runtime* runtime = Runtime::Current();
ClassLinker* class_linker = runtime->GetClassLinker();
ArenaPool* arena_pool = runtime->GetArenaPool();
- RegTypeCache reg_types(
- self, class_linker, arena_pool, /* can_load_classes= */ false, /* can_suspend= */ false);
+ RegTypeCache reg_types(self,
+ class_linker,
+ arena_pool,
+ class_loader,
+ dex_cache->GetDexFile(),
+ /* can_load_classes= */ false,
+ /* can_suspend= */ false);
impl::MethodVerifier<false> verifier(self,
arena_pool,
&reg_types,
/* verifier_deps= */ nullptr,
- m->GetDexFile(),
m->GetCodeItem(),
m->GetDexMethodIndex(),
runtime->IsAotCompiler(),
dex_cache,
- class_loader,
m->GetClassDef(),
m->GetAccessFlags(),
/* verify_to_dump= */ false,
@@ -5207,9 +5133,7 @@ void MethodVerifier::FindLocksAtDexPc(
MethodVerifier* MethodVerifier::CreateVerifier(Thread* self,
RegTypeCache* reg_types,
VerifierDeps* verifier_deps,
- const DexFile* dex_file,
Handle<mirror::DexCache> dex_cache,
- Handle<mirror::ClassLoader> class_loader,
const dex::ClassDef& class_def,
const dex::CodeItem* code_item,
uint32_t method_idx,
@@ -5220,12 +5144,10 @@ MethodVerifier* MethodVerifier::CreateVerifier(Thread* self,
Runtime::Current()->GetArenaPool(),
reg_types,
verifier_deps,
- dex_file,
code_item,
method_idx,
Runtime::Current()->IsAotCompiler(),
dex_cache,
- class_loader,
class_def,
access_flags,
verify_to_dump,
diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h
index e12a2f8fb1..711b455c2d 100644
--- a/runtime/verifier/method_verifier.h
+++ b/runtime/verifier/method_verifier.h
@@ -116,7 +116,6 @@ class MethodVerifier {
RegTypeCache* reg_types,
ArtMethod* method,
Handle<mirror::DexCache> dex_cache,
- Handle<mirror::ClassLoader> class_loader,
uint32_t dex_pc)
REQUIRES_SHARED(Locks::mutator_lock_);
@@ -196,7 +195,6 @@ class MethodVerifier {
ArenaPool* arena_pool,
RegTypeCache* reg_types,
VerifierDeps* verifier_deps,
- const DexFile* dex_file,
const dex::ClassDef& class_def,
const dex::CodeItem* code_item,
uint32_t dex_method_idx,
@@ -229,9 +227,7 @@ class MethodVerifier {
RegTypeCache* reg_types,
VerifierDeps* verifier_deps,
uint32_t method_idx,
- const DexFile* dex_file,
Handle<mirror::DexCache> dex_cache,
- Handle<mirror::ClassLoader> class_loader,
const dex::ClassDef& class_def_idx,
const dex::CodeItem* code_item,
uint32_t method_access_flags,
@@ -247,9 +243,7 @@ class MethodVerifier {
RegTypeCache* reg_types,
VerifierDeps* verifier_deps,
uint32_t method_idx,
- const DexFile* dex_file,
Handle<mirror::DexCache> dex_cache,
- Handle<mirror::ClassLoader> class_loader,
const dex::ClassDef& class_def_idx,
const dex::CodeItem* code_item,
uint32_t method_access_flags,
@@ -267,9 +261,7 @@ class MethodVerifier {
static MethodVerifier* CreateVerifier(Thread* self,
RegTypeCache* reg_types,
VerifierDeps* verifier_deps,
- const DexFile* dex_file,
Handle<mirror::DexCache> dex_cache,
- Handle<mirror::ClassLoader> class_loader,
const dex::ClassDef& class_def,
const dex::CodeItem* code_item,
uint32_t method_idx,
diff --git a/runtime/verifier/reg_type.cc b/runtime/verifier/reg_type.cc
index 62ba55be2c..23f1ff0cab 100644
--- a/runtime/verifier/reg_type.cc
+++ b/runtime/verifier/reg_type.cc
@@ -312,8 +312,7 @@ const RegType& RegType::GetSuperClass(RegTypeCache* cache) const {
if (!IsUnresolvedTypes()) {
ObjPtr<mirror::Class> super_klass = GetClass()->GetSuperClass();
if (super_klass != nullptr) {
- std::string temp;
- return cache->FromClass(super_klass->GetDescriptor(&temp), super_klass);
+ return cache->FromClass(super_klass);
} else {
return cache->Zero();
}
@@ -705,9 +704,7 @@ const RegType& RegType::Merge(const RegType& incoming_type,
} else if (incoming_type.GetClass() == join_class) {
return incoming_type;
} else {
- std::string temp;
- const char* descriptor = join_class->GetDescriptor(&temp);
- return reg_types->FromClass(descriptor, join_class);
+ return reg_types->FromClass(join_class);
}
}
} else {
diff --git a/runtime/verifier/reg_type_cache-inl.h b/runtime/verifier/reg_type_cache-inl.h
index c3b0850cde..6cde1ac048 100644
--- a/runtime/verifier/reg_type_cache-inl.h
+++ b/runtime/verifier/reg_type_cache-inl.h
@@ -19,6 +19,7 @@
#include "base/bit_vector-inl.h"
#include "class_root-inl.h"
+#include "dex/dex_file.h"
#include "mirror/class-inl.h"
#include "mirror/method_handle_impl.h"
#include "mirror/method_type.h"
@@ -46,6 +47,14 @@ inline const ConstantType& RegTypeCache::FromCat1Const(int32_t value, bool preci
return FromCat1NonSmallConstant(value, precise);
}
+inline const RegType& RegTypeCache::FromTypeIndex(dex::TypeIndex type_index) {
+ DCHECK_LT(type_index.index_, dex_file_->NumTypeIds());
+ if (entries_for_type_index_[type_index.index_] != nullptr) {
+ return *entries_for_type_index_[type_index.index_];
+ }
+ return FromTypeIndexUncached(type_index);
+}
+
inline const BooleanType& RegTypeCache::Boolean() {
return *down_cast<const BooleanType*>(entries_[kBooleanCacheId]);
}
@@ -124,39 +133,43 @@ inline const ImpreciseConstType& RegTypeCache::PosShortConstant() {
}
inline const ReferenceType& RegTypeCache::JavaLangClass() {
- const RegType* result = &FromClass("Ljava/lang/Class;", GetClassRoot<mirror::Class>());
+ const RegType* result = &FromClass(GetClassRoot<mirror::Class>());
+ DCHECK(result->GetClass()->DescriptorEquals("Ljava/lang/Class;"));
DCHECK(result->IsReference());
return *down_cast<const ReferenceType*>(result);
}
inline const ReferenceType& RegTypeCache::JavaLangString() {
- const RegType* result = &FromClass("Ljava/lang/String;", GetClassRoot<mirror::String>());
+ const RegType* result = &FromClass(GetClassRoot<mirror::String>());
+ DCHECK(result->GetClass()->DescriptorEquals("Ljava/lang/String;"));
DCHECK(result->IsReference());
return *down_cast<const ReferenceType*>(result);
}
inline const ReferenceType& RegTypeCache::JavaLangInvokeMethodHandle() {
- const RegType* result = &FromClass("Ljava/lang/invoke/MethodHandle;",
- GetClassRoot<mirror::MethodHandle>());
+ const RegType* result = &FromClass(GetClassRoot<mirror::MethodHandle>());
+ DCHECK(result->GetClass()->DescriptorEquals("Ljava/lang/invoke/MethodHandle;"));
DCHECK(result->IsReference());
return *down_cast<const ReferenceType*>(result);
}
inline const ReferenceType& RegTypeCache::JavaLangInvokeMethodType() {
- const RegType* result = &FromClass("Ljava/lang/invoke/MethodType;",
- GetClassRoot<mirror::MethodType>());
+ const RegType* result = &FromClass(GetClassRoot<mirror::MethodType>());
+ DCHECK(result->GetClass()->DescriptorEquals("Ljava/lang/invoke/MethodType;"));
DCHECK(result->IsReference());
return *down_cast<const ReferenceType*>(result);
}
inline const ReferenceType& RegTypeCache::JavaLangThrowable() {
- const RegType* result = &FromClass("Ljava/lang/Throwable;", GetClassRoot<mirror::Throwable>());
+ const RegType* result = &FromClass(GetClassRoot<mirror::Throwable>());
+ DCHECK(result->GetClass()->DescriptorEquals("Ljava/lang/Throwable;"));
DCHECK(result->IsReference());
return *down_cast<const ReferenceType*>(result);
}
inline const ReferenceType& RegTypeCache::JavaLangObject() {
- const RegType* result = &FromClass("Ljava/lang/Object;", GetClassRoot<mirror::Object>());
+ const RegType* result = &FromClass(GetClassRoot<mirror::Object>());
+ DCHECK(result->GetClass()->DescriptorEquals("Ljava/lang/Object;"));
DCHECK(result->IsReference());
return *down_cast<const ReferenceType*>(result);
}
diff --git a/runtime/verifier/reg_type_cache.cc b/runtime/verifier/reg_type_cache.cc
index c704209c60..64df3116eb 100644
--- a/runtime/verifier/reg_type_cache.cc
+++ b/runtime/verifier/reg_type_cache.cc
@@ -69,8 +69,7 @@ void RegTypeCache::FillPrimitiveAndSmallConstantTypes() {
new (&allocator_) NullType(null_handle_, "", kNullCacheId);
}
-const RegType& RegTypeCache::FromDescriptor(Handle<mirror::ClassLoader> loader,
- const char* descriptor) {
+const RegType& RegTypeCache::FromDescriptor(const char* descriptor) {
if (descriptor[1] == '\0') {
switch (descriptor[0]) {
case 'Z':
@@ -94,12 +93,19 @@ const RegType& RegTypeCache::FromDescriptor(Handle<mirror::ClassLoader> loader,
return Conflict();
}
} else if (descriptor[0] == 'L' || descriptor[0] == '[') {
- return From(loader, descriptor);
+ return From(descriptor);
} else {
return Conflict();
}
}
+const RegType& RegTypeCache::FromTypeIndexUncached(dex::TypeIndex type_index) {
+ DCHECK(entries_for_type_index_[type_index.index_] == nullptr);
+ const char* descriptor = dex_file_->GetTypeDescriptor(type_index);
+ const RegType& reg_type = FromDescriptor(descriptor);
+ entries_for_type_index_[type_index.index_] = &reg_type;
+ return reg_type;
+}
const RegType& RegTypeCache::RegTypeFromPrimitiveType(Primitive::Type prim_type) const {
switch (prim_type) {
@@ -134,16 +140,15 @@ bool RegTypeCache::MatchDescriptor(size_t idx, const std::string_view& descripto
return true;
}
-ObjPtr<mirror::Class> RegTypeCache::ResolveClass(const char* descriptor,
- Handle<mirror::ClassLoader> loader) {
+ObjPtr<mirror::Class> RegTypeCache::ResolveClass(const char* descriptor) {
// Class was not found, must create new type.
// Try resolving class
Thread* self = Thread::Current();
ObjPtr<mirror::Class> klass = nullptr;
if (can_load_classes_) {
- klass = class_linker_->FindClass(self, descriptor, loader);
+ klass = class_linker_->FindClass(self, descriptor, class_loader_);
} else {
- klass = class_linker_->LookupClass(self, descriptor, loader.Get());
+ klass = class_linker_->LookupClass(self, descriptor, class_loader_.Get());
if (klass != nullptr && !klass->IsResolved()) {
// We found the class but without it being loaded its not safe for use.
klass = nullptr;
@@ -158,7 +163,7 @@ std::string_view RegTypeCache::AddString(const std::string_view& str) {
return std::string_view(ptr, str.length());
}
-const RegType& RegTypeCache::From(Handle<mirror::ClassLoader> loader, const char* descriptor) {
+const RegType& RegTypeCache::From(const char* descriptor) {
std::string_view sv_descriptor(descriptor);
// Try looking up the class in the cache first. We use a std::string_view to avoid
// repeated strlen operations on the descriptor.
@@ -169,7 +174,9 @@ const RegType& RegTypeCache::From(Handle<mirror::ClassLoader> loader, const char
}
// Class not found in the cache, will create a new type for that.
// Try resolving class.
- ObjPtr<mirror::Class> klass = ResolveClass(descriptor, loader);
+ ObjPtr<mirror::Class> klass = ResolveClass(descriptor);
+ // TODO: Avoid copying the `descriptor` with `AddString()` below if the `descriptor`
+ // comes from the dex file, for example through `FromTypeIndex()`.
if (klass != nullptr) {
DCHECK(!klass->IsPrimitive());
RegType* entry = new (&allocator_) ReferenceType(
@@ -202,42 +209,55 @@ const RegType& RegTypeCache::MakeUnresolvedReference() {
null_handle_, AddString("a"), entries_.size()));
}
-const RegType* RegTypeCache::FindClass(ObjPtr<mirror::Class> klass) const {
+const RegType& RegTypeCache::FromClass(ObjPtr<mirror::Class> klass) {
DCHECK(klass != nullptr);
+ DCHECK(!klass->IsProxyClass());
+
if (klass->IsPrimitive()) {
- return &RegTypeFromPrimitiveType(klass->GetPrimitiveType());
+ return RegTypeFromPrimitiveType(klass->GetPrimitiveType());
+ }
+ if (!klass->IsArrayClass() && &klass->GetDexFile() == dex_file_) {
+ // Go through the `TypeIndex`-based cache. If the entry is not there yet, we shall
+ // fill it in now to make sure it's available for subsequent lookups.
+ std::optional<StackHandleScope<1u>> hs(std::nullopt);
+ if (kIsDebugBuild) {
+ hs.emplace(Thread::Current());
+ }
+ Handle<mirror::Class> h_class =
+ kIsDebugBuild ? hs->NewHandle(klass) : Handle<mirror::Class>();
+ const RegType& reg_type = FromTypeIndex(klass->GetDexTypeIndex());
+ DCHECK(reg_type.HasClass());
+ DCHECK(reg_type.GetClass() == h_class.Get());
+ return reg_type;
}
for (auto& pair : klass_entries_) {
- const Handle<mirror::Class> reg_klass = pair.first;
- const RegType* reg_type = pair.second;
- if (reg_klass.Get() == klass) {
- return reg_type;
+ const Handle<mirror::Class> entry_klass = pair.first;
+ const RegType* entry_reg_type = pair.second;
+ if (entry_klass.Get() == klass) {
+ return *entry_reg_type;
}
}
- return nullptr;
-}
-const RegType* RegTypeCache::InsertClass(const std::string_view& descriptor,
- ObjPtr<mirror::Class> klass) {
// No reference to the class was found, create new reference.
- DCHECK(FindClass(klass) == nullptr);
- RegType* const reg_type =
- new (&allocator_) ReferenceType(handles_.NewHandle(klass), descriptor, entries_.size());
- return &AddEntry(reg_type);
-}
-
-const RegType& RegTypeCache::FromClass(const char* descriptor, ObjPtr<mirror::Class> klass) {
- DCHECK(klass != nullptr);
- const RegType* reg_type = FindClass(klass);
- if (reg_type == nullptr) {
- reg_type = InsertClass(AddString(std::string_view(descriptor)), klass);
+ std::string_view descriptor;
+ if (klass->IsArrayClass()) {
+ std::string temp;
+ descriptor = AddString(std::string_view(klass->GetDescriptor(&temp)));
+ } else {
+ // Point `descriptor` to the string data in the dex file that defines the `klass`.
+ // That dex file cannot be unloaded while we hold a `Handle<>` to that `klass`.
+ descriptor = klass->GetDescriptorView();
}
- return *reg_type;
+ Handle<mirror::Class> h_klass = handles_.NewHandle(klass);
+ const RegType* reg_type = new (&allocator_) ReferenceType(h_klass, descriptor, entries_.size());
+ return AddEntry(reg_type);
}
RegTypeCache::RegTypeCache(Thread* self,
ClassLinker* class_linker,
ArenaPool* arena_pool,
+ Handle<mirror::ClassLoader> class_loader,
+ const DexFile* dex_file,
bool can_load_classes,
bool can_suspend)
: arena_stack_(arena_pool),
@@ -246,12 +266,18 @@ RegTypeCache::RegTypeCache(Thread* self,
klass_entries_(allocator_.Adapter(kArenaAllocVerifier)),
handles_(self),
class_linker_(class_linker),
+ class_loader_(class_loader),
+ dex_file_(dex_file),
+ entries_for_type_index_(allocator_.AllocArray<const RegType*>(dex_file->NumTypeIds())),
can_load_classes_(can_load_classes),
can_suspend_(can_suspend) {
DCHECK(can_suspend || !can_load_classes) << "Cannot load classes if suspension is disabled!";
if (kIsDebugBuild && can_suspend) {
Thread::Current()->AssertThreadSuspensionIsAllowable(gAborting == 0);
}
+ // TODO: Why are we using `ScopedArenaAllocator` here instead of the `ArenaAllocator` which
+ // guarantees zero-initialization? We could avoid this `fill_n()` with the `ArenaAllocator`.
+ std::fill_n(entries_for_type_index_, dex_file->NumTypeIds(), nullptr);
// The klass_entries_ array does not have primitives or small constants.
static constexpr size_t kNumReserveEntries = 32;
klass_entries_.reserve(kNumReserveEntries);
@@ -532,25 +558,24 @@ const ConstantType& RegTypeCache::FromCat2ConstHi(int32_t value, bool precise) {
return AddEntry(entry);
}
-const RegType& RegTypeCache::GetComponentType(const RegType& array,
- Handle<mirror::ClassLoader> loader) {
+const RegType& RegTypeCache::GetComponentType(const RegType& array) {
if (!array.IsArrayTypes()) {
return Conflict();
} else if (array.IsUnresolvedTypes()) {
DCHECK(!array.IsUnresolvedMergedReference()); // Caller must make sure not to ask for this.
const std::string descriptor(array.GetDescriptor());
- return FromDescriptor(loader, descriptor.c_str() + 1);
+ return FromDescriptor(descriptor.c_str() + 1);
} else {
ObjPtr<mirror::Class> klass = array.GetClass()->GetComponentType();
- std::string temp;
- const char* descriptor = klass->GetDescriptor(&temp);
if (klass->IsErroneous()) {
// Arrays may have erroneous component types, use unresolved in that case.
// We assume that the primitive classes are not erroneous, so we know it is a
// reference type.
- return FromDescriptor(loader, descriptor);
+ std::string temp;
+ const char* descriptor = klass->GetDescriptor(&temp);
+ return FromDescriptor(descriptor);
} else {
- return FromClass(descriptor, klass);
+ return FromClass(klass);
}
}
}
diff --git a/runtime/verifier/reg_type_cache.h b/runtime/verifier/reg_type_cache.h
index 54a6a6ae3c..737dc39c8b 100644
--- a/runtime/verifier/reg_type_cache.h
+++ b/runtime/verifier/reg_type_cache.h
@@ -36,7 +36,7 @@ class ClassLoader;
} // namespace mirror
class ClassLinker;
-class ScopedArenaAllocator;
+class DexFile;
namespace verifier {
@@ -69,9 +69,19 @@ class RegTypeCache {
EXPORT RegTypeCache(Thread* self,
ClassLinker* class_linker,
ArenaPool* arena_pool,
+ Handle<mirror::ClassLoader> class_loader,
+ const DexFile* dex_file,
bool can_load_classes = true,
bool can_suspend = true);
+ Handle<mirror::ClassLoader> GetClassLoader() const {
+ return class_loader_;
+ }
+
+ const DexFile* GetDexFile() const {
+ return dex_file_;
+ }
+
bool CanLoadClasses() const {
return can_load_classes_;
}
@@ -81,14 +91,8 @@ class RegTypeCache {
}
const art::verifier::RegType& GetFromId(uint16_t id) const;
- // Find a RegType, returns null if not found.
- const RegType* FindClass(ObjPtr<mirror::Class> klass) const
- REQUIRES_SHARED(Locks::mutator_lock_);
- // Insert a new class with a specified descriptor, must not already be in the cache.
- const RegType* InsertClass(const std::string_view& descriptor, ObjPtr<mirror::Class> klass)
- REQUIRES_SHARED(Locks::mutator_lock_);
- // Get or insert a reg type for a descriptor and klass.
- const RegType& FromClass(const char* descriptor, ObjPtr<mirror::Class> klass)
+ // Get or insert a reg type for a klass.
+ const RegType& FromClass(ObjPtr<mirror::Class> klass)
REQUIRES_SHARED(Locks::mutator_lock_);
const ConstantType& FromCat1Const(int32_t value, bool precise)
REQUIRES_SHARED(Locks::mutator_lock_);
@@ -96,7 +100,7 @@ class RegTypeCache {
REQUIRES_SHARED(Locks::mutator_lock_);
const ConstantType& FromCat2ConstHi(int32_t value, bool precise)
REQUIRES_SHARED(Locks::mutator_lock_);
- const RegType& FromDescriptor(Handle<mirror::ClassLoader> loader, const char* descriptor)
+ const RegType& FromDescriptor(const char* descriptor)
REQUIRES_SHARED(Locks::mutator_lock_);
const RegType& FromUnresolvedMerge(const RegType& left,
const RegType& right,
@@ -105,6 +109,8 @@ class RegTypeCache {
const RegType& FromUnresolvedSuperClass(const RegType& child)
REQUIRES_SHARED(Locks::mutator_lock_);
+ const RegType& FromTypeIndex(dex::TypeIndex type_index) REQUIRES_SHARED(Locks::mutator_lock_);
+
// Note: this should not be used outside of RegType::ClassJoin!
const RegType& MakeUnresolvedReference() REQUIRES_SHARED(Locks::mutator_lock_);
@@ -151,8 +157,7 @@ class RegTypeCache {
const ImpreciseConstType& IntConstant() REQUIRES_SHARED(Locks::mutator_lock_);
const ImpreciseConstType& PosByteConstant() REQUIRES_SHARED(Locks::mutator_lock_);
const ImpreciseConstType& PosShortConstant() REQUIRES_SHARED(Locks::mutator_lock_);
- const RegType& GetComponentType(const RegType& array, Handle<mirror::ClassLoader> loader)
- REQUIRES_SHARED(Locks::mutator_lock_);
+ const RegType& GetComponentType(const RegType& array) REQUIRES_SHARED(Locks::mutator_lock_);
void Dump(std::ostream& os) REQUIRES_SHARED(Locks::mutator_lock_);
const RegType& RegTypeFromPrimitiveType(Primitive::Type) const;
@@ -184,14 +189,17 @@ class RegTypeCache {
private:
void FillPrimitiveAndSmallConstantTypes() REQUIRES_SHARED(Locks::mutator_lock_);
- ObjPtr<mirror::Class> ResolveClass(const char* descriptor, Handle<mirror::ClassLoader> loader)
+ ObjPtr<mirror::Class> ResolveClass(const char* descriptor)
REQUIRES_SHARED(Locks::mutator_lock_);
bool MatchDescriptor(size_t idx, const std::string_view& descriptor)
REQUIRES_SHARED(Locks::mutator_lock_);
const ConstantType& FromCat1NonSmallConstant(int32_t value, bool precise)
REQUIRES_SHARED(Locks::mutator_lock_);
- const RegType& From(Handle<mirror::ClassLoader> loader, const char* descriptor)
+ const RegType& From(const char* descriptor)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
+ const RegType& FromTypeIndexUncached(dex::TypeIndex type_index)
REQUIRES_SHARED(Locks::mutator_lock_);
// Returns the pass in RegType.
@@ -217,6 +225,11 @@ class RegTypeCache {
ScopedNullHandle<mirror::Class> null_handle_;
ClassLinker* class_linker_;
+ Handle<mirror::ClassLoader> class_loader_;
+ const DexFile* const dex_file_;
+
+ // Fast lookup by type index.
+ const RegType** const entries_for_type_index_;
// Whether or not we're allowed to load classes.
const bool can_load_classes_;
diff --git a/runtime/verifier/reg_type_test.cc b/runtime/verifier/reg_type_test.cc
index 2dc110cd70..693dff4602 100644
--- a/runtime/verifier/reg_type_test.cc
+++ b/runtime/verifier/reg_type_test.cc
@@ -23,6 +23,7 @@
#include "base/scoped_arena_allocator.h"
#include "common_runtime_test.h"
#include "compiler_callbacks.h"
+#include "dex/test_dex_file_builder.h"
#include "reg_type-inl.h"
#include "reg_type_cache-inl.h"
#include "scoped_thread_state_change-inl.h"
@@ -36,13 +37,33 @@ class RegTypeTest : public CommonRuntimeTest {
RegTypeTest() {
use_boot_image_ = true; // Make the Runtime creation cheaper.
}
+
+ void SetUp() override {
+ CommonRuntimeTest::SetUp();
+
+ // Build a fake `DexFile` with some descriptors.
+ static const char* const descriptors[] = {
+ // References.
+ "Ljava/lang/Object;", "Ljava/lang/String;", "LNonExistent;",
+ // Primitives and `void`.
+ "Z", "B", "C", "S", "I", "J", "F", "D", "V"
+ };
+ TestDexFileBuilder builder;
+ for (const char* descriptor : descriptors) {
+ builder.AddType(descriptor);
+ }
+ dex_file_ = builder.Build("arbitrary-location");
+ }
+
+ std::unique_ptr<const DexFile> dex_file_;
};
TEST_F(RegTypeTest, ConstLoHi) {
// Tests creating primitive types types.
ArenaPool* arena_pool = Runtime::Current()->GetArenaPool();
ScopedObjectAccess soa(Thread::Current());
- RegTypeCache cache(soa.Self(), Runtime::Current()->GetClassLinker(), arena_pool);
+ ScopedNullHandle<mirror::ClassLoader> loader;
+ RegTypeCache cache(soa.Self(), class_linker_, arena_pool, loader, dex_file_.get());
const RegType& ref_type_const_0 = cache.FromCat1Const(10, true);
const RegType& ref_type_const_1 = cache.FromCat1Const(10, true);
const RegType& ref_type_const_2 = cache.FromCat1Const(30, true);
@@ -65,7 +86,8 @@ TEST_F(RegTypeTest, ConstLoHi) {
TEST_F(RegTypeTest, Pairs) {
ArenaPool* arena_pool = Runtime::Current()->GetArenaPool();
ScopedObjectAccess soa(Thread::Current());
- RegTypeCache cache(soa.Self(), Runtime::Current()->GetClassLinker(), arena_pool);
+ ScopedNullHandle<mirror::ClassLoader> loader;
+ RegTypeCache cache(soa.Self(), class_linker_, arena_pool, loader, dex_file_.get());
int64_t val = static_cast<int32_t>(1234);
const RegType& precise_lo = cache.FromCat2ConstLo(static_cast<int32_t>(val), true);
const RegType& precise_hi = cache.FromCat2ConstHi(static_cast<int32_t>(val >> 32), true);
@@ -90,7 +112,8 @@ TEST_F(RegTypeTest, Pairs) {
TEST_F(RegTypeTest, Primitives) {
ArenaPool* arena_pool = Runtime::Current()->GetArenaPool();
ScopedObjectAccess soa(Thread::Current());
- RegTypeCache cache(soa.Self(), Runtime::Current()->GetClassLinker(), arena_pool);
+ ScopedNullHandle<mirror::ClassLoader> loader;
+ RegTypeCache cache(soa.Self(), class_linker_, arena_pool, loader, dex_file_.get());
const RegType& bool_reg_type = cache.Boolean();
EXPECT_FALSE(bool_reg_type.IsUndefined());
@@ -365,12 +388,12 @@ TEST_F(RegTypeReferenceTest, UnresolvedType) {
ArenaPool* arena_pool = Runtime::Current()->GetArenaPool();
ScopedObjectAccess soa(Thread::Current());
ScopedNullHandle<mirror::ClassLoader> loader;
- RegTypeCache cache(soa.Self(), Runtime::Current()->GetClassLinker(), arena_pool);
- const RegType& ref_type_0 = cache.FromDescriptor(loader, "Ljava/lang/DoesNotExist;");
+ RegTypeCache cache(soa.Self(), class_linker_, arena_pool, loader, dex_file_.get());
+ const RegType& ref_type_0 = cache.FromDescriptor("Ljava/lang/DoesNotExist;");
EXPECT_TRUE(ref_type_0.IsUnresolvedReference());
EXPECT_TRUE(ref_type_0.IsNonZeroReferenceTypes());
- const RegType& ref_type_1 = cache.FromDescriptor(loader, "Ljava/lang/DoesNotExist;");
+ const RegType& ref_type_1 = cache.FromDescriptor("Ljava/lang/DoesNotExist;");
EXPECT_TRUE(ref_type_0.Equals(ref_type_1));
const RegType& unresolved_super_class = cache.FromUnresolvedSuperClass(ref_type_0);
@@ -383,10 +406,10 @@ TEST_F(RegTypeReferenceTest, UnresolvedUnintializedType) {
ArenaPool* arena_pool = Runtime::Current()->GetArenaPool();
ScopedObjectAccess soa(Thread::Current());
ScopedNullHandle<mirror::ClassLoader> loader;
- RegTypeCache cache(soa.Self(), Runtime::Current()->GetClassLinker(), arena_pool);
- const RegType& ref_type_0 = cache.FromDescriptor(loader, "Ljava/lang/DoesNotExist;");
+ RegTypeCache cache(soa.Self(), class_linker_, arena_pool, loader, dex_file_.get());
+ const RegType& ref_type_0 = cache.FromDescriptor("Ljava/lang/DoesNotExist;");
EXPECT_TRUE(ref_type_0.IsUnresolvedReference());
- const RegType& ref_type = cache.FromDescriptor(loader, "Ljava/lang/DoesNotExist;");
+ const RegType& ref_type = cache.FromDescriptor("Ljava/lang/DoesNotExist;");
EXPECT_TRUE(ref_type_0.Equals(ref_type));
// Create an uninitialized type of this unresolved type
const RegType& unresolved_unintialised = cache.Uninitialized(ref_type, 1101ull);
@@ -407,10 +430,9 @@ TEST_F(RegTypeReferenceTest, Dump) {
ArenaPool* arena_pool = Runtime::Current()->GetArenaPool();
ScopedObjectAccess soa(Thread::Current());
ScopedNullHandle<mirror::ClassLoader> loader;
- RegTypeCache cache(soa.Self(), Runtime::Current()->GetClassLinker(), arena_pool);
- const RegType& unresolved_ref = cache.FromDescriptor(loader, "Ljava/lang/DoesNotExist;");
- const RegType& unresolved_ref_another =
- cache.FromDescriptor(loader, "Ljava/lang/DoesNotExistEither;");
+ RegTypeCache cache(soa.Self(), class_linker_, arena_pool, loader, dex_file_.get());
+ const RegType& unresolved_ref = cache.FromDescriptor("Ljava/lang/DoesNotExist;");
+ const RegType& unresolved_ref_another = cache.FromDescriptor("Ljava/lang/DoesNotExistEither;");
const RegType& resolved_ref = cache.JavaLangString();
const RegType& resolved_unintialiesd = cache.Uninitialized(resolved_ref, 10);
const RegType& unresolved_unintialized = cache.Uninitialized(unresolved_ref, 12);
@@ -436,10 +458,10 @@ TEST_F(RegTypeReferenceTest, JavalangString) {
ArenaPool* arena_pool = Runtime::Current()->GetArenaPool();
ScopedObjectAccess soa(Thread::Current());
ScopedNullHandle<mirror::ClassLoader> loader;
- RegTypeCache cache(soa.Self(), Runtime::Current()->GetClassLinker(), arena_pool);
+ RegTypeCache cache(soa.Self(), class_linker_, arena_pool, loader, dex_file_.get());
const RegType& ref_type = cache.JavaLangString();
const RegType& ref_type_2 = cache.JavaLangString();
- const RegType& ref_type_3 = cache.FromDescriptor(loader, "Ljava/lang/String;");
+ const RegType& ref_type_3 = cache.FromDescriptor("Ljava/lang/String;");
EXPECT_TRUE(ref_type.Equals(ref_type_2));
EXPECT_TRUE(ref_type_2.Equals(ref_type_3));
@@ -458,29 +480,30 @@ TEST_F(RegTypeReferenceTest, JavalangObject) {
ArenaPool* arena_pool = Runtime::Current()->GetArenaPool();
ScopedObjectAccess soa(Thread::Current());
ScopedNullHandle<mirror::ClassLoader> loader;
- RegTypeCache cache(soa.Self(), Runtime::Current()->GetClassLinker(), arena_pool);
+ RegTypeCache cache(soa.Self(), class_linker_, arena_pool, loader, dex_file_.get());
const RegType& ref_type = cache.JavaLangObject();
const RegType& ref_type_2 = cache.JavaLangObject();
- const RegType& ref_type_3 = cache.FromDescriptor(loader, "Ljava/lang/Object;");
+ const RegType& ref_type_3 = cache.FromDescriptor("Ljava/lang/Object;");
EXPECT_TRUE(ref_type.Equals(ref_type_2));
EXPECT_TRUE(ref_type_3.Equals(ref_type_2));
EXPECT_EQ(ref_type.GetId(), ref_type_3.GetId());
}
+
TEST_F(RegTypeReferenceTest, Merging) {
// Tests merging logic
// String and object , LUB is object.
ScopedObjectAccess soa(Thread::Current());
ArenaPool* arena_pool = Runtime::Current()->GetArenaPool();
ScopedNullHandle<mirror::ClassLoader> loader;
- RegTypeCache cache_new(soa.Self(), Runtime::Current()->GetClassLinker(), arena_pool);
+ RegTypeCache cache_new(soa.Self(), class_linker_, arena_pool, loader, dex_file_.get());
const RegType& string = cache_new.JavaLangString();
const RegType& Object = cache_new.JavaLangObject();
EXPECT_TRUE(string.Merge(Object, &cache_new, /* verifier= */ nullptr).IsJavaLangObject());
// Merge two unresolved types.
- const RegType& ref_type_0 = cache_new.FromDescriptor(loader, "Ljava/lang/DoesNotExist;");
+ const RegType& ref_type_0 = cache_new.FromDescriptor("Ljava/lang/DoesNotExist;");
EXPECT_TRUE(ref_type_0.IsUnresolvedReference());
- const RegType& ref_type_1 = cache_new.FromDescriptor(loader, "Ljava/lang/DoesNotExistToo;");
+ const RegType& ref_type_1 = cache_new.FromDescriptor("Ljava/lang/DoesNotExistToo;");
EXPECT_FALSE(ref_type_0.Equals(ref_type_1));
const RegType& merged = ref_type_1.Merge(ref_type_0, &cache_new, /* verifier= */ nullptr);
@@ -497,7 +520,8 @@ TEST_F(RegTypeTest, MergingFloat) {
// Testing merging logic with float and float constants.
ArenaPool* arena_pool = Runtime::Current()->GetArenaPool();
ScopedObjectAccess soa(Thread::Current());
- RegTypeCache cache_new(soa.Self(), Runtime::Current()->GetClassLinker(), arena_pool);
+ ScopedNullHandle<mirror::ClassLoader> loader;
+ RegTypeCache cache_new(soa.Self(), class_linker_, arena_pool, loader, dex_file_.get());
constexpr int32_t kTestConstantValue = 10;
const RegType& float_type = cache_new.Float();
@@ -529,7 +553,8 @@ TEST_F(RegTypeTest, MergingLong) {
// Testing merging logic with long and long constants.
ArenaPool* arena_pool = Runtime::Current()->GetArenaPool();
ScopedObjectAccess soa(Thread::Current());
- RegTypeCache cache_new(soa.Self(), Runtime::Current()->GetClassLinker(), arena_pool);
+ ScopedNullHandle<mirror::ClassLoader> loader;
+ RegTypeCache cache_new(soa.Self(), class_linker_, arena_pool, loader, dex_file_.get());
constexpr int32_t kTestConstantValue = 10;
const RegType& long_lo_type = cache_new.LongLo();
@@ -588,7 +613,8 @@ TEST_F(RegTypeTest, MergingDouble) {
// Testing merging logic with double and double constants.
ArenaPool* arena_pool = Runtime::Current()->GetArenaPool();
ScopedObjectAccess soa(Thread::Current());
- RegTypeCache cache_new(soa.Self(), Runtime::Current()->GetClassLinker(), arena_pool);
+ ScopedNullHandle<mirror::ClassLoader> loader;
+ RegTypeCache cache_new(soa.Self(), class_linker_, arena_pool, loader, dex_file_.get());
constexpr int32_t kTestConstantValue = 10;
const RegType& double_lo_type = cache_new.DoubleLo();
@@ -702,7 +728,7 @@ TEST_F(RegTypeTest, MergeSemiLatticeRef) {
ScopedDisableMovingGC no_gc(soa.Self());
ScopedNullHandle<mirror::ClassLoader> loader;
- RegTypeCache cache(soa.Self(), Runtime::Current()->GetClassLinker(), arena_pool);
+ RegTypeCache cache(soa.Self(), class_linker_, arena_pool, loader, dex_file_.get());
const RegType& conflict = cache.Conflict();
const RegType& zero = cache.Zero();
@@ -710,12 +736,12 @@ TEST_F(RegTypeTest, MergeSemiLatticeRef) {
const RegType& int_type = cache.Integer();
const RegType& obj = cache.JavaLangObject();
- const RegType& obj_arr = cache.FromDescriptor(loader, "[Ljava/lang/Object;");
+ const RegType& obj_arr = cache.FromDescriptor("[Ljava/lang/Object;");
ASSERT_FALSE(obj_arr.IsUnresolvedReference());
- const RegType& unresolved_a = cache.FromDescriptor(loader, "Ldoes/not/resolve/A;");
+ const RegType& unresolved_a = cache.FromDescriptor("Ldoes/not/resolve/A;");
ASSERT_TRUE(unresolved_a.IsUnresolvedReference());
- const RegType& unresolved_b = cache.FromDescriptor(loader, "Ldoes/not/resolve/B;");
+ const RegType& unresolved_b = cache.FromDescriptor("Ldoes/not/resolve/B;");
ASSERT_TRUE(unresolved_b.IsUnresolvedReference());
const RegType& unresolved_ab = cache.FromUnresolvedMerge(unresolved_a, unresolved_b, nullptr);
ASSERT_TRUE(unresolved_ab.IsUnresolvedMergedReference());
@@ -728,25 +754,25 @@ TEST_F(RegTypeTest, MergeSemiLatticeRef) {
const RegType& uninit_unres_a_0 = cache.Uninitialized(unresolved_a, 0);
const RegType& uninit_unres_b_0 = cache.Uninitialized(unresolved_b, 0);
- const RegType& number = cache.FromDescriptor(loader, "Ljava/lang/Number;");
+ const RegType& number = cache.FromDescriptor("Ljava/lang/Number;");
ASSERT_FALSE(number.IsUnresolvedReference());
- const RegType& integer = cache.FromDescriptor(loader, "Ljava/lang/Integer;");
+ const RegType& integer = cache.FromDescriptor("Ljava/lang/Integer;");
ASSERT_FALSE(integer.IsUnresolvedReference());
const RegType& uninit_number_0 = cache.Uninitialized(number, 0u);
const RegType& uninit_integer_0 = cache.Uninitialized(integer, 0u);
- const RegType& number_arr = cache.FromDescriptor(loader, "[Ljava/lang/Number;");
+ const RegType& number_arr = cache.FromDescriptor("[Ljava/lang/Number;");
ASSERT_FALSE(number_arr.IsUnresolvedReference());
- const RegType& integer_arr = cache.FromDescriptor(loader, "[Ljava/lang/Integer;");
+ const RegType& integer_arr = cache.FromDescriptor("[Ljava/lang/Integer;");
ASSERT_FALSE(integer_arr.IsUnresolvedReference());
- const RegType& number_arr_arr = cache.FromDescriptor(loader, "[[Ljava/lang/Number;");
+ const RegType& number_arr_arr = cache.FromDescriptor("[[Ljava/lang/Number;");
ASSERT_FALSE(number_arr_arr.IsUnresolvedReference());
- const RegType& char_arr = cache.FromDescriptor(loader, "[C");
+ const RegType& char_arr = cache.FromDescriptor("[C");
ASSERT_FALSE(char_arr.IsUnresolvedReference());
- const RegType& byte_arr = cache.FromDescriptor(loader, "[B");
+ const RegType& byte_arr = cache.FromDescriptor("[B");
ASSERT_FALSE(byte_arr.IsUnresolvedReference());
const RegType& unresolved_a_num = cache.FromUnresolvedMerge(unresolved_a, number, nullptr);
@@ -1025,7 +1051,8 @@ TEST_F(RegTypeTest, ConstPrecision) {
// Tests creating primitive types types.
ArenaPool* arena_pool = Runtime::Current()->GetArenaPool();
ScopedObjectAccess soa(Thread::Current());
- RegTypeCache cache_new(soa.Self(), Runtime::Current()->GetClassLinker(), arena_pool);
+ ScopedNullHandle<mirror::ClassLoader> loader;
+ RegTypeCache cache_new(soa.Self(), class_linker_, arena_pool, loader, dex_file_.get());
const RegType& imprecise_const = cache_new.FromCat1Const(10, false);
const RegType& precise_const = cache_new.FromCat1Const(10, true);
@@ -1064,20 +1091,19 @@ TEST_F(RegTypeOOMTest, ClassJoinOOM) {
constexpr const char* kNumberArrayFive = "[[[[[Ljava/lang/Number;";
ScopedNullHandle<mirror::ClassLoader> loader;
- RegTypeCache cache(soa.Self(), Runtime::Current()->GetClassLinker(), arena_pool);
- const RegType& int_array_array = cache.FromDescriptor(loader, kIntArrayFive);
+ RegTypeCache cache(soa.Self(), class_linker_, arena_pool, loader, dex_file_.get());
+ const RegType& int_array_array = cache.FromDescriptor(kIntArrayFive);
ASSERT_TRUE(int_array_array.HasClass());
- const RegType& float_array_array = cache.FromDescriptor(loader, kFloatArrayFive);
+ const RegType& float_array_array = cache.FromDescriptor(kFloatArrayFive);
ASSERT_TRUE(float_array_array.HasClass());
// Check assumptions: the joined classes don't exist, yet.
- ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- ASSERT_TRUE(class_linker->LookupClass(soa.Self(), kNumberArrayFour, nullptr) == nullptr);
- ASSERT_TRUE(class_linker->LookupClass(soa.Self(), kNumberArrayFive, nullptr) == nullptr);
+ ASSERT_TRUE(class_linker_->LookupClass(soa.Self(), kNumberArrayFour, nullptr) == nullptr);
+ ASSERT_TRUE(class_linker_->LookupClass(soa.Self(), kNumberArrayFive, nullptr) == nullptr);
// Fill the heap.
VariableSizedHandleScope hs(soa.Self());
- FillHeap(soa.Self(), class_linker, &hs);
+ FillHeap(soa.Self(), class_linker_, &hs);
const RegType& join_type = int_array_array.Merge(float_array_array, &cache, nullptr);
ASSERT_TRUE(join_type.IsUnresolvedReference());
@@ -1100,12 +1126,18 @@ class RegTypeClassJoinTest : public RegTypeTest {
class_linker_->FindClass(soa.Self(), in2, class_loader)));
ASSERT_TRUE(c1 != nullptr);
ASSERT_TRUE(c2 != nullptr);
+ const DexFile* dex_file = &c1->GetDexFile();
+ ASSERT_EQ(dex_file, &c2->GetDexFile());
ScopedDisableMovingGC no_gc(soa.Self());
- RegTypeCache cache(soa.Self(), Runtime::Current()->GetClassLinker(), arena_pool);
- const RegType& c1_reg_type = *cache.InsertClass(in1, c1.Get());
- const RegType& c2_reg_type = *cache.InsertClass(in2, c2.Get());
+ RegTypeCache cache(soa.Self(), class_linker_, arena_pool, class_loader, dex_file);
+ const RegType& c1_reg_type = cache.FromClass(c1.Get());
+ ASSERT_TRUE(c1_reg_type.HasClass());
+ ASSERT_TRUE(c1_reg_type.GetClass() == c1.Get());
+ const RegType& c2_reg_type = cache.FromClass(c2.Get());
+ ASSERT_TRUE(c2_reg_type.HasClass());
+ ASSERT_TRUE(c2_reg_type.GetClass() == c2.Get());
const RegType& join_type = c1_reg_type.Merge(c2_reg_type, &cache, nullptr);
EXPECT_TRUE(join_type.HasClass());
@@ -1127,5 +1159,28 @@ TEST_F(RegTypeClassJoinTest, ClassJoinClassClass) {
TestClassJoin("LInterfaces$A;", "LInterfaces$B;", "Ljava/lang/Object;");
}
+TEST_F(RegTypeClassJoinTest, LookupByTypeIndex) {
+ ArenaPool* arena_pool = Runtime::Current()->GetArenaPool();
+ ScopedObjectAccess soa(Thread::Current());
+ ScopedNullHandle<mirror::ClassLoader> loader;
+ RegTypeCache cache(soa.Self(), class_linker_, arena_pool, loader, dex_file_.get());
+
+ auto get_type_index = [&](std::string_view descriptor) {
+ const dex::TypeId* type_id = dex_file_->FindTypeId(descriptor);
+ CHECK(type_id != nullptr);
+ return dex_file_->GetIndexForTypeId(*type_id);
+ };
+
+ ASSERT_EQ(&cache.Boolean(), &cache.FromTypeIndex(get_type_index("Z")));
+ ASSERT_EQ(&cache.Byte(), &cache.FromTypeIndex(get_type_index("B")));
+ ASSERT_EQ(&cache.Char(), &cache.FromTypeIndex(get_type_index("C")));
+ ASSERT_EQ(&cache.Short(), &cache.FromTypeIndex(get_type_index("S")));
+ ASSERT_EQ(&cache.Integer(), &cache.FromTypeIndex(get_type_index("I")));
+ ASSERT_EQ(&cache.LongLo(), &cache.FromTypeIndex(get_type_index("J")));
+ ASSERT_EQ(&cache.Float(), &cache.FromTypeIndex(get_type_index("F")));
+ ASSERT_EQ(&cache.DoubleLo(), &cache.FromTypeIndex(get_type_index("D")));
+ ASSERT_EQ(&cache.Conflict(), &cache.FromTypeIndex(get_type_index("V")));
+}
+
} // namespace verifier
} // namespace art