Move compiler/ to ClassAccessor
Remove usages of ClassDataItemIterator to reduces boiler plate code.
Bug: 79758018
Bug: 77709234
Test: test-art-host
Change-Id: Id41db3299bba3ea8debcbb0b9c721fa675adc064
diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc
index be8641f..68155d8 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 @@
// 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 7dc44fa..1b809d2 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 @@
}
}
-// 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
// 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());
- }
- }
- 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());
- }
- }
- it.Next();
- }
+ // 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) {
- 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());
- }
- it.Next();
+ 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());
}
- DCHECK(!it.HasNext());
}
- }
+ };
+ 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());
+ }
+ }
+ },
+ // 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;
+ }
+ 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 @@
}
}
-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 @@
// 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 @@
// 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 @@
} 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 @@
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 @@
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 @@
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 @@
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 06f0bcd..103862b 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 @@
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 5cfbcaa..a082142 100644
--- a/libdexfile/dex/class_accessor-inl.h
+++ b/libdexfile/dex/class_accessor-inl.h
@@ -38,14 +38,14 @@
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 @@
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 @@
}
}
{
- 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 @@
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 @@
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 835c4e2..72bc50b 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 @@
// 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 @@
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 @@
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 db3ff95..b75a95b 100644
--- a/libdexfile/dex/dex_instruction_iterator.h
+++ b/libdexfile/dex/dex_instruction_iterator.h
@@ -123,7 +123,7 @@
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 427a465..312a7b3 100644
--- a/tools/dexanalyze/dexanalyze_experiments.cc
+++ b/tools/dexanalyze/dexanalyze_experiments.cc
@@ -150,7 +150,7 @@
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 @@
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 @@
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_;