Cache `DexCache` and class in `InitImageMethodVisitor`.
Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing
Bug: 181943478
Change-Id: I31f9efda0ed5797a27f31f4a48ab5d087b69e350
diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc
index 5e037c4..7c73187 100644
--- a/dex2oat/linker/oat_writer.cc
+++ b/dex2oat/linker/oat_writer.cc
@@ -1153,7 +1153,7 @@
// Visit every compiled method in order to determine its order within the OAT file.
// Methods from the same class do not need to be adjacent in the OAT code.
-class OatWriter::LayoutCodeMethodVisitor : public OatDexMethodVisitor {
+class OatWriter::LayoutCodeMethodVisitor final : public OatDexMethodVisitor {
public:
LayoutCodeMethodVisitor(OatWriter* writer, size_t offset)
: OatDexMethodVisitor(writer, offset),
@@ -1161,7 +1161,7 @@
profile_index_dex_file_(nullptr) {
}
- bool StartClass(const DexFile* dex_file, size_t class_def_index) override {
+ bool StartClass(const DexFile* dex_file, size_t class_def_index) final {
// Update the cached `profile_index_` if needed. This happens only once per dex file
// because we visit all classes in a dex file together, so mark that as `UNLIKELY`.
if (UNLIKELY(dex_file != profile_index_dex_file_)) {
@@ -1175,14 +1175,7 @@
return OatDexMethodVisitor::StartClass(dex_file, class_def_index);
}
- bool EndClass() override {
- OatDexMethodVisitor::EndClass();
- return true;
- }
-
- bool VisitMethod(size_t class_def_method_index,
- const ClassAccessor::Method& method)
- override
+ bool VisitMethod(size_t class_def_method_index, const ClassAccessor::Method& method) final
REQUIRES_SHARED(Locks::mutator_lock_) {
Locks::mutator_lock_->AssertSharedHeld(Thread::Current());
@@ -1530,40 +1523,51 @@
CodeInfo::Deduper dedupe_bit_table_;
};
-class OatWriter::InitImageMethodVisitor : public OatDexMethodVisitor {
+class OatWriter::InitImageMethodVisitor final : public OatDexMethodVisitor {
public:
InitImageMethodVisitor(OatWriter* writer,
size_t offset,
const std::vector<const DexFile*>* dex_files)
+ REQUIRES_SHARED(Locks::mutator_lock_)
: OatDexMethodVisitor(writer, offset),
pointer_size_(GetInstructionSetPointerSize(writer_->compiler_options_.GetInstructionSet())),
- class_loader_(writer->HasImage() ? writer->image_writer_->GetAppClassLoader() : nullptr),
+ class_loader_(writer->image_writer_->GetAppClassLoader()),
dex_files_(dex_files),
class_linker_(Runtime::Current()->GetClassLinker()),
- is_image_class_(false) {}
+ dex_cache_dex_file_(nullptr),
+ dex_cache_(nullptr),
+ klass_(nullptr) {}
// Handle copied methods here. Copy pointer to quick code from
// an origin method to a copied method only if they are
// in the same oat file. If the origin and the copied methods are
// in different oat files don't touch the copied method.
// References to other oat files are not supported yet.
- bool StartClass(const DexFile* dex_file, size_t class_def_index) override
+ bool StartClass(const DexFile* dex_file, size_t class_def_index) final
REQUIRES_SHARED(Locks::mutator_lock_) {
OatDexMethodVisitor::StartClass(dex_file, class_def_index);
// Skip classes that are not in the image.
const dex::TypeId& type_id =
dex_file_->GetTypeId(dex_file->GetClassDef(class_def_index).class_idx_);
const char* class_descriptor = dex_file->GetTypeDescriptor(type_id);
- is_image_class_ = writer_->GetCompilerOptions().IsImageClass(class_descriptor);
- if (!is_image_class_) {
+ if (!writer_->GetCompilerOptions().IsImageClass(class_descriptor)) {
+ klass_ = nullptr;
return true;
}
- ObjPtr<mirror::DexCache> dex_cache = class_linker_->FindDexCache(Thread::Current(), *dex_file);
+ if (UNLIKELY(dex_file != dex_cache_dex_file_)) {
+ dex_cache_ = class_linker_->FindDexCache(Thread::Current(), *dex_file);
+ DCHECK(dex_cache_ != nullptr);
+ DCHECK(dex_cache_->GetDexFile() == dex_file);
+ dex_cache_dex_file_ = dex_file;
+ }
const dex::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
- ObjPtr<mirror::Class> klass =
- class_linker_->LookupResolvedType(class_def.class_idx_, dex_cache, class_loader_);
- if (klass != nullptr) {
- for (ArtMethod& method : klass->GetCopiedMethods(pointer_size_)) {
+ klass_ = class_linker_->LookupResolvedType(class_def.class_idx_, dex_cache_, class_loader_);
+ if (klass_ != nullptr) {
+ if (UNLIKELY(klass_->GetDexCache() != dex_cache_)) {
+ klass_ = nullptr; // This class definition is hidden by another dex file.
+ return true;
+ }
+ for (ArtMethod& method : klass_->GetCopiedMethods(pointer_size_)) {
// Find origin method. Declaring class and dex_method_idx
// in the copied method should be the same as in the origin
// method.
@@ -1590,46 +1594,29 @@
return true;
}
- bool VisitMethod(size_t class_def_method_index, const ClassAccessor::Method& method) override
+ bool VisitMethod(size_t class_def_method_index, const ClassAccessor::Method& method) final
REQUIRES_SHARED(Locks::mutator_lock_) {
// Skip methods that are not in the image.
- if (!is_image_class_) {
+ if (klass_ == nullptr) {
return true;
}
OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
- OatMethodOffsets offsets(0u);
if (HasCompiledCode(compiled_method)) {
DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
- offsets = oat_class->method_offsets_[method_offsets_index_];
+ OatMethodOffsets offsets = oat_class->method_offsets_[method_offsets_index_];
++method_offsets_index_;
- }
- Thread* self = Thread::Current();
- ObjPtr<mirror::DexCache> dex_cache = class_linker_->FindDexCache(self, *dex_file_);
- ArtMethod* resolved_method;
- if (writer_->GetCompilerOptions().IsBootImage() ||
- writer_->GetCompilerOptions().IsBootImageExtension()) {
- resolved_method = class_linker_->LookupResolvedMethod(
- method.GetIndex(), dex_cache, /*class_loader=*/ nullptr);
- if (resolved_method == nullptr) {
- LOG(FATAL) << "Unexpected failure to look up a method: "
- << dex_file_->PrettyMethod(method.GetIndex(), true);
- UNREACHABLE();
- }
- } else {
- // Should already have been resolved by the compiler.
- // It may not be resolved if the class failed to verify, in this case, don't set the
- // entrypoint. This is not fatal since we shall use a resolution method.
- resolved_method = class_linker_->LookupResolvedMethod(method.GetIndex(),
- dex_cache,
- class_loader_);
- }
- if (resolved_method != nullptr &&
- compiled_method != nullptr &&
- compiled_method->GetQuickCode().size() != 0) {
+ // Do not try to use the `DexCache` via `ClassLinker::LookupResolvedMethod()`.
+ // As we're going over all methods, `DexCache` entries would be quickly evicted
+ // and we do not want the overhead of `hiddenapi` checks in the slow-path call
+ // to `ClassLinker::FindResolvedMethod()` for a method that we have compiled.
+ ArtMethod* resolved_method = klass_->IsInterface()
+ ? klass_->FindInterfaceMethod(dex_cache_, method.GetIndex(), pointer_size_)
+ : klass_->FindClassMethod(dex_cache_, method.GetIndex(), pointer_size_);
+ DCHECK(resolved_method != nullptr);
resolved_method->SetEntryPointFromQuickCompiledCodePtrSize(
reinterpret_cast<void*>(offsets.code_offset_), pointer_size_);
}
@@ -1661,7 +1648,9 @@
const ObjPtr<mirror::ClassLoader> class_loader_;
const std::vector<const DexFile*>* dex_files_;
ClassLinker* const class_linker_;
- bool is_image_class_; // Updated in `StartClass()`.
+ const DexFile* dex_cache_dex_file_; // Updated in `StartClass()`.
+ ObjPtr<mirror::DexCache> dex_cache_; // Updated in `StartClass()`.
+ ObjPtr<mirror::Class> klass_; // Updated in `StartClass()`.
std::vector<std::pair<ArtMethod*, ArtMethod*>> methods_to_process_;
};