diff options
author | 2018-05-22 11:56:14 -0700 | |
---|---|---|
committer | 2018-05-24 10:48:53 -0700 | |
commit | c8c8d5f484b9e4660de288aa51ce3f831317ee53 (patch) | |
tree | fa329a0787a0e302ff40c7deefa97d5b79b28550 | |
parent | d804b76c0b8f9d2c94f3a8648aba26254742a1e2 (diff) |
Move compiler/ to ClassAccessor
Remove usages of ClassDataItemIterator to reduces boiler plate code.
Bug: 79758018
Bug: 77709234
Test: test-art-host
Change-Id: Id41db3299bba3ea8debcbb0b9c721fa675adc064
-rw-r--r-- | compiler/dex/dex_to_dex_compiler.cc | 16 | ||||
-rw-r--r-- | compiler/driver/compiler_driver.cc | 316 | ||||
-rw-r--r-- | compiler/verifier_deps_test.cc | 63 | ||||
-rw-r--r-- | libdexfile/dex/class_accessor-inl.h | 30 | ||||
-rw-r--r-- | libdexfile/dex/class_accessor.h | 95 | ||||
-rw-r--r-- | libdexfile/dex/dex_instruction_iterator.h | 2 | ||||
-rw-r--r-- | tools/dexanalyze/dexanalyze_experiments.cc | 6 |
7 files changed, 244 insertions, 284 deletions
diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc index be8641fd86..68155d844a 100644 --- a/compiler/dex/dex_to_dex_compiler.cc +++ b/compiler/dex/dex_to_dex_compiler.cc @@ -26,6 +26,7 @@ #include "base/mutex.h" #include "compiled_method.h" #include "dex/bytecode_utils.h" +#include "dex/class_accessor-inl.h" #include "dex/dex_file-inl.h" #include "dex/dex_instruction-inl.h" #include "dex_to_dex_decompiler.h" @@ -633,21 +634,14 @@ void DexToDexCompiler::SetDexFiles(const std::vector<const DexFile*>& dex_files) // item. std::unordered_set<const DexFile::CodeItem*> seen_code_items; for (const DexFile* dex_file : dex_files) { - for (size_t i = 0; i < dex_file->NumClassDefs(); ++i) { - const DexFile::ClassDef& class_def = dex_file->GetClassDef(i); - const uint8_t* class_data = dex_file->GetClassData(class_def); - if (class_data == nullptr) { - continue; - } - ClassDataItemIterator it(*dex_file, class_data); - it.SkipAllFields(); - for (; it.HasNextMethod(); it.Next()) { - const DexFile::CodeItem* code_item = it.GetMethodCodeItem(); + for (ClassAccessor accessor : dex_file->GetClasses()) { + accessor.VisitMethods([&](const ClassAccessor::Method& method) { + const DexFile::CodeItem* code_item = method.GetCodeItem(); // Detect the shared code items. if (!seen_code_items.insert(code_item).second) { shared_code_items_.insert(code_item); } - } + }); } } VLOG(compiler) << "Shared code items " << shared_code_items_.size(); diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 7dc44fa44b..1b809d232a 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -42,6 +42,7 @@ #include "compiler.h" #include "compiler_callbacks.h" #include "compiler_driver-inl.h" +#include "dex/class_accessor-inl.h" #include "dex/descriptors_names.h" #include "dex/dex_file-inl.h" #include "dex/dex_file_annotations.h" @@ -771,39 +772,6 @@ void CompilerDriver::Resolve(jobject class_loader, } } -// Resolve const-strings in the code. Done to have deterministic allocation behavior. Right now -// this is single-threaded for simplicity. -// TODO: Collect the relevant string indices in parallel, then allocate them sequentially in a -// stable order. - -static void ResolveConstStrings(ClassLinker* class_linker, - Handle<mirror::DexCache> dex_cache, - const DexFile& dex_file, - const DexFile::CodeItem* code_item) - REQUIRES_SHARED(Locks::mutator_lock_) { - if (code_item == nullptr) { - // Abstract or native method. - return; - } - - for (const DexInstructionPcPair& inst : CodeItemInstructionAccessor(dex_file, code_item)) { - switch (inst->Opcode()) { - case Instruction::CONST_STRING: - case Instruction::CONST_STRING_JUMBO: { - dex::StringIndex string_index((inst->Opcode() == Instruction::CONST_STRING) - ? inst->VRegB_21c() - : inst->VRegB_31c()); - ObjPtr<mirror::String> string = class_linker->ResolveString(string_index, dex_cache); - CHECK(string != nullptr) << "Could not allocate a string when forcing determinism"; - break; - } - - default: - break; - } - } -} - static void ResolveConstStrings(CompilerDriver* driver, const std::vector<const DexFile*>& dex_files, TimingLogger* timings) { @@ -816,33 +784,35 @@ static void ResolveConstStrings(CompilerDriver* driver, dex_cache.Assign(class_linker->FindDexCache(soa.Self(), *dex_file)); TimingLogger::ScopedTiming t("Resolve const-string Strings", timings); - size_t class_def_count = dex_file->NumClassDefs(); - for (size_t class_def_index = 0; class_def_index < class_def_count; ++class_def_index) { - const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index); - - const uint8_t* class_data = dex_file->GetClassData(class_def); - if (class_data == nullptr) { - // empty class, probably a marker interface - continue; - } - - ClassDataItemIterator it(*dex_file, class_data); - it.SkipAllFields(); - - bool compilation_enabled = driver->IsClassToCompile( - dex_file->StringByTypeIdx(class_def.class_idx_)); - if (!compilation_enabled) { + for (ClassAccessor accessor : dex_file->GetClasses()) { + if (!driver->IsClassToCompile(accessor.GetDescriptor())) { // Compilation is skipped, do not resolve const-string in code of this class. // FIXME: Make sure that inlining honors this. b/26687569 continue; } + accessor.VisitMethods([&](const ClassAccessor::Method& method) + REQUIRES_SHARED(Locks::mutator_lock_) { + // Resolve const-strings in the code. Done to have deterministic allocation behavior. Right + // now this is single-threaded for simplicity. + // TODO: Collect the relevant string indices in parallel, then allocate them sequentially + // in a stable order. + for (const DexInstructionPcPair& inst : method.GetInstructions()) { + switch (inst->Opcode()) { + case Instruction::CONST_STRING: + case Instruction::CONST_STRING_JUMBO: { + dex::StringIndex string_index((inst->Opcode() == Instruction::CONST_STRING) + ? inst->VRegB_21c() + : inst->VRegB_31c()); + ObjPtr<mirror::String> string = class_linker->ResolveString(string_index, dex_cache); + CHECK(string != nullptr) << "Could not allocate a string when forcing determinism"; + break; + } - // Direct and virtual methods. - while (it.HasNextMethod()) { - ResolveConstStrings(class_linker, dex_cache, *dex_file, it.GetMethodCodeItem()); - it.Next(); - } - DCHECK(!it.HasNext()); + default: + break; + } + } + }); } } } @@ -856,14 +826,9 @@ static void InitializeTypeCheckBitstrings(CompilerDriver* driver, ClassLinker* class_linker, Handle<mirror::DexCache> dex_cache, const DexFile& dex_file, - const DexFile::CodeItem* code_item) + const ClassAccessor::Method& method) REQUIRES_SHARED(Locks::mutator_lock_) { - if (code_item == nullptr) { - // Abstract or native method. - return; - } - - for (const DexInstructionPcPair& inst : CodeItemInstructionAccessor(dex_file, code_item)) { + for (const DexInstructionPcPair& inst : method.GetInstructions()) { switch (inst->Opcode()) { case Instruction::CHECK_CAST: case Instruction::INSTANCE_OF: { @@ -907,34 +872,18 @@ static void InitializeTypeCheckBitstrings(CompilerDriver* driver, dex_cache.Assign(class_linker->FindDexCache(soa.Self(), *dex_file)); TimingLogger::ScopedTiming t("Initialize type check bitstrings", timings); - size_t class_def_count = dex_file->NumClassDefs(); - for (size_t class_def_index = 0; class_def_index < class_def_count; ++class_def_index) { - const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index); - - const uint8_t* class_data = dex_file->GetClassData(class_def); - if (class_data == nullptr) { - // empty class, probably a marker interface - continue; - } - - ClassDataItemIterator it(*dex_file, class_data); - it.SkipAllFields(); - - bool compilation_enabled = driver->IsClassToCompile( - dex_file->StringByTypeIdx(class_def.class_idx_)); - if (!compilation_enabled) { + for (ClassAccessor accessor : dex_file->GetClasses()) { + if (!driver->IsClassToCompile(accessor.GetDescriptor())) { // Compilation is skipped, do not look for type checks in code of this class. // FIXME: Make sure that inlining honors this. b/26687569 continue; } // Direct and virtual methods. - while (it.HasNextMethod()) { - InitializeTypeCheckBitstrings( - driver, class_linker, dex_cache, *dex_file, it.GetMethodCodeItem()); - it.Next(); - } - DCHECK(!it.HasNext()); + accessor.VisitMethods([&](const ClassAccessor::Method& method) + REQUIRES_SHARED(Locks::mutator_lock_) { + InitializeTypeCheckBitstrings(driver, class_linker, dex_cache, *dex_file, method); + }); } } } @@ -954,10 +903,8 @@ static void EnsureVerifiedOrVerifyAtRuntime(jobject jclass_loader, ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); for (const DexFile* dex_file : dex_files) { - for (uint32_t i = 0; i < dex_file->NumClassDefs(); ++i) { - const DexFile::ClassDef& class_def = dex_file->GetClassDef(i); - const char* descriptor = dex_file->GetClassDescriptor(class_def); - cls.Assign(class_linker->FindClass(soa.Self(), descriptor, class_loader)); + for (ClassAccessor accessor : dex_file->GetClasses()) { + cls.Assign(class_linker->FindClass(soa.Self(), accessor.GetDescriptor(), class_loader)); if (cls == nullptr) { soa.Self()->ClearException(); } else if (&cls->GetDexFile() == dex_file) { @@ -1740,22 +1687,16 @@ static void CheckAndClearResolveException(Thread* self) bool CompilerDriver::RequiresConstructorBarrier(const DexFile& dex_file, uint16_t class_def_idx) const { - const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_idx); - const uint8_t* class_data = dex_file.GetClassData(class_def); - if (class_data == nullptr) { - // Empty class such as a marker interface. - return false; - } - ClassDataItemIterator it(dex_file, class_data); - it.SkipStaticFields(); + ClassAccessor accessor(dex_file, dex_file.GetClassDef(class_def_idx)); + bool has_is_final = false; // We require a constructor barrier if there are final instance fields. - while (it.HasNextInstanceField()) { - if (it.MemberIsFinal()) { - return true; + accessor.VisitFields(/*static*/ VoidFunctor(), + [&](const ClassAccessor::Field& field) { + if (field.IsFinal()) { + has_is_final = true; } - it.Next(); - } - return false; + }); + return has_is_final; } class ResolveClassFieldsAndMethodsVisitor : public CompilationVisitor { @@ -1770,11 +1711,6 @@ class ResolveClassFieldsAndMethodsVisitor : public CompilationVisitor { const DexFile& dex_file = *manager_->GetDexFile(); ClassLinker* class_linker = manager_->GetClassLinker(); - // If an instance field is final then we need to have a barrier on the return, static final - // fields are assigned within the lock held for class initialization. Conservatively assume - // constructor barriers are always required. - bool requires_constructor_barrier = true; - // Method and Field are the worst. We can't resolve without either // context from the code use (to disambiguate virtual vs direct // method and instance vs static field) or from class @@ -1806,56 +1742,53 @@ class ResolveClassFieldsAndMethodsVisitor : public CompilationVisitor { // We want to resolve the methods and fields eagerly. resolve_fields_and_methods = true; } - // Note the class_data pointer advances through the headers, - // static fields, instance fields, direct methods, and virtual - // methods. - const uint8_t* class_data = dex_file.GetClassData(class_def); - if (class_data == nullptr) { - // Empty class such as a marker interface. - requires_constructor_barrier = false; - } else { - ClassDataItemIterator it(dex_file, class_data); - while (it.HasNextStaticField()) { - if (resolve_fields_and_methods) { - ArtField* field = class_linker->ResolveField( - it.GetMemberIndex(), dex_cache, class_loader, /* is_static */ true); - if (field == nullptr) { - CheckAndClearResolveException(soa.Self()); - } + // If an instance field is final then we need to have a barrier on the return, static final + // fields are assigned within the lock held for class initialization. + bool requires_constructor_barrier = false; + + ClassAccessor accessor(dex_file, class_def); + // Optionally resolve fields and methods and figure out if we need a constructor barrier. + auto method_visitor = [&](const ClassAccessor::Method& method) + REQUIRES_SHARED(Locks::mutator_lock_) { + if (resolve_fields_and_methods) { + ArtMethod* resolved = class_linker->ResolveMethod<ClassLinker::ResolveMode::kNoChecks>( + method.GetIndex(), + dex_cache, + class_loader, + /* referrer */ nullptr, + method.GetInvokeType(class_def.access_flags_)); + if (resolved == nullptr) { + CheckAndClearResolveException(soa.Self()); } - it.Next(); } - // We require a constructor barrier if there are final instance fields. - requires_constructor_barrier = false; - while (it.HasNextInstanceField()) { - if (it.MemberIsFinal()) { - requires_constructor_barrier = true; - } - if (resolve_fields_and_methods) { - ArtField* field = class_linker->ResolveField( - it.GetMemberIndex(), dex_cache, class_loader, /* is_static */ false); - if (field == nullptr) { - CheckAndClearResolveException(soa.Self()); + }; + accessor.VisitFieldsAndMethods( + // static fields + [&](ClassAccessor::Field& field) REQUIRES_SHARED(Locks::mutator_lock_) { + if (resolve_fields_and_methods) { + ArtField* resolved = class_linker->ResolveField( + field.GetIndex(), dex_cache, class_loader, /* is_static */ true); + if (resolved == nullptr) { + CheckAndClearResolveException(soa.Self()); + } } - } - it.Next(); - } - if (resolve_fields_and_methods) { - while (it.HasNextMethod()) { - ArtMethod* method = class_linker->ResolveMethod<ClassLinker::ResolveMode::kNoChecks>( - it.GetMemberIndex(), - dex_cache, - class_loader, - /* referrer */ nullptr, - it.GetMethodInvokeType(class_def)); - if (method == nullptr) { - CheckAndClearResolveException(soa.Self()); + }, + // instance fields + [&](ClassAccessor::Field& field) REQUIRES_SHARED(Locks::mutator_lock_) { + if (field.IsFinal()) { + // We require a constructor barrier if there are final instance fields. + requires_constructor_barrier = true; } - it.Next(); - } - DCHECK(!it.HasNext()); - } - } + if (resolve_fields_and_methods) { + ArtField* resolved = class_linker->ResolveField( + field.GetIndex(), dex_cache, class_loader, /* is_static */ false); + if (resolved == nullptr) { + CheckAndClearResolveException(soa.Self()); + } + } + }, + /*direct methods*/ method_visitor, + /*virtual methods*/ method_visitor); manager_->GetCompiler()->SetRequiresConstructorBarrier(self, &dex_file, class_def_index, @@ -1942,32 +1875,13 @@ void CompilerDriver::SetVerified(jobject class_loader, } } -static void PopulateVerifiedMethods(const DexFile& dex_file, - uint32_t class_def_index, - VerificationResults* verification_results) { - const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index); - const uint8_t* class_data = dex_file.GetClassData(class_def); - if (class_data == nullptr) { - return; - } - ClassDataItemIterator it(dex_file, class_data); - it.SkipAllFields(); - - while (it.HasNextMethod()) { - verification_results->CreateVerifiedMethodFor(MethodReference(&dex_file, it.GetMemberIndex())); - it.Next(); - } - DCHECK(!it.HasNext()); -} - -static void LoadAndUpdateStatus(const DexFile& dex_file, - const DexFile::ClassDef& class_def, +static void LoadAndUpdateStatus(const ClassAccessor& accessor, ClassStatus status, Handle<mirror::ClassLoader> class_loader, Thread* self) REQUIRES_SHARED(Locks::mutator_lock_) { StackHandleScope<1> hs(self); - const char* descriptor = dex_file.GetClassDescriptor(class_def); + const char* descriptor = accessor.GetDescriptor(); ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); Handle<mirror::Class> cls(hs.NewHandle<mirror::Class>( class_linker->FindClass(self, descriptor, class_loader))); @@ -1975,7 +1889,7 @@ static void LoadAndUpdateStatus(const DexFile& dex_file, // Check that the class is resolved with the current dex file. We might get // a boot image class, or a class in a different dex file for multidex, and // we should not update the status in that case. - if (&cls->GetDexFile() == &dex_file) { + if (&cls->GetDexFile() == &accessor.GetDexFile()) { ObjectLock<mirror::Class> lock(self, cls); mirror::Class::SetStatus(cls, status, self); } @@ -2014,13 +1928,13 @@ bool CompilerDriver::FastVerify(jobject jclass_loader, // Fetch the list of unverified classes. const std::set<dex::TypeIndex>& unverified_classes = verifier_deps->GetUnverifiedClasses(*dex_file); - for (uint32_t i = 0; i < dex_file->NumClassDefs(); ++i) { - const DexFile::ClassDef& class_def = dex_file->GetClassDef(i); - if (unverified_classes.find(class_def.class_idx_) == unverified_classes.end()) { + uint32_t class_def_idx = 0u; + for (ClassAccessor accessor : dex_file->GetClasses()) { + if (unverified_classes.find(accessor.GetClassIdx()) == unverified_classes.end()) { if (compiler_only_verifies) { // Just update the compiled_classes_ map. The compiler doesn't need to resolve // the type. - ClassReference ref(dex_file, i); + ClassReference ref(dex_file, class_def_idx); ClassStatus existing = ClassStatus::kNotReady; DCHECK(compiled_classes_.Get(ref, &existing)) << ref.dex_file->GetLocation(); ClassStateTable::InsertResult result = @@ -2029,26 +1943,27 @@ bool CompilerDriver::FastVerify(jobject jclass_loader, } else { // Update the class status, so later compilation stages know they don't need to verify // the class. - LoadAndUpdateStatus( - *dex_file, class_def, ClassStatus::kVerified, class_loader, soa.Self()); + LoadAndUpdateStatus(accessor, ClassStatus::kVerified, 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. - PopulateVerifiedMethods(*dex_file, i, verification_results_); + accessor.VisitMethods([&](const ClassAccessor::Method& method) { + verification_results_->CreateVerifiedMethodFor(method.GetReference()); + }); } } else if (!compiler_only_verifies) { // Make sure later compilation stages know they should not try to verify // this class again. - LoadAndUpdateStatus(*dex_file, - class_def, + LoadAndUpdateStatus(accessor, ClassStatus::kRetryVerificationAtRuntime, class_loader, soa.Self()); } } + ++class_def_idx; } return true; } @@ -2784,22 +2699,22 @@ static void CompileDexFile(CompilerDriver* driver, auto compile = [&context, &compile_fn](size_t class_def_index) { ScopedTrace trace(__FUNCTION__); const DexFile& dex_file = *context.GetDexFile(); - const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index); ClassLinker* class_linker = context.GetClassLinker(); jobject jclass_loader = context.GetClassLoader(); ClassReference ref(&dex_file, class_def_index); + const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index); + ClassAccessor accessor(dex_file, class_def); // Skip compiling classes with generic verifier failures since they will still fail at runtime if (context.GetCompiler()->GetVerificationResults()->IsClassRejected(ref)) { return; } // Use a scoped object access to perform to the quick SkipClass check. - const char* descriptor = dex_file.GetClassDescriptor(class_def); ScopedObjectAccess soa(Thread::Current()); StackHandleScope<3> hs(soa.Self()); Handle<mirror::ClassLoader> class_loader( hs.NewHandle(soa.Decode<mirror::ClassLoader>(jclass_loader))); Handle<mirror::Class> klass( - hs.NewHandle(class_linker->FindClass(soa.Self(), descriptor, class_loader))); + hs.NewHandle(class_linker->FindClass(soa.Self(), accessor.GetDescriptor(), class_loader))); Handle<mirror::DexCache> dex_cache; if (klass == nullptr) { soa.Self()->AssertPendingException(); @@ -2814,9 +2729,8 @@ static void CompileDexFile(CompilerDriver* driver, dex_cache = hs.NewHandle(klass->GetDexCache()); } - const uint8_t* class_data = dex_file.GetClassData(class_def); - if (class_data == nullptr) { - // empty class, probably a marker interface + // Avoid suspension if there are no methods to compile. + if (accessor.NumDirectMethods() + accessor.NumVirtualMethods() == 0) { return; } @@ -2829,28 +2743,24 @@ static void CompileDexFile(CompilerDriver* driver, optimizer::DexToDexCompiler::CompilationLevel dex_to_dex_compilation_level = GetDexToDexCompilationLevel(soa.Self(), *driver, jclass_loader, dex_file, class_def); - ClassDataItemIterator it(dex_file, class_data); - it.SkipAllFields(); - bool compilation_enabled = driver->IsClassToCompile( - dex_file.StringByTypeIdx(class_def.class_idx_)); + const bool compilation_enabled = driver->IsClassToCompile(accessor.GetDescriptor()); // Compile direct and virtual methods. int64_t previous_method_idx = -1; - while (it.HasNextMethod()) { - uint32_t method_idx = it.GetMemberIndex(); + accessor.VisitMethods([&](const ClassAccessor::Method& method) { + const uint32_t method_idx = method.GetIndex(); if (method_idx == previous_method_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 - it.Next(); - continue; + return; } previous_method_idx = method_idx; compile_fn(soa.Self(), driver, - it.GetMethodCodeItem(), - it.GetMethodAccessFlags(), - it.GetMethodInvokeType(class_def), + method.GetCodeItem(), + method.GetAccessFlags(), + method.GetInvokeType(class_def.access_flags_), class_def_index, method_idx, class_loader, @@ -2858,9 +2768,7 @@ static void CompileDexFile(CompilerDriver* driver, dex_to_dex_compilation_level, compilation_enabled, dex_cache); - it.Next(); - } - DCHECK(!it.HasNext()); + }); }; context.ForAllLambda(0, dex_file.NumClassDefs(), compile, thread_count); } diff --git a/compiler/verifier_deps_test.cc b/compiler/verifier_deps_test.cc index 06f0bcdec7..103862beff 100644 --- a/compiler/verifier_deps_test.cc +++ b/compiler/verifier_deps_test.cc @@ -22,6 +22,8 @@ #include "class_linker.h" #include "common_compiler_test.h" #include "compiler_callbacks.h" +#include "dex/class_accessor-inl.h" +#include "dex/class_iterator.h" #include "dex/dex_file-inl.h" #include "dex/dex_file_types.h" #include "dex/verification_results.h" @@ -148,48 +150,45 @@ class VerifierDepsTest : public CommonCompilerTest { Handle<mirror::DexCache> dex_cache_handle(hs.NewHandle(klass_Main_->GetDexCache())); const DexFile::ClassDef* class_def = klass_Main_->GetClassDef(); - const uint8_t* class_data = primary_dex_file_->GetClassData(*class_def); - CHECK(class_data != nullptr); + ClassAccessor accessor(*primary_dex_file_, *class_def); - ClassDataItemIterator it(*primary_dex_file_, class_data); - it.SkipAllFields(); + bool has_failures = true; + bool found_method = false; - ArtMethod* method = nullptr; - while (it.HasNextDirectMethod()) { + accessor.VisitMethods([&](const ClassAccessor::Method& method) + REQUIRES_SHARED(Locks::mutator_lock_) { ArtMethod* resolved_method = class_linker_->ResolveMethod<ClassLinker::ResolveMode::kNoChecks>( - it.GetMemberIndex(), + method.GetIndex(), dex_cache_handle, class_loader_handle, /* referrer */ nullptr, - it.GetMethodInvokeType(*class_def)); + method.GetInvokeType(class_def->access_flags_)); CHECK(resolved_method != nullptr); if (method_name == resolved_method->GetName()) { - method = resolved_method; - break; + soa.Self()->SetVerifierDeps(callbacks_->GetVerifierDeps()); + MethodVerifier verifier(soa.Self(), + primary_dex_file_, + dex_cache_handle, + class_loader_handle, + *class_def, + method.GetCodeItem(), + method.GetIndex(), + resolved_method, + method.GetAccessFlags(), + true /* can_load_classes */, + true /* allow_soft_failures */, + true /* need_precise_constants */, + false /* verify to dump */, + true /* allow_thread_suspension */); + verifier.Verify(); + soa.Self()->SetVerifierDeps(nullptr); + has_failures = verifier.HasFailures(); + found_method = true; } - it.Next(); - } - CHECK(method != nullptr); - - Thread::Current()->SetVerifierDeps(callbacks_->GetVerifierDeps()); - MethodVerifier verifier(Thread::Current(), - primary_dex_file_, - dex_cache_handle, - class_loader_handle, - *class_def, - it.GetMethodCodeItem(), - it.GetMemberIndex(), - method, - it.GetMethodAccessFlags(), - true /* can_load_classes */, - true /* allow_soft_failures */, - true /* need_precise_constants */, - false /* verify to dump */, - true /* allow_thread_suspension */); - verifier.Verify(); - Thread::Current()->SetVerifierDeps(nullptr); - return !verifier.HasFailures(); + }); + CHECK(found_method) << "Expected to find method " << method_name; + return !has_failures; } void VerifyDexFile(const char* multidex = nullptr) { diff --git a/libdexfile/dex/class_accessor-inl.h b/libdexfile/dex/class_accessor-inl.h index 5cfbcaa359..a082142366 100644 --- a/libdexfile/dex/class_accessor-inl.h +++ b/libdexfile/dex/class_accessor-inl.h @@ -38,14 +38,14 @@ inline ClassAccessor::ClassAccessor(const DexFile& dex_file, const DexFile::Clas num_virtual_methods_(ptr_pos_ != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u) {} inline const uint8_t* ClassAccessor::Method::Read(const uint8_t* ptr) { - method_idx_ += DecodeUnsignedLeb128(&ptr); + index_ += DecodeUnsignedLeb128(&ptr); access_flags_ = DecodeUnsignedLeb128(&ptr); code_off_ = DecodeUnsignedLeb128(&ptr); return ptr; } inline const uint8_t* ClassAccessor::Field::Read(const uint8_t* ptr) { - field_idx_ += DecodeUnsignedLeb128(&ptr); + index_ += DecodeUnsignedLeb128(&ptr); access_flags_ = DecodeUnsignedLeb128(&ptr); return ptr; } @@ -54,7 +54,7 @@ template <typename StaticFieldVisitor, typename InstanceFieldVisitor, typename DirectMethodVisitor, typename VirtualMethodVisitor> -inline void ClassAccessor::VisitMethodsAndFields( +inline void ClassAccessor::VisitFieldsAndMethods( const StaticFieldVisitor& static_field_visitor, const InstanceFieldVisitor& instance_field_visitor, const DirectMethodVisitor& direct_method_visitor, @@ -75,14 +75,14 @@ inline void ClassAccessor::VisitMethodsAndFields( } } { - Method data(dex_file_); + Method data(dex_file_, /*is_static_or_direct*/ true); for (size_t i = 0; i < num_direct_methods_; ++i) { ptr = data.Read(ptr); direct_method_visitor(data); } } { - Method data(dex_file_); + Method data(dex_file_, /*is_static_or_direct*/ false); for (size_t i = 0; i < num_virtual_methods_; ++i) { ptr = data.Read(ptr); virtual_method_visitor(data); @@ -94,12 +94,22 @@ template <typename DirectMethodVisitor, typename VirtualMethodVisitor> inline void ClassAccessor::VisitMethods(const DirectMethodVisitor& direct_method_visitor, const VirtualMethodVisitor& virtual_method_visitor) const { - VisitMethodsAndFields(VoidFunctor(), + VisitFieldsAndMethods(VoidFunctor(), VoidFunctor(), direct_method_visitor, virtual_method_visitor); } +template <typename StaticFieldVisitor, + typename InstanceFieldVisitor> +inline void ClassAccessor::VisitFields(const StaticFieldVisitor& static_field_visitor, + const InstanceFieldVisitor& instance_field_visitor) const { + VisitFieldsAndMethods(static_field_visitor, + instance_field_visitor, + VoidFunctor(), + VoidFunctor()); +} + // Visit direct and virtual methods. template <typename MethodVisitor> inline void ClassAccessor::VisitMethods(const MethodVisitor& method_visitor) const { @@ -114,6 +124,14 @@ inline CodeItemInstructionAccessor ClassAccessor::Method::GetInstructions() cons return CodeItemInstructionAccessor(dex_file_, dex_file_.GetCodeItem(GetCodeItemOffset())); } +inline const char* ClassAccessor::GetDescriptor() const { + return dex_file_.StringByTypeIdx(descriptor_index_); +} + +inline const DexFile::CodeItem* ClassAccessor::Method::GetCodeItem() const { + return dex_file_.GetCodeItem(code_off_); +} + } // namespace art #endif // ART_LIBDEXFILE_DEX_CLASS_ACCESSOR_INL_H_ diff --git a/libdexfile/dex/class_accessor.h b/libdexfile/dex/class_accessor.h index 835c4e2eb7..72bc50b98c 100644 --- a/libdexfile/dex/class_accessor.h +++ b/libdexfile/dex/class_accessor.h @@ -20,6 +20,9 @@ #include "base/utils.h" #include "code_item_accessors.h" #include "dex_file.h" +#include "invoke_type.h" +#include "method_reference.h" +#include "modifiers.h" namespace art { @@ -27,56 +30,82 @@ class ClassIteratorData; // Classes to access Dex data. class ClassAccessor { - public: - // Class method data. - class Method { + private: + class BaseItem { public: uint32_t GetIndex() const { - return method_idx_; + return index_; } uint32_t GetAccessFlags() const { return access_flags_; } + bool IsFinal() const { + return (GetAccessFlags() & kAccFinal) != 0; + } + + public: + uint32_t index_ = 0u; + uint32_t access_flags_ = 0u; + }; + + public: + // A decoded version of the method of a class_data_item. + class Method : public BaseItem { + public: uint32_t GetCodeItemOffset() const { return code_off_; } + InvokeType GetInvokeType(uint32_t class_access_flags) const { + return is_static_or_direct_ + ? GetDirectMethodInvokeType() + : GetVirtualMethodInvokeType(class_access_flags); + } + + MethodReference GetReference() const { + return MethodReference(&dex_file_, GetIndex()); + } + CodeItemInstructionAccessor GetInstructions() const; + const DexFile::CodeItem* GetCodeItem() const; + private: - explicit Method(const DexFile& dex_file) : dex_file_(dex_file) {} + explicit Method(const DexFile& dex_file, bool is_static_or_direct) + : dex_file_(dex_file), + is_static_or_direct_(is_static_or_direct) {} const uint8_t* Read(const uint8_t* ptr); - // A decoded version of the method of a class_data_item. + InvokeType GetDirectMethodInvokeType() const { + return (GetAccessFlags() & kAccStatic) != 0 ? kStatic : kDirect; + } + + InvokeType GetVirtualMethodInvokeType(uint32_t class_access_flags) const { + DCHECK_EQ(GetAccessFlags() & kAccStatic, 0U); + if ((class_access_flags & kAccInterface) != 0) { + return kInterface; + } else if ((GetAccessFlags() & kAccConstructor) != 0) { + return kSuper; + } else { + return kVirtual; + } + } + const DexFile& dex_file_; - uint32_t method_idx_ = 0u; - uint32_t access_flags_ = 0u; + const bool is_static_or_direct_; uint32_t code_off_ = 0u; friend class ClassAccessor; }; - // Class field data. - class Field { - public: - uint32_t GetIndex() const { - return field_idx_; - } - - uint32_t GetAccessFlags() const { - return access_flags_; - } - + // A decoded version of the field of a class_data_item. + class Field : public BaseItem { private: const uint8_t* Read(const uint8_t* ptr); - // A decoded version of the field of a class_data_item. - uint32_t field_idx_ = 0u; - uint32_t access_flags_ = 0u; - friend class ClassAccessor; }; @@ -89,20 +118,27 @@ class ClassAccessor { const DexFile::CodeItem* GetCodeItem(const Method& method) const; // Iterator data is not very iterator friendly, use visitors to get around this. + // No thread safety analysis since the visitor may require capabilities. template <typename StaticFieldVisitor, typename InstanceFieldVisitor, typename DirectMethodVisitor, typename VirtualMethodVisitor> - void VisitMethodsAndFields(const StaticFieldVisitor& static_field_visitor, + void VisitFieldsAndMethods(const StaticFieldVisitor& static_field_visitor, const InstanceFieldVisitor& instance_field_visitor, const DirectMethodVisitor& direct_method_visitor, - const VirtualMethodVisitor& virtual_method_visitor) const; + const VirtualMethodVisitor& virtual_method_visitor) const + NO_THREAD_SAFETY_ANALYSIS; template <typename DirectMethodVisitor, typename VirtualMethodVisitor> void VisitMethods(const DirectMethodVisitor& direct_method_visitor, const VirtualMethodVisitor& virtual_method_visitor) const; + template <typename StaticFieldVisitor, + typename InstanceFieldVisitor> + void VisitFields(const StaticFieldVisitor& static_field_visitor, + const InstanceFieldVisitor& instance_field_visitor) const; + // Visit direct and virtual methods. template <typename MethodVisitor> void VisitMethods(const MethodVisitor& method_visitor) const; @@ -123,11 +159,16 @@ class ClassAccessor { return num_virtual_methods_; } - // TODO: Deprecate - dex::TypeIndex GetDescriptorIndex() const { + const char* GetDescriptor() const; + + dex::TypeIndex GetClassIdx() const { return descriptor_index_; } + const DexFile& GetDexFile() const { + return dex_file_; + } + protected: const DexFile& dex_file_; const dex::TypeIndex descriptor_index_ = {}; diff --git a/libdexfile/dex/dex_instruction_iterator.h b/libdexfile/dex/dex_instruction_iterator.h index db3ff95e02..b75a95bf5c 100644 --- a/libdexfile/dex/dex_instruction_iterator.h +++ b/libdexfile/dex/dex_instruction_iterator.h @@ -123,7 +123,7 @@ class DexInstructionIterator : public DexInstructionIteratorBase { using DexInstructionIteratorBase::DexInstructionIteratorBase; explicit DexInstructionIterator(const uint16_t* inst, uint32_t dex_pc) - : DexInstructionIteratorBase(Instruction::At(inst), dex_pc) {} + : DexInstructionIteratorBase(inst != nullptr ? Instruction::At(inst) : nullptr, dex_pc) {} explicit DexInstructionIterator(const DexInstructionPcPair& pair) : DexInstructionIterator(pair.Instructions(), pair.DexPc()) {} diff --git a/tools/dexanalyze/dexanalyze_experiments.cc b/tools/dexanalyze/dexanalyze_experiments.cc index 427a465caf..312a7b3159 100644 --- a/tools/dexanalyze/dexanalyze_experiments.cc +++ b/tools/dexanalyze/dexanalyze_experiments.cc @@ -150,7 +150,7 @@ void CountDexIndices::ProcessDexFile(const DexFile& dex_file) { case Instruction::INVOKE_VIRTUAL_RANGE: { bool is_range = (inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE); uint32_t method_idx = is_range ? inst->VRegB_3rc() : inst->VRegB_35c(); - if (dex_file.GetMethodId(method_idx).class_idx_ == accessor.GetDescriptorIndex()) { + if (dex_file.GetMethodId(method_idx).class_idx_ == accessor.GetClassIdx()) { ++same_class_virtual_; } else { ++other_class_virtual_; @@ -162,7 +162,7 @@ void CountDexIndices::ProcessDexFile(const DexFile& dex_file) { case Instruction::INVOKE_DIRECT_RANGE: { bool is_range = (inst->Opcode() == Instruction::INVOKE_DIRECT_RANGE); uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c(); - if (dex_file.GetMethodId(method_idx).class_idx_ == accessor.GetDescriptorIndex()) { + if (dex_file.GetMethodId(method_idx).class_idx_ == accessor.GetClassIdx()) { ++same_class_direct_; } else { ++other_class_direct_; @@ -174,7 +174,7 @@ void CountDexIndices::ProcessDexFile(const DexFile& dex_file) { case Instruction::INVOKE_STATIC_RANGE: { bool is_range = (inst->Opcode() == Instruction::INVOKE_STATIC_RANGE); uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c(); - if (dex_file.GetMethodId(method_idx).class_idx_ == accessor.GetDescriptorIndex()) { + if (dex_file.GetMethodId(method_idx).class_idx_ == accessor.GetClassIdx()) { ++same_class_static_; } else { ++other_class_static_; |