diff options
author | 2024-10-14 09:56:26 +0000 | |
---|---|---|
committer | 2024-10-17 07:08:14 +0000 | |
commit | 625356946238649c5fae5ee96c1d0c3a9acdaf8b (patch) | |
tree | d646afe7178a1a3b26c4edb5c80ac8a9635f13a9 | |
parent | 3e5cfa5a7557395123f4f4648a761d88eda358b7 (diff) |
Share `RegTypeCache` for all methods in a `Class`.
Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing
Bug: 181943478
Change-Id: Ic5e2ad1a83a9013a428b51ef39641d8a1f34cee9
-rw-r--r-- | dex2oat/verifier_deps_test.cc | 7 | ||||
-rw-r--r-- | oatdump/oatdump.cc | 38 | ||||
-rw-r--r-- | openjdkjvmti/ti_method.cc | 10 | ||||
-rw-r--r-- | runtime/verifier/class_verifier.cc | 114 | ||||
-rw-r--r-- | runtime/verifier/method_verifier.cc | 127 | ||||
-rw-r--r-- | runtime/verifier/method_verifier.h | 41 | ||||
-rw-r--r-- | runtime/verifier/reg_type_cache-inl.h | 1 | ||||
-rw-r--r-- | runtime/verifier/reg_type_cache.cc | 12 | ||||
-rw-r--r-- | runtime/verifier/reg_type_cache.h | 29 | ||||
-rw-r--r-- | runtime/verifier/reg_type_test.cc | 102 |
10 files changed, 232 insertions, 249 deletions
diff --git a/dex2oat/verifier_deps_test.cc b/dex2oat/verifier_deps_test.cc index 2cddcedcfa..46e40902de 100644 --- a/dex2oat/verifier_deps_test.cc +++ b/dex2oat/verifier_deps_test.cc @@ -37,6 +37,7 @@ #include "thread.h" #include "utils/atomic_dex_ref_map-inl.h" #include "verifier/method_verifier-inl.h" +#include "verifier/reg_type_cache.h" namespace art { namespace verifier { @@ -161,8 +162,10 @@ 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()); std::unique_ptr<MethodVerifier> verifier( MethodVerifier::CreateVerifier(soa.Self(), + ®_types, callbacks_->GetVerifierDeps(), primary_dex_file_, dex_cache_handle, @@ -171,9 +174,7 @@ class VerifierDepsTest : public CommonCompilerDriverTest { method.GetCodeItem(), method.GetIndex(), method.GetAccessFlags(), - /* can_load_classes= */ true, - /* verify to dump */ false, - /* allow_thread_suspension= */ true, + /* verify_to_dump= */ false, /* api_level= */ 0)); verifier->Verify(); soa.Self()->SetVerifierDeps(nullptr); diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index 726d6b085f..06d9e98218 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -1180,14 +1180,14 @@ class OatDumper { hs.reset(new StackHandleScope<1>(Thread::Current())); vios->Stream() << "VERIFIER TYPE ANALYSIS:\n"; ScopedIndentation indent2(vios); - verifier.reset(DumpVerifier(vios, - soa, - hs.get(), - dex_method_idx, - &dex_file, - class_def, - code_item, - method_access_flags)); + DumpVerifier(vios, + soa, + hs.get(), + dex_method_idx, + &dex_file, + class_def, + code_item, + method_access_flags); } { vios->Stream() << "OatMethodOffsets "; @@ -1493,14 +1493,14 @@ class OatDumper { code_item_accessor.HasCodeItem(); } - verifier::MethodVerifier* DumpVerifier(VariableIndentationOutputStream* vios, - ScopedObjectAccess& soa, - StackHandleScope<1>* hs, - uint32_t dex_method_idx, - const DexFile* dex_file, - const dex::ClassDef& class_def, - const dex::CodeItem* code_item, - uint32_t method_access_flags) + void DumpVerifier(VariableIndentationOutputStream* vios, + ScopedObjectAccess& soa, + StackHandleScope<1>* hs, + uint32_t dex_method_idx, + const DexFile* dex_file, + const dex::ClassDef& class_def, + const dex::CodeItem* code_item, + uint32_t method_access_flags) REQUIRES_SHARED(Locks::mutator_lock_) { if ((method_access_flags & kAccNative) == 0) { Runtime* const runtime = Runtime::Current(); @@ -1512,9 +1512,9 @@ class OatDumper { dex_method_idx, dex_cache, *options_.class_loader_); if (method == nullptr) { soa.Self()->ClearException(); - return nullptr; + return; } - return verifier::MethodVerifier::VerifyMethodAndDump( + verifier::MethodVerifier::VerifyMethodAndDump( soa.Self(), vios, dex_method_idx, @@ -1526,8 +1526,6 @@ class OatDumper { method_access_flags, /* api_level= */ 0); } - - return nullptr; } void DumpCode(VariableIndentationOutputStream* vios, diff --git a/openjdkjvmti/ti_method.cc b/openjdkjvmti/ti_method.cc index 0557234a46..6150a4692b 100644 --- a/openjdkjvmti/ti_method.cc +++ b/openjdkjvmti/ti_method.cc @@ -79,6 +79,7 @@ #include "ti_phase.h" #include "verifier/register_line-inl.h" #include "verifier/reg_type-inl.h" +#include "verifier/reg_type_cache.h" #include "verifier/method_verifier-inl.h" namespace openjdkjvmti { @@ -637,9 +638,16 @@ class CommonLocalVariableClosure : public art::Closure { art::StackHandleScope<2> hs(art::Thread::Current()); art::Handle<art::mirror::DexCache> dex_cache(hs.NewHandle(method->GetDexCache())); art::Handle<art::mirror::ClassLoader> class_loader(hs.NewHandle(method->GetClassLoader())); + art::Thread* self = art::Thread::Current(); + 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); std::unique_ptr<art::verifier::MethodVerifier> verifier( art::verifier::MethodVerifier::CalculateVerificationInfo( - art::Thread::Current(), + self, + ®_types, method, dex_cache, class_loader, diff --git a/runtime/verifier/class_verifier.cc b/runtime/verifier/class_verifier.cc index eea737608b..d6fd64e376 100644 --- a/runtime/verifier/class_verifier.cc +++ b/runtime/verifier/class_verifier.cc @@ -111,65 +111,69 @@ FailureKind ClassVerifier::VerifyClass(Thread* self, MethodVerifier::FailureData failure_data; ClassLinker* const linker = Runtime::Current()->GetClassLinker(); - for (const ClassAccessor::Method& method : accessor.GetMethods()) { - int64_t* previous_idx = &previous_method_idx[method.IsStaticOrDirect() ? 0u : 1u]; - self->AllowThreadSuspension(); - const uint32_t method_idx = method.GetIndex(); - if (method_idx == *previous_idx) { - // smali can create dex files with two encoded_methods sharing the same method_idx - // http://code.google.com/p/smali/issues/detail?id=119 - continue; - } - *previous_idx = method_idx; - std::string hard_failure_msg; - MethodVerifier::FailureData result = - MethodVerifier::VerifyMethod(self, - linker, - Runtime::Current()->GetArenaPool(), - verifier_deps, - method_idx, - dex_file, - dex_cache, - class_loader, - class_def, - method.GetCodeItem(), - method.GetAccessFlags(), - log_level, - api_level, - Runtime::Current()->IsAotCompiler(), - &hard_failure_msg); - if (result.kind == FailureKind::kHardFailure) { - if (failure_data.kind == FailureKind::kHardFailure) { - // If we logged an error before, we need a newline. - *error += "\n"; - } else { - // If we didn't log a hard failure before, print the header of the message. - *error += "Verifier rejected class "; - *error += PrettyDescriptor(dex_file->GetClassDescriptor(class_def)); - *error += ":"; + if (accessor.NumMethods() != 0u) { + ArenaPool* arena_pool = Runtime::Current()->GetArenaPool(); + RegTypeCache reg_types(self, linker, arena_pool); + for (const ClassAccessor::Method& method : accessor.GetMethods()) { + int64_t* previous_idx = &previous_method_idx[method.IsStaticOrDirect() ? 0u : 1u]; + self->AllowThreadSuspension(); + const uint32_t method_idx = method.GetIndex(); + if (method_idx == *previous_idx) { + // smali can create dex files with two encoded_methods sharing the same method_idx + // http://code.google.com/p/smali/issues/detail?id=119 + continue; } - *error += " "; - *error += hard_failure_msg; - } else if (result.kind != FailureKind::kNoFailure) { - UpdateMethodFlags(method.GetIndex(), klass, dex_cache, callbacks, result.types); - if ((result.types & VerifyError::VERIFY_ERROR_LOCKING) != 0) { - // Print a warning about expected slow-down. - // Use a string temporary to print one contiguous warning. - std::string tmp = - StringPrintf("Method %s failed lock verification and will run slower.", - dex_file->PrettyMethod(method.GetIndex()).c_str()); - if (!gPrintedDxMonitorText) { - tmp += - "\nCommon causes for lock verification issues are non-optimized dex code\n" - "and incorrect proguard optimizations."; - gPrintedDxMonitorText = true; + *previous_idx = method_idx; + std::string hard_failure_msg; + MethodVerifier::FailureData result = + MethodVerifier::VerifyMethod(self, + arena_pool, + ®_types, + verifier_deps, + method_idx, + dex_file, + dex_cache, + class_loader, + class_def, + method.GetCodeItem(), + method.GetAccessFlags(), + log_level, + api_level, + Runtime::Current()->IsAotCompiler(), + &hard_failure_msg); + if (result.kind == FailureKind::kHardFailure) { + if (failure_data.kind == FailureKind::kHardFailure) { + // If we logged an error before, we need a newline. + *error += "\n"; + } else { + // If we didn't log a hard failure before, print the header of the message. + *error += "Verifier rejected class "; + *error += PrettyDescriptor(dex_file->GetClassDescriptor(class_def)); + *error += ":"; + } + *error += " "; + *error += hard_failure_msg; + } else if (result.kind != FailureKind::kNoFailure) { + UpdateMethodFlags(method.GetIndex(), klass, dex_cache, callbacks, result.types); + if ((result.types & VerifyError::VERIFY_ERROR_LOCKING) != 0) { + // Print a warning about expected slow-down. + // Use a string temporary to print one contiguous warning. + std::string tmp = + StringPrintf("Method %s failed lock verification and will run slower.", + dex_file->PrettyMethod(method.GetIndex()).c_str()); + if (!gPrintedDxMonitorText) { + tmp += + "\nCommon causes for lock verification issues are non-optimized dex code\n" + "and incorrect proguard optimizations."; + gPrintedDxMonitorText = true; + } + LOG(WARNING) << tmp; } - LOG(WARNING) << tmp; } - } - // Merge the result for the method into the global state for the class. - failure_data.Merge(result); + // Merge the result for the method into the global state for the class. + failure_data.Merge(result); + } } uint64_t elapsed_time_microseconds = timer.Stop(); VLOG(verifier) << "VerifyClass took " << PrettyDuration(UsToNs(elapsed_time_microseconds)) diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index f464edfd34..aebf1ec5c2 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -56,6 +56,7 @@ #include "mirror/var_handle.h" #include "obj_ptr-inl.h" #include "reg_type-inl.h" +#include "reg_type_cache.h" #include "register_line-inl.h" #include "runtime.h" #include "scoped_newline.h" @@ -129,14 +130,12 @@ class MethodVerifier final : public ::art::verifier::MethodVerifier { private: MethodVerifier(Thread* self, - ClassLinker* class_linker, ArenaPool* arena_pool, + RegTypeCache* reg_types, VerifierDeps* verifier_deps, const DexFile* dex_file, const dex::CodeItem* code_item, uint32_t method_idx, - bool can_load_classes, - bool allow_thread_suspension, bool aot_mode, Handle<mirror::DexCache> dex_cache, Handle<mirror::ClassLoader> class_loader, @@ -145,15 +144,13 @@ class MethodVerifier final : public ::art::verifier::MethodVerifier { bool verify_to_dump, uint32_t api_level) REQUIRES_SHARED(Locks::mutator_lock_) : art::verifier::MethodVerifier(self, - class_linker, arena_pool, + reg_types, verifier_deps, dex_file, class_def, code_item, method_idx, - can_load_classes, - allow_thread_suspension, aot_mode), method_access_flags_(access_flags), return_type_(nullptr), @@ -163,7 +160,7 @@ class MethodVerifier final : public ::art::verifier::MethodVerifier { interesting_dex_pc_(-1), monitor_enter_dex_pcs_(nullptr), verify_to_dump_(verify_to_dump), - allow_thread_suspension_(allow_thread_suspension), + allow_thread_suspension_(reg_types->CanSuspend()), is_constructor_(false), api_level_(api_level == 0 ? std::numeric_limits<uint32_t>::max() : api_level) { } @@ -4879,30 +4876,31 @@ bool MethodVerifier<kVerifierDebug>::PotentiallyMarkRuntimeThrow() { } // namespace } // namespace impl +inline ClassLinker* MethodVerifier::GetClassLinker() const { + return reg_types_.GetClassLinker(); +} + MethodVerifier::MethodVerifier(Thread* self, - ClassLinker* class_linker, 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, - bool can_load_classes, - bool allow_thread_suspension, bool aot_mode) : self_(self), arena_stack_(arena_pool), allocator_(&arena_stack_), - reg_types_(self, class_linker, can_load_classes, allocator_, allow_thread_suspension), + reg_types_(*reg_types), reg_table_(allocator_), work_insn_idx_(dex::kDexNoIndex), dex_method_idx_(dex_method_idx), dex_file_(dex_file), class_def_(class_def), code_item_accessor_(*dex_file, code_item), - // TODO: make it designated initialization when we compile as C++20. - flags_({false, false}), - const_flags_({aot_mode, can_load_classes}), + 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), verifier_deps_(verifier_deps), link_(nullptr) { @@ -4913,8 +4911,8 @@ MethodVerifier::~MethodVerifier() { } MethodVerifier::FailureData MethodVerifier::VerifyMethod(Thread* self, - ClassLinker* class_linker, ArenaPool* arena_pool, + RegTypeCache* reg_types, VerifierDeps* verifier_deps, uint32_t method_idx, const DexFile* dex_file, @@ -4929,8 +4927,8 @@ MethodVerifier::FailureData MethodVerifier::VerifyMethod(Thread* self, std::string* hard_failure_msg) { if (VLOG_IS_ON(verifier_debug)) { return VerifyMethod<true>(self, - class_linker, arena_pool, + reg_types, verifier_deps, method_idx, dex_file, @@ -4945,8 +4943,8 @@ MethodVerifier::FailureData MethodVerifier::VerifyMethod(Thread* self, hard_failure_msg); } else { return VerifyMethod<false>(self, - class_linker, arena_pool, + reg_types, verifier_deps, method_idx, dex_file, @@ -4981,8 +4979,8 @@ static inline bool CanRuntimeHandleVerificationFailure(uint32_t encountered_fail template <bool kVerifierDebug> MethodVerifier::FailureData MethodVerifier::VerifyMethod(Thread* self, - ClassLinker* class_linker, ArenaPool* arena_pool, + RegTypeCache* reg_types, VerifierDeps* verifier_deps, uint32_t method_idx, const DexFile* dex_file, @@ -4999,20 +4997,18 @@ MethodVerifier::FailureData MethodVerifier::VerifyMethod(Thread* self, uint64_t start_ns = kTimeVerifyMethod ? NanoTime() : 0; impl::MethodVerifier<kVerifierDebug> verifier(self, - class_linker, arena_pool, + reg_types, verifier_deps, dex_file, code_item, method_idx, - /* can_load_classes= */ true, - /* allow_thread_suspension= */ true, aot_mode, dex_cache, class_loader, class_def, method_access_flags, - /* verify to dump */ false, + /* verify_to_dump= */ false, api_level); if (verifier.Verify()) { // Verification completed, however failures may be pending that didn't cause the verification @@ -5105,21 +5101,21 @@ MethodVerifier::FailureData MethodVerifier::VerifyMethod(Thread* self, MethodVerifier* MethodVerifier::CalculateVerificationInfo( Thread* self, + 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( new impl::MethodVerifier<false>(self, - Runtime::Current()->GetClassLinker(), - Runtime::Current()->GetArenaPool(), + runtime->GetArenaPool(), + reg_types, /* verifier_deps= */ nullptr, method->GetDexFile(), method->GetCodeItem(), method->GetDexMethodIndex(), - /* can_load_classes= */ false, - /* allow_thread_suspension= */ false, - Runtime::Current()->IsAotCompiler(), + runtime->IsAotCompiler(), dex_cache, class_loader, *method->GetDeclaringClass()->GetClassDef(), @@ -5128,7 +5124,7 @@ MethodVerifier* MethodVerifier::CalculateVerificationInfo( // Just use the verifier at the current skd-version. // This might affect what soft-verifier errors are reported. // Callers can then filter out relevant errors if needed. - Runtime::Current()->GetTargetSdkVersion())); + runtime->GetTargetSdkVersion())); verifier->interesting_dex_pc_ = dex_pc; verifier->Verify(); if (VLOG_IS_ON(verifier)) { @@ -5143,44 +5139,42 @@ MethodVerifier* MethodVerifier::CalculateVerificationInfo( } } -MethodVerifier* MethodVerifier::VerifyMethodAndDump(Thread* self, - VariableIndentationOutputStream* vios, - uint32_t dex_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, - uint32_t api_level) { - impl::MethodVerifier<false>* verifier = new impl::MethodVerifier<false>( +void MethodVerifier::VerifyMethodAndDump(Thread* self, + VariableIndentationOutputStream* vios, + uint32_t dex_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, + uint32_t api_level) { + Runtime* runtime = Runtime::Current(); + ClassLinker* class_linker = runtime->GetClassLinker(); + ArenaPool* arena_pool = runtime->GetArenaPool(); + RegTypeCache reg_types(self, class_linker, arena_pool); + impl::MethodVerifier<false> verifier( self, - Runtime::Current()->GetClassLinker(), - Runtime::Current()->GetArenaPool(), + arena_pool, + ®_types, /* verifier_deps= */ nullptr, dex_file, code_item, dex_method_idx, - /* can_load_classes= */ true, - /* allow_thread_suspension= */ true, - Runtime::Current()->IsAotCompiler(), + runtime->IsAotCompiler(), dex_cache, class_loader, class_def, method_access_flags, /* verify_to_dump= */ true, api_level); - verifier->Verify(); - verifier->DumpFailures(vios->Stream()); - vios->Stream() << verifier->info_messages_.str(); - // Only dump and return if no hard failures. Otherwise the verifier may be not fully initialized + verifier.Verify(); + verifier.DumpFailures(vios->Stream()); + vios->Stream() << verifier.info_messages_.str(); + // Only dump if no hard failures. Otherwise the verifier may be not fully initialized // and querying any info is dangerous/can abort. - if (verifier->flags_.have_pending_hard_failure_) { - delete verifier; - return nullptr; - } else { - verifier->Dump(vios); - return verifier; + if (!verifier.flags_.have_pending_hard_failure_) { + verifier.Dump(vios); } } @@ -5189,19 +5183,23 @@ void MethodVerifier::FindLocksAtDexPc( uint32_t dex_pc, std::vector<MethodVerifier::DexLockInfo>* monitor_enter_dex_pcs, uint32_t api_level) { - StackHandleScope<2> hs(Thread::Current()); + Thread* self = Thread::Current(); + StackHandleScope<2> hs(self); Handle<mirror::DexCache> dex_cache(hs.NewHandle(m->GetDexCache())); Handle<mirror::ClassLoader> class_loader(hs.NewHandle(m->GetClassLoader())); - impl::MethodVerifier<false> verifier(hs.Self(), - Runtime::Current()->GetClassLinker(), - Runtime::Current()->GetArenaPool(), + 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); + impl::MethodVerifier<false> verifier(self, + arena_pool, + ®_types, /* verifier_deps= */ nullptr, m->GetDexFile(), m->GetCodeItem(), m->GetDexMethodIndex(), - /* can_load_classes= */ false, - /* allow_thread_suspension= */ false, - Runtime::Current()->IsAotCompiler(), + runtime->IsAotCompiler(), dex_cache, class_loader, m->GetClassDef(), @@ -5214,6 +5212,7 @@ void MethodVerifier::FindLocksAtDexPc( } MethodVerifier* MethodVerifier::CreateVerifier(Thread* self, + RegTypeCache* reg_types, VerifierDeps* verifier_deps, const DexFile* dex_file, Handle<mirror::DexCache> dex_cache, @@ -5222,19 +5221,15 @@ MethodVerifier* MethodVerifier::CreateVerifier(Thread* self, const dex::CodeItem* code_item, uint32_t method_idx, uint32_t access_flags, - bool can_load_classes, bool verify_to_dump, - bool allow_thread_suspension, uint32_t api_level) { return new impl::MethodVerifier<false>(self, - Runtime::Current()->GetClassLinker(), Runtime::Current()->GetArenaPool(), + reg_types, verifier_deps, dex_file, code_item, method_idx, - can_load_classes, - allow_thread_suspension, Runtime::Current()->IsAotCompiler(), dex_cache, class_loader, diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h index 5caa0ba363..e12a2f8fb1 100644 --- a/runtime/verifier/method_verifier.h +++ b/runtime/verifier/method_verifier.h @@ -32,7 +32,6 @@ #include "dex/method_reference.h" #include "handle.h" #include "instruction_flags.h" -#include "reg_type_cache.h" #include "register_line.h" #include "verifier_enums.h" @@ -51,6 +50,7 @@ struct CodeItem; } // namespace dex namespace mirror { +class ClassLoader; class DexCache; } // namespace mirror @@ -60,6 +60,7 @@ class MethodVerifier; class RegisterLine; using RegisterLineArenaUniquePtr = std::unique_ptr<RegisterLine, RegisterLineArenaDelete>; class RegType; +class RegTypeCache; struct ScopedNewLine; class VerifierDeps; @@ -97,21 +98,22 @@ class PcToRegisterLineTable { // The verifier class MethodVerifier { public: - EXPORT static MethodVerifier* VerifyMethodAndDump(Thread* self, - VariableIndentationOutputStream* vios, - 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, - uint32_t api_level) + EXPORT static void VerifyMethodAndDump(Thread* self, + VariableIndentationOutputStream* vios, + 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, + uint32_t api_level) REQUIRES_SHARED(Locks::mutator_lock_); // Calculates the type information at the given `dex_pc`. // No classes will be loaded. EXPORT static MethodVerifier* CalculateVerificationInfo(Thread* self, + RegTypeCache* reg_types, ArtMethod* method, Handle<mirror::DexCache> dex_cache, Handle<mirror::ClassLoader> class_loader, @@ -175,9 +177,7 @@ class MethodVerifier { return encountered_failure_types_; } - ClassLinker* GetClassLinker() const { - return reg_types_.GetClassLinker(); - } + ClassLinker* GetClassLinker() const; bool IsAotMode() const { return const_flags_.aot_mode_; @@ -193,15 +193,13 @@ class MethodVerifier { protected: MethodVerifier(Thread* self, - ClassLinker* class_linker, 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, - bool can_load_classes, - bool allow_thread_suspension, bool aot_mode) REQUIRES_SHARED(Locks::mutator_lock_); @@ -227,8 +225,8 @@ class MethodVerifier { * for code flow problems. */ static FailureData VerifyMethod(Thread* self, - ClassLinker* class_linker, ArenaPool* arena_pool, + RegTypeCache* reg_types, VerifierDeps* verifier_deps, uint32_t method_idx, const DexFile* dex_file, @@ -245,8 +243,8 @@ class MethodVerifier { template <bool kVerifierDebug> static FailureData VerifyMethod(Thread* self, - ClassLinker* class_linker, ArenaPool* arena_pool, + RegTypeCache* reg_types, VerifierDeps* verifier_deps, uint32_t method_idx, const DexFile* dex_file, @@ -267,6 +265,7 @@ class MethodVerifier { // has an irrecoverable corruption. virtual bool Verify() REQUIRES_SHARED(Locks::mutator_lock_) = 0; static MethodVerifier* CreateVerifier(Thread* self, + RegTypeCache* reg_types, VerifierDeps* verifier_deps, const DexFile* dex_file, Handle<mirror::DexCache> dex_cache, @@ -275,9 +274,7 @@ class MethodVerifier { const dex::CodeItem* code_item, uint32_t method_idx, uint32_t access_flags, - bool can_load_classes, bool verify_to_dump, - bool allow_thread_suspension, uint32_t api_level) REQUIRES_SHARED(Locks::mutator_lock_); @@ -290,7 +287,7 @@ class MethodVerifier { ArenaStack arena_stack_; ScopedArenaAllocator allocator_; - RegTypeCache reg_types_; + RegTypeCache& reg_types_; // TODO: Change to a pointer in a separate CL. PcToRegisterLineTable reg_table_; diff --git a/runtime/verifier/reg_type_cache-inl.h b/runtime/verifier/reg_type_cache-inl.h index addf958472..40abf27041 100644 --- a/runtime/verifier/reg_type_cache-inl.h +++ b/runtime/verifier/reg_type_cache-inl.h @@ -18,7 +18,6 @@ #define ART_RUNTIME_VERIFIER_REG_TYPE_CACHE_INL_H_ #include "base/bit_vector-inl.h" -#include "class_linker.h" #include "class_root-inl.h" #include "mirror/class-inl.h" #include "mirror/method_handle_impl.h" diff --git a/runtime/verifier/reg_type_cache.cc b/runtime/verifier/reg_type_cache.cc index 71a6f3f318..b435b01d02 100644 --- a/runtime/verifier/reg_type_cache.cc +++ b/runtime/verifier/reg_type_cache.cc @@ -283,15 +283,17 @@ const RegType& RegTypeCache::FromClass(const char* descriptor, RegTypeCache::RegTypeCache(Thread* self, ClassLinker* class_linker, + ArenaPool* arena_pool, bool can_load_classes, - ScopedArenaAllocator& allocator, bool can_suspend) - : entries_(allocator.Adapter(kArenaAllocVerifier)), - klass_entries_(allocator.Adapter(kArenaAllocVerifier)), - allocator_(allocator), + : arena_stack_(arena_pool), + allocator_(&arena_stack_), + entries_(allocator_.Adapter(kArenaAllocVerifier)), + klass_entries_(allocator_.Adapter(kArenaAllocVerifier)), handles_(self), class_linker_(class_linker), - can_load_classes_(can_load_classes) { + 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); diff --git a/runtime/verifier/reg_type_cache.h b/runtime/verifier/reg_type_cache.h index d9d3ddc2a2..106d12340a 100644 --- a/runtime/verifier/reg_type_cache.h +++ b/runtime/verifier/reg_type_cache.h @@ -66,11 +66,20 @@ static constexpr size_t kDefaultArenaBitVectorBytes = 8; class RegTypeCache { public: - RegTypeCache(Thread* self, - ClassLinker* class_linker, - bool can_load_classes, - ScopedArenaAllocator& allocator, - bool can_suspend = true); + EXPORT RegTypeCache(Thread* self, + ClassLinker* class_linker, + ArenaPool* arena_pool, + bool can_load_classes = true, + bool can_suspend = true); + + bool CanLoadClasses() const { + return can_load_classes_; + } + + bool CanSuspend() const { + return can_suspend_; + } + const art::verifier::RegType& GetFromId(uint16_t id) const; // Find a RegType, returns null if not found. const RegType* FindClass(ObjPtr<mirror::Class> klass, bool precise) const @@ -195,15 +204,16 @@ class RegTypeCache { // verifier and return a string view. std::string_view AddString(const std::string_view& str); + // Arena allocator. + ArenaStack arena_stack_; + ScopedArenaAllocator allocator_; + // The actual storage for the RegTypes. ScopedArenaVector<const RegType*> entries_; // Fast lookup for quickly finding entries that have a matching class. ScopedArenaVector<std::pair<Handle<mirror::Class>, const RegType*>> klass_entries_; - // Arena allocator. - ScopedArenaAllocator& allocator_; - // Handle scope containing classes. VariableSizedHandleScope handles_; ScopedNullHandle<mirror::Class> null_handle_; @@ -213,6 +223,9 @@ class RegTypeCache { // Whether or not we're allowed to load classes. const bool can_load_classes_; + // Whether or not we're allowed to suspend. + const bool can_suspend_; + DISALLOW_COPY_AND_ASSIGN(RegTypeCache); }; diff --git a/runtime/verifier/reg_type_test.cc b/runtime/verifier/reg_type_test.cc index b9d618f16e..ec7fc45e4f 100644 --- a/runtime/verifier/reg_type_test.cc +++ b/runtime/verifier/reg_type_test.cc @@ -53,11 +53,9 @@ class RegTypeTest : public CommonRuntimeTest { TEST_F(RegTypeTest, ConstLoHi) { // Tests creating primitive types types. - ArenaStack stack(Runtime::Current()->GetArenaPool()); - ScopedArenaAllocator allocator(&stack); + ArenaPool* arena_pool = Runtime::Current()->GetArenaPool(); ScopedObjectAccess soa(Thread::Current()); - RegTypeCache cache( - soa.Self(), Runtime::Current()->GetClassLinker(), /* can_load_classes= */ true, allocator); + RegTypeCache cache(soa.Self(), Runtime::Current()->GetClassLinker(), arena_pool); 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); @@ -78,11 +76,9 @@ TEST_F(RegTypeTest, ConstLoHi) { } TEST_F(RegTypeTest, Pairs) { - ArenaStack stack(Runtime::Current()->GetArenaPool()); - ScopedArenaAllocator allocator(&stack); + ArenaPool* arena_pool = Runtime::Current()->GetArenaPool(); ScopedObjectAccess soa(Thread::Current()); - RegTypeCache cache( - soa.Self(), Runtime::Current()->GetClassLinker(), /* can_load_classes= */ true, allocator); + RegTypeCache cache(soa.Self(), Runtime::Current()->GetClassLinker(), arena_pool); 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); @@ -105,11 +101,9 @@ TEST_F(RegTypeTest, Pairs) { } TEST_F(RegTypeTest, Primitives) { - ArenaStack stack(Runtime::Current()->GetArenaPool()); - ScopedArenaAllocator allocator(&stack); + ArenaPool* arena_pool = Runtime::Current()->GetArenaPool(); ScopedObjectAccess soa(Thread::Current()); - RegTypeCache cache( - soa.Self(), Runtime::Current()->GetClassLinker(), /* can_load_classes= */ true, allocator); + RegTypeCache cache(soa.Self(), Runtime::Current()->GetClassLinker(), arena_pool); const RegType& bool_reg_type = cache.Boolean(); EXPECT_FALSE(bool_reg_type.IsUndefined()); @@ -381,12 +375,10 @@ class RegTypeReferenceTest : public RegTypeTest {}; TEST_F(RegTypeReferenceTest, JavaLangObjectImprecise) { // Tests matching precisions. A reference type that was created precise doesn't // match the one that is imprecise. - ArenaStack stack(Runtime::Current()->GetArenaPool()); - ScopedArenaAllocator allocator(&stack); + ArenaPool* arena_pool = Runtime::Current()->GetArenaPool(); ScopedObjectAccess soa(Thread::Current()); ScopedNullHandle<mirror::ClassLoader> loader; - RegTypeCache cache( - soa.Self(), Runtime::Current()->GetClassLinker(), /* can_load_classes= */ true, allocator); + RegTypeCache cache(soa.Self(), Runtime::Current()->GetClassLinker(), arena_pool); const RegType& imprecise_obj = cache.JavaLangObject(false); const RegType& precise_obj = cache.JavaLangObject(true); const RegType& precise_obj_2 = PreciseJavaLangObjectFromDescriptor(&cache, loader); @@ -400,12 +392,10 @@ TEST_F(RegTypeReferenceTest, JavaLangObjectImprecise) { TEST_F(RegTypeReferenceTest, UnresolvedType) { // Tests creating unresolved types. Miss for the first time asking the cache and // a hit second time. - ArenaStack stack(Runtime::Current()->GetArenaPool()); - ScopedArenaAllocator allocator(&stack); + ArenaPool* arena_pool = Runtime::Current()->GetArenaPool(); ScopedObjectAccess soa(Thread::Current()); ScopedNullHandle<mirror::ClassLoader> loader; - RegTypeCache cache( - soa.Self(), Runtime::Current()->GetClassLinker(), /* can_load_classes= */ true, allocator); + RegTypeCache cache(soa.Self(), Runtime::Current()->GetClassLinker(), arena_pool); const RegType& ref_type_0 = cache.FromDescriptor(loader, "Ljava/lang/DoesNotExist;"); EXPECT_TRUE(ref_type_0.IsUnresolvedReference()); EXPECT_TRUE(ref_type_0.IsNonZeroReferenceTypes()); @@ -420,12 +410,10 @@ TEST_F(RegTypeReferenceTest, UnresolvedType) { TEST_F(RegTypeReferenceTest, UnresolvedUnintializedType) { // Tests creating types uninitialized types from unresolved types. - ArenaStack stack(Runtime::Current()->GetArenaPool()); - ScopedArenaAllocator allocator(&stack); + ArenaPool* arena_pool = Runtime::Current()->GetArenaPool(); ScopedObjectAccess soa(Thread::Current()); ScopedNullHandle<mirror::ClassLoader> loader; - RegTypeCache cache( - soa.Self(), Runtime::Current()->GetClassLinker(), /* can_load_classes= */ true, allocator); + RegTypeCache cache(soa.Self(), Runtime::Current()->GetClassLinker(), arena_pool); const RegType& ref_type_0 = cache.FromDescriptor(loader, "Ljava/lang/DoesNotExist;"); EXPECT_TRUE(ref_type_0.IsUnresolvedReference()); const RegType& ref_type = cache.FromDescriptor(loader, "Ljava/lang/DoesNotExist;"); @@ -446,12 +434,10 @@ TEST_F(RegTypeReferenceTest, UnresolvedUnintializedType) { TEST_F(RegTypeReferenceTest, Dump) { // Tests types for proper Dump messages. - ArenaStack stack(Runtime::Current()->GetArenaPool()); - ScopedArenaAllocator allocator(&stack); + ArenaPool* arena_pool = Runtime::Current()->GetArenaPool(); ScopedObjectAccess soa(Thread::Current()); ScopedNullHandle<mirror::ClassLoader> loader; - RegTypeCache cache( - soa.Self(), Runtime::Current()->GetClassLinker(), /* can_load_classes= */ true, allocator); + 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;"); @@ -477,12 +463,10 @@ TEST_F(RegTypeReferenceTest, JavalangString) { // Add a class to the cache then look for the same class and make sure it is a // Hit the second time. Then check for the same effect when using // The JavaLangObject method instead of FromDescriptor. String class is final. - ArenaStack stack(Runtime::Current()->GetArenaPool()); - ScopedArenaAllocator allocator(&stack); + ArenaPool* arena_pool = Runtime::Current()->GetArenaPool(); ScopedObjectAccess soa(Thread::Current()); ScopedNullHandle<mirror::ClassLoader> loader; - RegTypeCache cache( - soa.Self(), Runtime::Current()->GetClassLinker(), /* can_load_classes= */ true, allocator); + RegTypeCache cache(soa.Self(), Runtime::Current()->GetClassLinker(), arena_pool); const RegType& ref_type = cache.JavaLangString(); const RegType& ref_type_2 = cache.JavaLangString(); const RegType& ref_type_3 = cache.FromDescriptor(loader, "Ljava/lang/String;"); @@ -501,12 +485,10 @@ TEST_F(RegTypeReferenceTest, JavalangObject) { // Add a class to the cache then look for the same class and make sure it is a // Hit the second time. Then I am checking for the same effect when using // The JavaLangObject method instead of FromDescriptor. Object Class in not final. - ArenaStack stack(Runtime::Current()->GetArenaPool()); - ScopedArenaAllocator allocator(&stack); + ArenaPool* arena_pool = Runtime::Current()->GetArenaPool(); ScopedObjectAccess soa(Thread::Current()); ScopedNullHandle<mirror::ClassLoader> loader; - RegTypeCache cache( - soa.Self(), Runtime::Current()->GetClassLinker(), /* can_load_classes= */ true, allocator); + RegTypeCache cache(soa.Self(), Runtime::Current()->GetClassLinker(), arena_pool); const RegType& ref_type = cache.JavaLangObject(true); const RegType& ref_type_2 = cache.JavaLangObject(true); const RegType& ref_type_3 = PreciseJavaLangObjectFromDescriptor(&cache, loader); @@ -519,11 +501,9 @@ TEST_F(RegTypeReferenceTest, Merging) { // Tests merging logic // String and object , LUB is object. ScopedObjectAccess soa(Thread::Current()); - ArenaStack stack(Runtime::Current()->GetArenaPool()); - ScopedArenaAllocator allocator(&stack); + ArenaPool* arena_pool = Runtime::Current()->GetArenaPool(); ScopedNullHandle<mirror::ClassLoader> loader; - RegTypeCache cache_new( - soa.Self(), Runtime::Current()->GetClassLinker(), /* can_load_classes= */ true, allocator); + RegTypeCache cache_new(soa.Self(), Runtime::Current()->GetClassLinker(), arena_pool); const RegType& string = cache_new.JavaLangString(); const RegType& Object = cache_new.JavaLangObject(true); EXPECT_TRUE(string.Merge(Object, &cache_new, /* verifier= */ nullptr).IsJavaLangObject()); @@ -545,11 +525,9 @@ TEST_F(RegTypeReferenceTest, Merging) { TEST_F(RegTypeTest, MergingFloat) { // Testing merging logic with float and float constants. - ArenaStack stack(Runtime::Current()->GetArenaPool()); - ScopedArenaAllocator allocator(&stack); + ArenaPool* arena_pool = Runtime::Current()->GetArenaPool(); ScopedObjectAccess soa(Thread::Current()); - RegTypeCache cache_new( - soa.Self(), Runtime::Current()->GetClassLinker(), /* can_load_classes= */ true, allocator); + RegTypeCache cache_new(soa.Self(), Runtime::Current()->GetClassLinker(), arena_pool); constexpr int32_t kTestConstantValue = 10; const RegType& float_type = cache_new.Float(); @@ -579,11 +557,9 @@ TEST_F(RegTypeTest, MergingFloat) { TEST_F(RegTypeTest, MergingLong) { // Testing merging logic with long and long constants. - ArenaStack stack(Runtime::Current()->GetArenaPool()); - ScopedArenaAllocator allocator(&stack); + ArenaPool* arena_pool = Runtime::Current()->GetArenaPool(); ScopedObjectAccess soa(Thread::Current()); - RegTypeCache cache_new( - soa.Self(), Runtime::Current()->GetClassLinker(), /* can_load_classes= */ true, allocator); + RegTypeCache cache_new(soa.Self(), Runtime::Current()->GetClassLinker(), arena_pool); constexpr int32_t kTestConstantValue = 10; const RegType& long_lo_type = cache_new.LongLo(); @@ -640,11 +616,9 @@ TEST_F(RegTypeTest, MergingLong) { TEST_F(RegTypeTest, MergingDouble) { // Testing merging logic with double and double constants. - ArenaStack stack(Runtime::Current()->GetArenaPool()); - ScopedArenaAllocator allocator(&stack); + ArenaPool* arena_pool = Runtime::Current()->GetArenaPool(); ScopedObjectAccess soa(Thread::Current()); - RegTypeCache cache_new( - soa.Self(), Runtime::Current()->GetClassLinker(), /* can_load_classes= */ true, allocator); + RegTypeCache cache_new(soa.Self(), Runtime::Current()->GetClassLinker(), arena_pool); constexpr int32_t kTestConstantValue = 10; const RegType& double_lo_type = cache_new.DoubleLo(); @@ -752,15 +726,13 @@ TEST_F(RegTypeTest, MergeSemiLatticeRef) { // | // 0 - ArenaStack stack(Runtime::Current()->GetArenaPool()); - ScopedArenaAllocator allocator(&stack); + ArenaPool* arena_pool = Runtime::Current()->GetArenaPool(); ScopedObjectAccess soa(Thread::Current()); ScopedDisableMovingGC no_gc(soa.Self()); ScopedNullHandle<mirror::ClassLoader> loader; - RegTypeCache cache( - soa.Self(), Runtime::Current()->GetClassLinker(), /* can_load_classes= */ true, allocator); + RegTypeCache cache(soa.Self(), Runtime::Current()->GetClassLinker(), arena_pool); const RegType& conflict = cache.Conflict(); const RegType& zero = cache.Zero(); @@ -1081,11 +1053,9 @@ TEST_F(RegTypeTest, MergeSemiLatticeRef) { TEST_F(RegTypeTest, ConstPrecision) { // Tests creating primitive types types. - ArenaStack stack(Runtime::Current()->GetArenaPool()); - ScopedArenaAllocator allocator(&stack); + ArenaPool* arena_pool = Runtime::Current()->GetArenaPool(); ScopedObjectAccess soa(Thread::Current()); - RegTypeCache cache_new( - soa.Self(), Runtime::Current()->GetClassLinker(), /* can_load_classes= */ true, allocator); + RegTypeCache cache_new(soa.Self(), Runtime::Current()->GetClassLinker(), arena_pool); const RegType& imprecise_const = cache_new.FromCat1Const(10, false); const RegType& precise_const = cache_new.FromCat1Const(10, true); @@ -1110,8 +1080,7 @@ TEST_F(RegTypeOOMTest, ClassJoinOOM) { // Tests that we don't abort with OOMs. - ArenaStack stack(Runtime::Current()->GetArenaPool()); - ScopedArenaAllocator allocator(&stack); + ArenaPool* arena_pool = Runtime::Current()->GetArenaPool(); ScopedObjectAccess soa(Thread::Current()); ScopedDisableMovingGC no_gc(soa.Self()); @@ -1125,8 +1094,7 @@ TEST_F(RegTypeOOMTest, ClassJoinOOM) { constexpr const char* kNumberArrayFive = "[[[[[Ljava/lang/Number;"; ScopedNullHandle<mirror::ClassLoader> loader; - RegTypeCache cache( - soa.Self(), Runtime::Current()->GetClassLinker(), /* can_load_classes= */ true, allocator); + RegTypeCache cache(soa.Self(), Runtime::Current()->GetClassLinker(), arena_pool); const RegType& int_array_array = cache.FromDescriptor(loader, kIntArrayFive); ASSERT_TRUE(int_array_array.HasClass()); const RegType& float_array_array = cache.FromDescriptor(loader, kFloatArrayFive); @@ -1148,8 +1116,7 @@ TEST_F(RegTypeOOMTest, ClassJoinOOM) { class RegTypeClassJoinTest : public RegTypeTest { protected: void TestClassJoin(const char* in1, const char* in2, const char* out) { - ArenaStack stack(Runtime::Current()->GetArenaPool()); - ScopedArenaAllocator allocator(&stack); + ArenaPool* arena_pool = Runtime::Current()->GetArenaPool(); ScopedObjectAccess soa(Thread::Current()); jobject jclass_loader = LoadDex("Interfaces"); @@ -1166,8 +1133,7 @@ class RegTypeClassJoinTest : public RegTypeTest { ScopedDisableMovingGC no_gc(soa.Self()); - RegTypeCache cache( - soa.Self(), Runtime::Current()->GetClassLinker(), /* can_load_classes= */ true, allocator); + RegTypeCache cache(soa.Self(), Runtime::Current()->GetClassLinker(), arena_pool); const RegType& c1_reg_type = *cache.InsertClass(in1, c1.Get(), false); const RegType& c2_reg_type = *cache.InsertClass(in2, c2.Get(), false); |