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/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);
}