diff options
author | Nicolas Geoffray <ngeoffray@google.com> | 2021-07-14 14:59:25 +0100 |
---|---|---|
committer | Nicolas Geoffray <ngeoffray@google.com> | 2021-07-14 17:13:08 +0000 |
commit | 9e050ab1a061d9660eb0c1daa01a823ad75b0f05 (patch) | |
tree | 714f2ba3b11406310416e85357f45450634846b2 | |
parent | 4f990714b13e0b4446305a5411648a1a9ae42a7a (diff) | |
download | art-android-s-beta-4.tar.gz |
Remove the need of VerifiedMethod in the compiler.android-s-beta-4android-s-beta-3android-s-beta-4
The compiler only needs to know if a method is compilable or not. So
just record a set of uncompilable methods (in some cases, we cannot have
an ArtMethod, but the method can still be compiled).
Test: test.py
Bug: 28313047
Change-Id: Ic4235bc8160ec91daa5ebf6504741089b43e99cb
25 files changed, 133 insertions, 516 deletions
diff --git a/compiler/Android.bp b/compiler/Android.bp index 6b74f77b73..e579e36a72 100644 --- a/compiler/Android.bp +++ b/compiler/Android.bp @@ -36,7 +36,6 @@ art_cc_defaults { "compiled_method.cc", "debug/elf_debug_writer.cc", "dex/inline_method_analyser.cc", - "dex/verified_method.cc", "dex/verification_results.cc", "driver/compiled_method_storage.cc", "driver/compiler_options.cc", diff --git a/compiler/common_compiler_test.cc b/compiler/common_compiler_test.cc index 9170a8555a..1b69f2a1d4 100644 --- a/compiler/common_compiler_test.cc +++ b/compiler/common_compiler_test.cc @@ -209,8 +209,7 @@ void CommonCompilerTestImpl::OverrideInstructionSetFeatures(InstructionSet instr void CommonCompilerTestImpl::SetUpRuntimeOptionsImpl() { compiler_options_.reset(new CompilerOptions); - verification_results_.reset(new VerificationResults(compiler_options_.get())); - + verification_results_.reset(new VerificationResults()); ApplyInstructionSet(); } @@ -251,9 +250,6 @@ void CommonCompilerTestImpl::CompileMethod(ArtMethod* method) { dex_file, dex_cache); } else { - verification_results_->AddDexFile(&dex_file); - verification_results_->CreateVerifiedMethodFor( - MethodReference(&dex_file, method->GetDexMethodIndex())); compiled_method = compiler->Compile(method->GetCodeItem(), method->GetAccessFlags(), method->GetInvokeType(), diff --git a/compiler/dex/verification_results.cc b/compiler/dex/verification_results.cc index 6241ff3c6c..b819d0effa 100644 --- a/compiler/dex/verification_results.cc +++ b/compiler/dex/verification_results.cc @@ -20,97 +20,19 @@ #include "base/mutex-inl.h" #include "base/stl_util.h" -#include "driver/compiler_options.h" #include "runtime.h" #include "thread-current-inl.h" #include "thread.h" -#include "utils/atomic_dex_ref_map-inl.h" -#include "verified_method.h" -#include "verifier/method_verifier-inl.h" namespace art { -VerificationResults::VerificationResults(const CompilerOptions* compiler_options) - : compiler_options_(compiler_options), - verified_methods_lock_("compiler verified methods lock"), +VerificationResults::VerificationResults() + : uncompilable_methods_lock_("compiler uncompilable methods lock"), rejected_classes_lock_("compiler rejected classes lock") {} -VerificationResults::~VerificationResults() { - WriterMutexLock mu(Thread::Current(), verified_methods_lock_); - STLDeleteValues(&verified_methods_); - atomic_verified_methods_.Visit([](const DexFileReference& ref ATTRIBUTE_UNUSED, - const VerifiedMethod* method) { - delete method; - }); -} - -void VerificationResults::ProcessVerifiedMethod(verifier::MethodVerifier* method_verifier) { - DCHECK(method_verifier != nullptr); - MethodReference ref = method_verifier->GetMethodReference(); - std::unique_ptr<const VerifiedMethod> verified_method(VerifiedMethod::Create(method_verifier)); - if (verified_method == nullptr) { - // We'll punt this later. - return; - } - AtomicMap::InsertResult result = atomic_verified_methods_.Insert(ref, - /*expected*/ nullptr, - verified_method.get()); - const VerifiedMethod* existing = nullptr; - bool inserted; - if (result != AtomicMap::kInsertResultInvalidDexFile) { - inserted = (result == AtomicMap::kInsertResultSuccess); - if (!inserted) { - // Rare case. - CHECK(atomic_verified_methods_.Get(ref, &existing)); - CHECK_NE(verified_method.get(), existing); - } - } else { - WriterMutexLock mu(Thread::Current(), verified_methods_lock_); - auto it = verified_methods_.find(ref); - inserted = it == verified_methods_.end(); - if (inserted) { - verified_methods_.Put(ref, verified_method.get()); - DCHECK(verified_methods_.find(ref) != verified_methods_.end()); - } else { - existing = it->second; - } - } - if (inserted) { - // Successfully added, release the unique_ptr since we no longer have ownership. - DCHECK_EQ(GetVerifiedMethod(ref), verified_method.get()); - verified_method.release(); // NOLINT b/117926937 - } else { - // TODO: Investigate why are we doing the work again for this method and try to avoid it. - LOG(WARNING) << "Method processed more than once: " << ref.PrettyMethod(); - // Let the unique_ptr delete the new verified method since there was already an existing one - // registered. It is unsafe to replace the existing one since the JIT may be using it to - // generate a native GC map. - } -} - -const VerifiedMethod* VerificationResults::GetVerifiedMethod(MethodReference ref) const { - const VerifiedMethod* ret = nullptr; - if (atomic_verified_methods_.Get(ref, &ret)) { - return ret; - } - ReaderMutexLock mu(Thread::Current(), verified_methods_lock_); - auto it = verified_methods_.find(ref); - return (it != verified_methods_.end()) ? it->second : nullptr; -} - -void VerificationResults::CreateVerifiedMethodFor(MethodReference ref) { - // This method should only be called for classes verified at compile time, - // which have no verifier error, nor has methods that we know will throw - // at runtime. - std::unique_ptr<VerifiedMethod> verified_method = std::make_unique<VerifiedMethod>( - /* encountered_error_types= */ 0, /* has_runtime_throw= */ false); - if (atomic_verified_methods_.Insert(ref, - /*expected*/ nullptr, - verified_method.get()) == - AtomicMap::InsertResult::kInsertResultSuccess) { - verified_method.release(); // NOLINT b/117926937 - } -} +// Non-inline version of the destructor, as it does some implicit work not worth +// inlining. +VerificationResults::~VerificationResults() {} void VerificationResults::AddRejectedClass(ClassReference ref) { { @@ -122,38 +44,21 @@ void VerificationResults::AddRejectedClass(ClassReference ref) { bool VerificationResults::IsClassRejected(ClassReference ref) const { ReaderMutexLock mu(Thread::Current(), rejected_classes_lock_); - return (rejected_classes_.find(ref) != rejected_classes_.end()); + return rejected_classes_.find(ref) != rejected_classes_.end(); } -bool VerificationResults::IsCandidateForCompilation(MethodReference&, - const uint32_t access_flags) const { - if (!compiler_options_->IsAotCompilationEnabled()) { - return false; - } - // Don't compile class initializers unless kEverything. - if ((compiler_options_->GetCompilerFilter() != CompilerFilter::kEverything) && - ((access_flags & kAccConstructor) != 0) && ((access_flags & kAccStatic) != 0)) { - return false; +void VerificationResults::AddUncompilableMethod(MethodReference ref) { + { + WriterMutexLock mu(Thread::Current(), uncompilable_methods_lock_); + uncompilable_methods_.insert(ref); } - return true; + DCHECK(IsUncompilableMethod(ref)); } -void VerificationResults::AddDexFile(const DexFile* dex_file) { - atomic_verified_methods_.AddDexFile(dex_file); - WriterMutexLock mu(Thread::Current(), verified_methods_lock_); - // There can be some verified methods that are already registered for the dex_file since we set - // up well known classes earlier. Remove these and put them in the array so that we don't - // accidentally miss seeing them. - for (auto it = verified_methods_.begin(); it != verified_methods_.end(); ) { - MethodReference ref = it->first; - if (ref.dex_file == dex_file) { - CHECK(atomic_verified_methods_.Insert(ref, nullptr, it->second) == - AtomicMap::kInsertResultSuccess); - it = verified_methods_.erase(it); - } else { - ++it; - } - } +bool VerificationResults::IsUncompilableMethod(MethodReference ref) const { + ReaderMutexLock mu(Thread::Current(), uncompilable_methods_lock_); + return uncompilable_methods_.find(ref) != uncompilable_methods_.end(); } + } // namespace art diff --git a/compiler/dex/verification_results.h b/compiler/dex/verification_results.h index 04c4fa65e6..b294ed3020 100644 --- a/compiler/dex/verification_results.h +++ b/compiler/dex/verification_results.h @@ -17,65 +17,35 @@ #ifndef ART_COMPILER_DEX_VERIFICATION_RESULTS_H_ #define ART_COMPILER_DEX_VERIFICATION_RESULTS_H_ -#include <stdint.h> #include <set> -#include "base/dchecked_vector.h" #include "base/macros.h" #include "base/mutex.h" -#include "base/safe_map.h" #include "dex/class_reference.h" #include "dex/method_reference.h" -#include "utils/atomic_dex_ref_map.h" namespace art { namespace verifier { -class MethodVerifier; class VerifierDepsTest; } // namespace verifier -class CompilerOptions; -class VerifiedMethod; - // Used by CompilerCallbacks to track verification information from the Runtime. class VerificationResults { public: - explicit VerificationResults(const CompilerOptions* compiler_options); + VerificationResults(); ~VerificationResults(); - void ProcessVerifiedMethod(verifier::MethodVerifier* method_verifier) - REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!verified_methods_lock_); - - void CreateVerifiedMethodFor(MethodReference ref) - REQUIRES(!verified_methods_lock_); - - const VerifiedMethod* GetVerifiedMethod(MethodReference ref) const - REQUIRES(!verified_methods_lock_); - void AddRejectedClass(ClassReference ref) REQUIRES(!rejected_classes_lock_); bool IsClassRejected(ClassReference ref) const REQUIRES(!rejected_classes_lock_); - bool IsCandidateForCompilation(MethodReference& method_ref, const uint32_t access_flags) const; - - // Add a dex file to enable using the atomic map. - void AddDexFile(const DexFile* dex_file) REQUIRES(!verified_methods_lock_); + void AddUncompilableMethod(MethodReference ref) REQUIRES(!uncompilable_methods_lock_); + bool IsUncompilableMethod(MethodReference ref) const REQUIRES(!uncompilable_methods_lock_); private: - // Verified methods. The method array is fixed to avoid needing a lock to extend it. - using AtomicMap = AtomicDexRefMap<MethodReference, const VerifiedMethod*>; - using VerifiedMethodMap = SafeMap<MethodReference, const VerifiedMethod*>; - - VerifiedMethodMap verified_methods_ GUARDED_BY(verified_methods_lock_); - const CompilerOptions* const compiler_options_; - - // Dex2oat can add dex files to atomic_verified_methods_ to avoid locking when calling - // GetVerifiedMethod. - AtomicMap atomic_verified_methods_; - // TODO: External locking during CompilerDriver::PreCompile(), no locking during compilation. - mutable ReaderWriterMutex verified_methods_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER; + mutable ReaderWriterMutex uncompilable_methods_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER; + std::set<MethodReference> uncompilable_methods_ GUARDED_BY(uncompilable_methods_lock_); // Rejected classes. // TODO: External locking during CompilerDriver::PreCompile(), no locking during compilation. diff --git a/compiler/dex/verified_method.cc b/compiler/dex/verified_method.cc deleted file mode 100644 index 04f7215015..0000000000 --- a/compiler/dex/verified_method.cc +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "verified_method.h" - -#include <algorithm> -#include <memory> - -#include <android-base/logging.h> - -#include "dex/code_item_accessors-inl.h" -#include "dex/dex_file.h" -#include "dex/dex_instruction-inl.h" -#include "runtime.h" -#include "verifier/method_verifier-inl.h" -#include "verifier/reg_type-inl.h" -#include "verifier/register_line-inl.h" -#include "verifier/verifier_deps.h" - -namespace art { - -VerifiedMethod::VerifiedMethod(uint32_t encountered_error_types, bool has_runtime_throw) - : encountered_error_types_(encountered_error_types), - has_runtime_throw_(has_runtime_throw) { -} - -const VerifiedMethod* VerifiedMethod::Create(verifier::MethodVerifier* method_verifier) { - DCHECK(Runtime::Current()->IsAotCompiler()); - std::unique_ptr<VerifiedMethod> verified_method( - new VerifiedMethod(method_verifier->GetEncounteredFailureTypes(), - method_verifier->HasInstructionThatWillThrow())); - - return verified_method.release(); -} - -} // namespace art diff --git a/compiler/dex/verified_method.h b/compiler/dex/verified_method.h deleted file mode 100644 index f100f78fb0..0000000000 --- a/compiler/dex/verified_method.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ART_COMPILER_DEX_VERIFIED_METHOD_H_ -#define ART_COMPILER_DEX_VERIFIED_METHOD_H_ - -#include <vector> - -#include "base/mutex.h" -#include "base/safe_map.h" -#include "dex/dex_file.h" -#include "dex/method_reference.h" - -namespace art { - -namespace verifier { -class MethodVerifier; -} // namespace verifier - -class VerifiedMethod { - public: - VerifiedMethod(uint32_t encountered_error_types, bool has_runtime_throw); - - static const VerifiedMethod* Create(verifier::MethodVerifier* method_verifier) - REQUIRES_SHARED(Locks::mutator_lock_); - ~VerifiedMethod() = default; - - // Returns true if there were any errors during verification. - bool HasVerificationFailures() const { - return encountered_error_types_ != 0; - } - - uint32_t GetEncounteredVerificationFailures() const { - return encountered_error_types_; - } - - bool HasRuntimeThrow() const { - return has_runtime_throw_; - } - - private: - const uint32_t encountered_error_types_; - const bool has_runtime_throw_; -}; - -} // namespace art - -#endif // ART_COMPILER_DEX_VERIFIED_METHOD_H_ diff --git a/compiler/driver/compiler_options.cc b/compiler/driver/compiler_options.cc index a5805f953b..ad5a009808 100644 --- a/compiler/driver/compiler_options.cc +++ b/compiler/driver/compiler_options.cc @@ -31,7 +31,6 @@ #include "compiler_options_map-inl.h" #include "dex/dex_file-inl.h" #include "dex/verification_results.h" -#include "dex/verified_method.h" #include "runtime.h" #include "scoped_thread_state_change-inl.h" #include "simple_compiler_options_map.h" @@ -156,35 +155,4 @@ const VerificationResults* CompilerOptions::GetVerificationResults() const { return verification_results_; } -const VerifiedMethod* CompilerOptions::GetVerifiedMethod(const DexFile* dex_file, - uint32_t method_idx) const { - MethodReference ref(dex_file, method_idx); - return verification_results_->GetVerifiedMethod(ref); -} - -bool CompilerOptions::IsMethodVerifiedWithoutFailures(uint32_t method_idx, - uint16_t class_def_idx, - const DexFile& dex_file) const { - const VerifiedMethod* verified_method = GetVerifiedMethod(&dex_file, method_idx); - if (verified_method != nullptr) { - return !verified_method->HasVerificationFailures(); - } - - // If we can't find verification metadata, check if this is a system class (we trust that system - // classes have their methods verified). If it's not, be conservative and assume the method - // has not been verified successfully. - - // TODO: When compiling the boot image it should be safe to assume that everything is verified, - // even if methods are not found in the verification cache. - const char* descriptor = dex_file.GetClassDescriptor(dex_file.GetClassDef(class_def_idx)); - ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - Thread* self = Thread::Current(); - ScopedObjectAccess soa(self); - bool is_system_class = class_linker->FindSystemClass(self, descriptor) != nullptr; - if (!is_system_class) { - self->ClearException(); - } - return is_system_class; -} - } // namespace art diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h index da75d3741a..db17bda7ac 100644 --- a/compiler/driver/compiler_options.h +++ b/compiler/driver/compiler_options.h @@ -48,7 +48,6 @@ enum class InstructionSet; class InstructionSetFeatures; class ProfileCompilationInfo; class VerificationResults; -class VerifiedMethod; // Enum for CheckProfileMethodsCompiled. Outside CompilerOptions so it can be forward-declared. enum class ProfileMethodsCheck : uint8_t { @@ -298,14 +297,6 @@ class CompilerOptions final { const VerificationResults* GetVerificationResults() const; - const VerifiedMethod* GetVerifiedMethod(const DexFile* dex_file, uint32_t method_idx) const; - - // Checks if the specified method has been verified without failures. Returns - // false if the method is not in the verification results (GetVerificationResults). - bool IsMethodVerifiedWithoutFailures(uint32_t method_idx, - uint16_t class_def_idx, - const DexFile& dex_file) const; - bool ParseCompilerOptions(const std::vector<std::string>& options, bool ignore_unrecognized, std::string* error_msg); diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index 3263e9ca3a..e7826bbba3 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -23,7 +23,6 @@ #include "block_builder.h" #include "code_generator.h" #include "data_type-inl.h" -#include "dex/verified_method.h" #include "driver/compiler_options.h" #include "driver/dex_compilation_unit.h" #include "instruction_builder.h" diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc index a096338ee2..ca35d99f24 100644 --- a/compiler/optimizing/code_generator.cc +++ b/compiler/optimizing/code_generator.cc @@ -42,7 +42,6 @@ #include "compiled_method.h" #include "dex/bytecode_utils.h" #include "dex/code_item_accessors-inl.h" -#include "dex/verified_method.h" #include "graph_visualizer.h" #include "image.h" #include "gc/space/image_space.h" diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc index 664126a54d..74eae430ad 100644 --- a/compiler/optimizing/inliner.cc +++ b/compiler/optimizing/inliner.cc @@ -26,8 +26,6 @@ #include "data_type-inl.h" #include "dead_code_elimination.h" #include "dex/inline_method_analyser.h" -#include "dex/verification_results.h" -#include "dex/verified_method.h" #include "driver/compiler_options.h" #include "driver/dex_compilation_unit.h" #include "instruction_simplifier.h" @@ -388,24 +386,9 @@ static bool IsMethodUnverified(const CompilerOptions& compiler_options, ArtMetho // We're at runtime, we know this is cold code if the class // is not verified, so don't bother analyzing. return true; - } - uint16_t class_def_idx = method->GetDeclaringClass()->GetDexClassDefIndex(); - - const VerifiedMethod* verified_method = - compiler_options.GetVerifiedMethod(method->GetDexFile(), method->GetDexMethodIndex()); - if (verified_method != nullptr && verified_method->HasRuntimeThrow()) { - // Compiler doesn't handle dead code as nicely as verifier. + } else if (!method->GetDeclaringClass()->IsVerifiedNeedsAccessChecks()) { return true; } - if (!compiler_options.IsMethodVerifiedWithoutFailures(method->GetDexMethodIndex(), - class_def_idx, - *method->GetDexFile())) { - if (verified_method == nullptr || - !verifier::CanCompilerHandleVerificationFailure( - verified_method->GetEncounteredVerificationFailures())) { - return true; - } - } } return false; } diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index b6ab9fb1b5..16abf9d37d 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -38,8 +38,6 @@ #include "debug/elf_debug_writer.h" #include "debug/method_debug_info.h" #include "dex/dex_file_types.h" -#include "dex/verification_results.h" -#include "dex/verified_method.h" #include "driver/compiled_method_storage.h" #include "driver/compiler_options.h" #include "driver/dex_compilation_unit.h" @@ -63,7 +61,6 @@ #include "ssa_phi_elimination.h" #include "stack_map_stream.h" #include "utils/assembler.h" -#include "verifier/verifier_compiler_binding.h" namespace art { @@ -1017,98 +1014,84 @@ CompiledMethod* OptimizingCompiler::Compile(const dex::CodeItem* code_item, CompiledMethod* compiled_method = nullptr; Runtime* runtime = Runtime::Current(); DCHECK(runtime->IsAotCompiler()); - const VerifiedMethod* verified_method = compiler_options.GetVerifiedMethod(&dex_file, method_idx); - DCHECK(!verified_method->HasRuntimeThrow()); - if (compiler_options.IsMethodVerifiedWithoutFailures(method_idx, class_def_idx, dex_file) || - verifier::CanCompilerHandleVerificationFailure( - verified_method->GetEncounteredVerificationFailures())) { - ArenaAllocator allocator(runtime->GetArenaPool()); - ArenaStack arena_stack(runtime->GetArenaPool()); - CodeVectorAllocator code_allocator(&allocator); - std::unique_ptr<CodeGenerator> codegen; - bool compiled_intrinsic = false; - { - ScopedObjectAccess soa(Thread::Current()); - ArtMethod* method = - runtime->GetClassLinker()->ResolveMethod<ClassLinker::ResolveMode::kCheckICCEAndIAE>( - method_idx, dex_cache, jclass_loader, /*referrer=*/ nullptr, invoke_type); - DCHECK_EQ(method == nullptr, soa.Self()->IsExceptionPending()); - soa.Self()->ClearException(); // Suppress exception if any. - VariableSizedHandleScope handles(soa.Self()); - Handle<mirror::Class> compiling_class = - handles.NewHandle(method != nullptr ? method->GetDeclaringClass() : nullptr); - DexCompilationUnit dex_compilation_unit( - jclass_loader, - runtime->GetClassLinker(), - dex_file, - code_item, - class_def_idx, - method_idx, - access_flags, - /*verified_method=*/ nullptr, // Not needed by the Optimizing compiler. - dex_cache, - compiling_class); - // All signature polymorphic methods are native. - DCHECK(method == nullptr || !method->IsSignaturePolymorphic()); - // Go to native so that we don't block GC during compilation. - ScopedThreadSuspension sts(soa.Self(), kNative); - // Try to compile a fully intrinsified implementation. - if (method != nullptr && UNLIKELY(method->IsIntrinsic())) { - DCHECK(compiler_options.IsBootImage()); - codegen.reset( - TryCompileIntrinsic(&allocator, - &arena_stack, - &code_allocator, - dex_compilation_unit, - method, - &handles)); - if (codegen != nullptr) { - compiled_intrinsic = true; - } - } - if (codegen == nullptr) { - codegen.reset( - TryCompile(&allocator, - &arena_stack, - &code_allocator, - dex_compilation_unit, - method, - compiler_options.IsBaseline() - ? CompilationKind::kBaseline - : CompilationKind::kOptimized, - &handles)); + ArenaAllocator allocator(runtime->GetArenaPool()); + ArenaStack arena_stack(runtime->GetArenaPool()); + CodeVectorAllocator code_allocator(&allocator); + std::unique_ptr<CodeGenerator> codegen; + bool compiled_intrinsic = false; + { + ScopedObjectAccess soa(Thread::Current()); + ArtMethod* method = + runtime->GetClassLinker()->ResolveMethod<ClassLinker::ResolveMode::kCheckICCEAndIAE>( + method_idx, dex_cache, jclass_loader, /*referrer=*/ nullptr, invoke_type); + DCHECK_EQ(method == nullptr, soa.Self()->IsExceptionPending()); + soa.Self()->ClearException(); // Suppress exception if any. + VariableSizedHandleScope handles(soa.Self()); + Handle<mirror::Class> compiling_class = + handles.NewHandle(method != nullptr ? method->GetDeclaringClass() : nullptr); + DexCompilationUnit dex_compilation_unit( + jclass_loader, + runtime->GetClassLinker(), + dex_file, + code_item, + class_def_idx, + method_idx, + access_flags, + /*verified_method=*/ nullptr, // Not needed by the Optimizing compiler. + dex_cache, + compiling_class); + // All signature polymorphic methods are native. + DCHECK(method == nullptr || !method->IsSignaturePolymorphic()); + // Go to native so that we don't block GC during compilation. + ScopedThreadSuspension sts(soa.Self(), kNative); + // Try to compile a fully intrinsified implementation. + if (method != nullptr && UNLIKELY(method->IsIntrinsic())) { + DCHECK(compiler_options.IsBootImage()); + codegen.reset( + TryCompileIntrinsic(&allocator, + &arena_stack, + &code_allocator, + dex_compilation_unit, + method, + &handles)); + if (codegen != nullptr) { + compiled_intrinsic = true; } } - if (codegen.get() != nullptr) { - compiled_method = Emit(&allocator, - &code_allocator, - codegen.get(), - compiled_intrinsic ? nullptr : code_item); - if (compiled_intrinsic) { - compiled_method->MarkAsIntrinsic(); - } + if (codegen == nullptr) { + codegen.reset( + TryCompile(&allocator, + &arena_stack, + &code_allocator, + dex_compilation_unit, + method, + compiler_options.IsBaseline() + ? CompilationKind::kBaseline + : CompilationKind::kOptimized, + &handles)); + } + } + if (codegen.get() != nullptr) { + compiled_method = Emit(&allocator, + &code_allocator, + codegen.get(), + compiled_intrinsic ? nullptr : code_item); + if (compiled_intrinsic) { + compiled_method->MarkAsIntrinsic(); + } - if (kArenaAllocatorCountAllocations) { - codegen.reset(); // Release codegen's ScopedArenaAllocator for memory accounting. - size_t total_allocated = allocator.BytesAllocated() + arena_stack.PeakBytesAllocated(); - if (total_allocated > kArenaAllocatorMemoryReportThreshold) { - MemStats mem_stats(allocator.GetMemStats()); - MemStats peak_stats(arena_stack.GetPeakStats()); - LOG(INFO) << "Used " << total_allocated << " bytes of arena memory for compiling " - << dex_file.PrettyMethod(method_idx) - << "\n" << Dumpable<MemStats>(mem_stats) - << "\n" << Dumpable<MemStats>(peak_stats); - } + if (kArenaAllocatorCountAllocations) { + codegen.reset(); // Release codegen's ScopedArenaAllocator for memory accounting. + size_t total_allocated = allocator.BytesAllocated() + arena_stack.PeakBytesAllocated(); + if (total_allocated > kArenaAllocatorMemoryReportThreshold) { + MemStats mem_stats(allocator.GetMemStats()); + MemStats peak_stats(arena_stack.GetPeakStats()); + LOG(INFO) << "Used " << total_allocated << " bytes of arena memory for compiling " + << dex_file.PrettyMethod(method_idx) + << "\n" << Dumpable<MemStats>(mem_stats) + << "\n" << Dumpable<MemStats>(peak_stats); } } - } else { - MethodCompilationStat method_stat; - if (compiler_options.VerifyAtRuntime()) { - method_stat = MethodCompilationStat::kNotCompiledVerifyAtRuntime; - } else { - method_stat = MethodCompilationStat::kNotCompiledVerificationError; - } - MaybeRecordStat(compilation_stats_.get(), method_stat); } if (kIsDebugBuild && diff --git a/compiler/optimizing/optimizing_compiler_stats.h b/compiler/optimizing/optimizing_compiler_stats.h index 3d0815f1eb..24d01539df 100644 --- a/compiler/optimizing/optimizing_compiler_stats.h +++ b/compiler/optimizing/optimizing_compiler_stats.h @@ -58,8 +58,6 @@ enum class MethodCompilationStat { kNotCompiledSpaceFilter, kNotCompiledUnhandledInstruction, kNotCompiledUnsupportedIsa, - kNotCompiledVerificationError, - kNotCompiledVerifyAtRuntime, kNotCompiledIrreducibleLoopAndStringInit, kNotCompiledPhiEquivalentInOsr, kInlinedMonomorphicCall, diff --git a/dex2oat/common_compiler_driver_test.cc b/dex2oat/common_compiler_driver_test.cc index 1f62cd7da5..2007c5a970 100644 --- a/dex2oat/common_compiler_driver_test.cc +++ b/dex2oat/common_compiler_driver_test.cc @@ -41,8 +41,7 @@ void CommonCompilerDriverTest::CompileAll(jobject class_loader, compiler_driver_->PreCompile(class_loader, dex_files, timings, - &compiler_options_->image_classes_, - verification_results_.get()); + &compiler_options_->image_classes_); // Verification results in the `callback_` should not be used during compilation. down_cast<QuickCompilerCallbacks*>(callbacks_.get())->SetVerificationResults( diff --git a/dex2oat/dex/quick_compiler_callbacks.cc b/dex2oat/dex/quick_compiler_callbacks.cc index f6f82678c8..11223ff3c8 100644 --- a/dex2oat/dex/quick_compiler_callbacks.cc +++ b/dex2oat/dex/quick_compiler_callbacks.cc @@ -22,9 +22,9 @@ namespace art { -void QuickCompilerCallbacks::MethodVerified(verifier::MethodVerifier* verifier) { +void QuickCompilerCallbacks::AddUncompilableMethod(MethodReference ref) { if (verification_results_ != nullptr) { - verification_results_->ProcessVerifiedMethod(verifier); + verification_results_->AddUncompilableMethod(ref); } } diff --git a/dex2oat/dex/quick_compiler_callbacks.h b/dex2oat/dex/quick_compiler_callbacks.h index 578a1f56e7..4447e02ccb 100644 --- a/dex2oat/dex/quick_compiler_callbacks.h +++ b/dex2oat/dex/quick_compiler_callbacks.h @@ -33,8 +33,7 @@ class QuickCompilerCallbacks final : public CompilerCallbacks { ~QuickCompilerCallbacks() { } - void MethodVerified(verifier::MethodVerifier* verifier) - REQUIRES_SHARED(Locks::mutator_lock_) override; + void AddUncompilableMethod(MethodReference ref) override; void ClassRejected(ClassReference ref) override; diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index a1f1945ff8..8a07539ef1 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -1514,13 +1514,7 @@ class Dex2Oat final { if (CompilerFilter::IsAnyCompilationEnabled(compiler_options_->GetCompilerFilter()) || IsImage()) { // Only modes with compilation or image generation require verification results. - // Do this here instead of when we - // create the compilation callbacks since the compilation mode may have been changed by the - // very large app logic. - // Avoiding setting the verification results saves RAM by not adding the dex files later in - // the function. - // Note: When compiling boot image, this must be done before creating the Runtime. - verification_results_.reset(new VerificationResults(compiler_options_.get())); + verification_results_.reset(new VerificationResults()); callbacks_->SetVerificationResults(verification_results_.get()); } @@ -1731,16 +1725,6 @@ class Dex2Oat final { } } - // Verification results are only required for modes that have any compilation. Avoid - // adding the dex files if possible to prevent allocating large arrays. - if (verification_results_ != nullptr) { - for (const auto& dex_file : dex_files) { - // Pre-register dex files so that we can access verification results without locks during - // compilation and verification. - verification_results_->AddDexFile(dex_file); - } - } - // Setup VerifierDeps for compilation and report if we fail to parse the data. if (!DoEagerUnquickeningOfVdex() && input_vdex_file_ != nullptr) { std::unique_ptr<verifier::VerifierDeps> verifier_deps( @@ -1991,8 +1975,7 @@ class Dex2Oat final { driver_->PreCompile(class_loader, dex_files, timings_, - &compiler_options_->image_classes_, - verification_results_.get()); + &compiler_options_->image_classes_); callbacks_->SetVerificationResults(nullptr); // Should not be needed anymore. compiler_options_->verification_results_ = verification_results_.get(); driver_->CompileAll(class_loader, dex_files, timings_); diff --git a/dex2oat/driver/compiler_driver.cc b/dex2oat/driver/compiler_driver.cc index e1f51437ce..dabf82ce0d 100644 --- a/dex2oat/driver/compiler_driver.cc +++ b/dex2oat/driver/compiler_driver.cc @@ -53,7 +53,6 @@ #include "dex/dex_file_annotations.h" #include "dex/dex_instruction-inl.h" #include "dex/verification_results.h" -#include "dex/verified_method.h" #include "driver/compiler_options.h" #include "driver/dex_compilation_unit.h" #include "gc/accounting/card_table-inl.h" @@ -493,18 +492,13 @@ static void CompileMethodQuick( const VerificationResults* results = compiler_options.GetVerificationResults(); DCHECK(results != nullptr); MethodReference method_ref(&dex_file, method_idx); - const VerifiedMethod* verified_method = results->GetVerifiedMethod(method_ref); - bool compile = - // Basic checks, e.g., not <clinit>. - results->IsCandidateForCompilation(method_ref, access_flags) && - // Did not fail to create VerifiedMethod metadata. - verified_method != nullptr && - // Do not have failures that should punt to the interpreter. - !verified_method->HasRuntimeThrow() && - (verified_method->GetEncounteredVerificationFailures() & - verifier::VERIFY_ERROR_LOCKING) == 0 && - // Is eligible for compilation by methods-to-compile filter. - ShouldCompileBasedOnProfile(compiler_options, profile_index, method_ref); + // Don't compile class initializers unless kEverything. + bool compile = (compiler_options.GetCompilerFilter() == CompilerFilter::kEverything) || + ((access_flags & kAccConstructor) == 0) || ((access_flags & kAccStatic) == 0); + // Check if it's an uncompilable method found by the verifier. + compile = compile && !results->IsUncompilableMethod(method_ref); + // Check if we should compile based on the profile. + compile = compile && ShouldCompileBasedOnProfile(compiler_options, profile_index, method_ref); if (compile) { // NOTE: if compiler declines to compile this method, it will return null. @@ -812,8 +806,7 @@ class CreateConflictTablesVisitor : public ClassVisitor { void CompilerDriver::PreCompile(jobject class_loader, const std::vector<const DexFile*>& dex_files, TimingLogger* timings, - /*inout*/ HashSet<std::string>* image_classes, - /*out*/ VerificationResults* verification_results) { + /*inout*/ HashSet<std::string>* image_classes) { CheckThreadPools(); VLOG(compiler) << "Before precompile " << GetMemoryUsageString(false); @@ -848,7 +841,7 @@ void CompilerDriver::PreCompile(jobject class_loader, VLOG(compiler) << "Verify none mode specified, skipping verification."; SetVerified(class_loader, dex_files, timings); } else if (compiler_options_->IsVerificationEnabled()) { - Verify(class_loader, dex_files, timings, verification_results); + Verify(class_loader, dex_files, timings); VLOG(compiler) << "Verify: " << GetMemoryUsageString(false); if (GetCompilerOptions().IsForceDeterminism() && @@ -1678,8 +1671,7 @@ static void LoadAndUpdateStatus(const ClassAccessor& accessor, bool CompilerDriver::FastVerify(jobject jclass_loader, const std::vector<const DexFile*>& dex_files, - TimingLogger* timings, - /*out*/ VerificationResults* verification_results) { + TimingLogger* timings) { verifier::VerifierDeps* verifier_deps = Runtime::Current()->GetCompilerCallbacks()->GetVerifierDeps(); // If there exist VerifierDeps that aren't the ones we just created to output, use them to verify. @@ -1730,15 +1722,6 @@ bool CompilerDriver::FastVerify(jobject jclass_loader, // the class. LoadAndUpdateStatus( accessor, ClassStatus::kVerifiedNeedsAccessChecks, class_loader, soa.Self()); - // Create `VerifiedMethod`s for each methods, the compiler expects one for - // quickening or compiling. - // Note that this means: - // - We're only going to compile methods that did verify. - // - Quickening will not do checkcast ellision. - // TODO(ngeoffray): Reconsider this once we refactor compiler filters. - for (const ClassAccessor::Method& method : accessor.GetMethods()) { - verification_results->CreateVerifiedMethodFor(method.GetReference()); - } } } else if (!compiler_only_verifies) { // Make sure later compilation stages know they should not try to verify @@ -1755,9 +1738,8 @@ bool CompilerDriver::FastVerify(jobject jclass_loader, void CompilerDriver::Verify(jobject jclass_loader, const std::vector<const DexFile*>& dex_files, - TimingLogger* timings, - /*out*/ VerificationResults* verification_results) { - if (FastVerify(jclass_loader, dex_files, timings, verification_results)) { + TimingLogger* timings) { + if (FastVerify(jclass_loader, dex_files, timings)) { return; } diff --git a/dex2oat/driver/compiler_driver.h b/dex2oat/driver/compiler_driver.h index 18be20d0f0..3da8c3ae10 100644 --- a/dex2oat/driver/compiler_driver.h +++ b/dex2oat/driver/compiler_driver.h @@ -104,8 +104,7 @@ class CompilerDriver { void PreCompile(jobject class_loader, const std::vector<const DexFile*>& dex_files, TimingLogger* timings, - /*inout*/ HashSet<std::string>* image_classes, - /*out*/ VerificationResults* verification_results) + /*inout*/ HashSet<std::string>* image_classes) REQUIRES(!Locks::mutator_lock_); void CompileAll(jobject class_loader, const std::vector<const DexFile*>& dex_files, @@ -241,13 +240,11 @@ class CompilerDriver { // verification was successful. bool FastVerify(jobject class_loader, const std::vector<const DexFile*>& dex_files, - TimingLogger* timings, - /*out*/ VerificationResults* verification_results); + TimingLogger* timings); void Verify(jobject class_loader, const std::vector<const DexFile*>& dex_files, - TimingLogger* timings, - /*out*/ VerificationResults* verification_results); + TimingLogger* timings); void VerifyDexFile(jobject class_loader, const DexFile& dex_file, diff --git a/dex2oat/verifier_deps_test.cc b/dex2oat/verifier_deps_test.cc index e480478c22..42909aec8a 100644 --- a/dex2oat/verifier_deps_test.cc +++ b/dex2oat/verifier_deps_test.cc @@ -27,7 +27,6 @@ #include "dex/dex_file-inl.h" #include "dex/dex_file_types.h" #include "dex/verification_results.h" -#include "dex/verified_method.h" #include "driver/compiler_driver-inl.h" #include "driver/compiler_options.h" #include "handle_scope-inl.h" @@ -47,7 +46,7 @@ class VerifierDepsCompilerCallbacks : public CompilerCallbacks { : CompilerCallbacks(CompilerCallbacks::CallbackMode::kCompileApp), deps_(nullptr) {} - void MethodVerified(verifier::MethodVerifier* verifier ATTRIBUTE_UNUSED) override {} + void AddUncompilableMethod(MethodReference ref ATTRIBUTE_UNUSED) override {} void ClassRejected(ClassReference ref ATTRIBUTE_UNUSED) override {} verifier::VerifierDeps* GetVerifierDeps() const override { return deps_; } @@ -93,16 +92,8 @@ class VerifierDepsTest : public CommonCompilerDriverTest { verifier_deps_.reset(verifier_deps); } callbacks_->SetVerifierDeps(verifier_deps); - compiler_driver_->Verify(class_loader_, dex_files_, &timings, verification_results_.get()); + compiler_driver_->Verify(class_loader_, dex_files_, &timings); callbacks_->SetVerifierDeps(nullptr); - // Clear entries in the verification results to avoid hitting a DCHECK that - // we always succeed inserting a new entry after verifying. - AtomicDexRefMap<MethodReference, const VerifiedMethod*>* map = - &verification_results_->atomic_verified_methods_; - map->Visit([](const DexFileReference& ref ATTRIBUTE_UNUSED, const VerifiedMethod* method) { - delete method; - }); - map->ClearEntries(); } void SetVerifierDeps(const std::vector<const DexFile*>& dex_files) { @@ -125,9 +116,6 @@ class VerifierDepsTest : public CommonCompilerDriverTest { for (const DexFile* dex_file : dex_files_) { class_linker_->RegisterDexFile(*dex_file, loader.Get()); } - for (const DexFile* dex_file : dex_files_) { - verification_results_->AddDexFile(dex_file); - } SetDexFilesForOatFile(dex_files_); } diff --git a/runtime/compiler_callbacks.h b/runtime/compiler_callbacks.h index 18632dc6c6..23379a9550 100644 --- a/runtime/compiler_callbacks.h +++ b/runtime/compiler_callbacks.h @@ -19,6 +19,7 @@ #include "base/locks.h" #include "dex/class_reference.h" +#include "dex/method_reference.h" #include "class_status.h" namespace art { @@ -33,7 +34,6 @@ class Class; namespace verifier { -class MethodVerifier; class VerifierDeps; } // namespace verifier @@ -47,8 +47,7 @@ class CompilerCallbacks { virtual ~CompilerCallbacks() { } - virtual void MethodVerified(verifier::MethodVerifier* verifier) - REQUIRES_SHARED(Locks::mutator_lock_) = 0; + virtual void AddUncompilableMethod(MethodReference ref) = 0; virtual void ClassRejected(ClassReference ref) = 0; virtual verifier::VerifierDeps* GetVerifierDeps() const = 0; diff --git a/runtime/noop_compiler_callbacks.h b/runtime/noop_compiler_callbacks.h index 439f4856a6..f415831fee 100644 --- a/runtime/noop_compiler_callbacks.h +++ b/runtime/noop_compiler_callbacks.h @@ -26,9 +26,7 @@ class NoopCompilerCallbacks final : public CompilerCallbacks { NoopCompilerCallbacks() : CompilerCallbacks(CompilerCallbacks::CallbackMode::kCompileApp) {} ~NoopCompilerCallbacks() {} - void MethodVerified(verifier::MethodVerifier* verifier ATTRIBUTE_UNUSED) override { - } - + void AddUncompilableMethod(MethodReference ref ATTRIBUTE_UNUSED) override {} void ClassRejected(ClassReference ref ATTRIBUTE_UNUSED) override {} verifier::VerifierDeps* GetVerifierDeps() const override { return nullptr; } diff --git a/runtime/verifier/class_verifier.cc b/runtime/verifier/class_verifier.cc index 1c8142b642..6a189a29c7 100644 --- a/runtime/verifier/class_verifier.cc +++ b/runtime/verifier/class_verifier.cc @@ -54,8 +54,13 @@ static bool gPrintedDxMonitorText = false; static void UpdateMethodFlags(uint32_t method_index, Handle<mirror::Class> klass, Handle<mirror::DexCache> dex_cache, + CompilerCallbacks* callbacks, int error_types) REQUIRES_SHARED(Locks::mutator_lock_) { + if (callbacks != nullptr && !CanCompilerHandleVerificationFailure(error_types)) { + MethodReference ref(dex_cache->GetDexFile(), method_index); + callbacks->AddUncompilableMethod(ref); + } if (klass == nullptr) { DCHECK(Runtime::Current()->IsAotCompiler()); // Flags will be set at runtime. @@ -130,7 +135,6 @@ FailureKind ClassVerifier::VerifyClass(Thread* self, class_def, method.GetCodeItem(), method.GetAccessFlags(), - callbacks, allow_soft_failures, log_level, /*need_precise_constants=*/ false, @@ -150,7 +154,7 @@ FailureKind ClassVerifier::VerifyClass(Thread* self, *error += " "; *error += hard_failure_msg; } else if (result.kind != FailureKind::kNoFailure) { - UpdateMethodFlags(method.GetIndex(), klass, dex_cache, result.types); + 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. @@ -174,6 +178,12 @@ FailureKind ClassVerifier::VerifyClass(Thread* self, << ", class: " << PrettyDescriptor(dex_file->GetClassDescriptor(class_def)); GetMetrics()->ClassVerificationCount()->AddOne(); + + if (failure_data.kind == verifier::FailureKind::kHardFailure && callbacks != nullptr) { + ClassReference ref(dex_file, dex_file->GetIndexForClassDef(class_def)); + callbacks->ClassRejected(ref); + } + return failure_data.kind; } diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index ced62bea1a..fea4d8a21a 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -35,7 +35,6 @@ #include "base/utils.h" #include "class_linker.h" #include "class_root-inl.h" -#include "compiler_callbacks.h" #include "dex/class_accessor-inl.h" #include "dex/descriptors_names.h" #include "dex/dex_file-inl.h" @@ -5040,7 +5039,6 @@ MethodVerifier::FailureData MethodVerifier::VerifyMethod(Thread* self, const dex::ClassDef& class_def, const dex::CodeItem* code_item, uint32_t method_access_flags, - CompilerCallbacks* callbacks, bool allow_soft_failures, HardFailLogMode log_level, bool need_precise_constants, @@ -5059,7 +5057,6 @@ MethodVerifier::FailureData MethodVerifier::VerifyMethod(Thread* self, class_def, code_item, method_access_flags, - callbacks, allow_soft_failures, log_level, need_precise_constants, @@ -5078,7 +5075,6 @@ MethodVerifier::FailureData MethodVerifier::VerifyMethod(Thread* self, class_def, code_item, method_access_flags, - callbacks, allow_soft_failures, log_level, need_precise_constants, @@ -5117,7 +5113,6 @@ MethodVerifier::FailureData MethodVerifier::VerifyMethod(Thread* self, const dex::ClassDef& class_def, const dex::CodeItem* code_item, uint32_t method_access_flags, - CompilerCallbacks* callbacks, bool allow_soft_failures, HardFailLogMode log_level, bool need_precise_constants, @@ -5151,11 +5146,6 @@ MethodVerifier::FailureData MethodVerifier::VerifyMethod(Thread* self, // to hard fail. CHECK(!verifier.flags_.have_pending_hard_failure_); - if (code_item != nullptr && callbacks != nullptr) { - // Let the interested party know that the method was verified. - callbacks->MethodVerified(&verifier); - } - if (verifier.failures_.size() != 0) { if (VLOG_IS_ON(verifier)) { verifier.DumpFailures(VLOG_STREAM(verifier) << "Soft verification failures in " @@ -5209,11 +5199,6 @@ MethodVerifier::FailureData MethodVerifier::VerifyMethod(Thread* self, } result.kind = FailureKind::kHardFailure; - if (callbacks != nullptr) { - // Let the interested party know that we failed the class. - ClassReference ref(dex_file, dex_file->GetIndexForClassDef(class_def)); - callbacks->ClassRejected(ref); - } if (kVerifierDebug || VLOG_IS_ON(verifier)) { LOG(ERROR) << verifier.info_messages_.str(); verifier.Dump(LOG_STREAM(ERROR)); diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h index 0e59251a15..858be17dbc 100644 --- a/runtime/verifier/method_verifier.h +++ b/runtime/verifier/method_verifier.h @@ -39,7 +39,6 @@ namespace art { class ClassLinker; -class CompilerCallbacks; class DexFile; class Instruction; struct ReferenceMap2Visitor; @@ -178,7 +177,6 @@ class MethodVerifier { void VisitRoots(RootVisitor* visitor, const RootInfo& roots) REQUIRES_SHARED(Locks::mutator_lock_); - // Accessors used by the compiler via CompilerCallback const CodeItemDataAccessor& CodeItem() const { return code_item_accessor_; } @@ -257,7 +255,6 @@ class MethodVerifier { const dex::ClassDef& class_def_idx, const dex::CodeItem* code_item, uint32_t method_access_flags, - CompilerCallbacks* callbacks, bool allow_soft_failures, HardFailLogMode log_level, bool need_precise_constants, @@ -278,7 +275,6 @@ class MethodVerifier { const dex::ClassDef& class_def_idx, const dex::CodeItem* code_item, uint32_t method_access_flags, - CompilerCallbacks* callbacks, bool allow_soft_failures, HardFailLogMode log_level, bool need_precise_constants, |