Merge "ARM: VIXL32: Fix the assembler usage in the intrinsics."
diff --git a/compiler/compiled_method.h b/compiler/compiled_method.h
index 99b0ac1..174e85e 100644
--- a/compiler/compiled_method.h
+++ b/compiler/compiled_method.h
@@ -26,6 +26,7 @@
#include "base/array_ref.h"
#include "base/bit_utils.h"
#include "base/length_prefixed_array.h"
+#include "dex_file_types.h"
#include "method_reference.h"
namespace art {
@@ -302,9 +303,9 @@
return target_dex_file_;
}
- uint32_t TargetTypeIndex() const {
+ dex::TypeIndex TargetTypeIndex() const {
DCHECK(patch_type_ == Type::kType || patch_type_ == Type::kTypeRelative);
- return type_idx_;
+ return dex::TypeIndex(type_idx_);
}
const DexFile* TargetStringDexFile() const {
diff --git a/compiler/dex/verified_method.cc b/compiler/dex/verified_method.cc
index e19fb7b..1bdace9 100644
--- a/compiler/dex/verified_method.cc
+++ b/compiler/dex/verified_method.cc
@@ -230,7 +230,7 @@
const verifier::RegType& reg_type(line->GetRegisterType(method_verifier,
inst->VRegA_21c()));
const verifier::RegType& cast_type =
- method_verifier->ResolveCheckedClass(inst->VRegB_21c());
+ method_verifier->ResolveCheckedClass(dex::TypeIndex(inst->VRegB_21c()));
is_safe_cast = cast_type.IsStrictlyAssignableFrom(reg_type, method_verifier);
} else {
const verifier::RegType& array_type(line->GetRegisterType(method_verifier,
diff --git a/compiler/driver/compiler_driver-inl.h b/compiler/driver/compiler_driver-inl.h
index 9711516..f056dd3 100644
--- a/compiler/driver/compiler_driver-inl.h
+++ b/compiler/driver/compiler_driver-inl.h
@@ -38,7 +38,7 @@
inline mirror::Class* CompilerDriver::ResolveClass(
const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
- Handle<mirror::ClassLoader> class_loader, uint16_t cls_index,
+ Handle<mirror::ClassLoader> class_loader, dex::TypeIndex cls_index,
const DexCompilationUnit* mUnit) {
DCHECK_EQ(dex_cache->GetDexFile(), mUnit->GetDexFile());
DCHECK_EQ(class_loader.Get(), GetClassLoader(soa, mUnit));
@@ -141,7 +141,7 @@
mirror::Class* referrer_class,
ArtMember* resolved_member,
uint16_t member_idx,
- uint32_t* storage_index) {
+ dex::TypeIndex* storage_index) {
DCHECK(resolved_member->IsStatic());
if (LIKELY(referrer_class != nullptr)) {
ObjPtr<mirror::Class> members_class = resolved_member->GetDeclaringClass();
@@ -156,7 +156,7 @@
// TODO: for images we can elide the static storage base null check
// if we know there's a non-null entry in the image
const DexFile* dex_file = dex_cache->GetDexFile();
- uint32_t storage_idx = DexFile::kDexNoIndex;
+ dex::TypeIndex storage_idx(DexFile::kDexNoIndex16);
if (LIKELY(members_class->GetDexCache() == dex_cache)) {
// common case where the dex cache of both the referrer and the member are the same,
// no need to search the dex file
@@ -166,27 +166,27 @@
// of the class mentioned in the dex file and there is no dex cache entry.
storage_idx = resolved_member->GetDeclaringClass()->FindTypeIndexInOtherDexFile(*dex_file);
}
- if (storage_idx != DexFile::kDexNoIndex) {
+ if (storage_idx.IsValid()) {
*storage_index = storage_idx;
return std::make_pair(true, !resolved_member->IsFinal());
}
}
}
// Conservative defaults.
- *storage_index = DexFile::kDexNoIndex;
+ *storage_index = dex::TypeIndex(DexFile::kDexNoIndex16);
return std::make_pair(false, false);
}
inline std::pair<bool, bool> CompilerDriver::IsFastStaticField(
mirror::DexCache* dex_cache, mirror::Class* referrer_class,
- ArtField* resolved_field, uint16_t field_idx, uint32_t* storage_index) {
+ ArtField* resolved_field, uint16_t field_idx, dex::TypeIndex* storage_index) {
return IsClassOfStaticMemberAvailableToReferrer(
dex_cache, referrer_class, resolved_field, field_idx, storage_index);
}
inline bool CompilerDriver::IsClassOfStaticMethodAvailableToReferrer(
mirror::DexCache* dex_cache, mirror::Class* referrer_class,
- ArtMethod* resolved_method, uint16_t method_idx, uint32_t* storage_index) {
+ ArtMethod* resolved_method, uint16_t method_idx, dex::TypeIndex* storage_index) {
std::pair<bool, bool> result = IsClassOfStaticMemberAvailableToReferrer(
dex_cache, referrer_class, resolved_method, method_idx, storage_index);
// Only the first member of `result` is meaningful, as there is no
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index aa0d10b..c62e214 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -969,7 +969,7 @@
}
DCHECK(profile_compilation_info_ != nullptr);
const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_idx);
- uint16_t type_idx = class_def.class_idx_;
+ dex::TypeIndex type_idx = class_def.class_idx_;
bool result = profile_compilation_info_->ContainsClass(dex_file, type_idx);
if (kDebugProfileGuidedCompilation) {
LOG(INFO) << "[ProfileGuidedCompilation] " << (result ? "Verified" : "Skipped") << " method:"
@@ -981,7 +981,7 @@
class ResolveCatchBlockExceptionsClassVisitor : public ClassVisitor {
public:
explicit ResolveCatchBlockExceptionsClassVisitor(
- std::set<std::pair<uint16_t, const DexFile*>>& exceptions_to_resolve)
+ std::set<std::pair<dex::TypeIndex, const DexFile*>>& exceptions_to_resolve)
: exceptions_to_resolve_(exceptions_to_resolve) {}
virtual bool operator()(ObjPtr<mirror::Class> c) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
@@ -1012,8 +1012,8 @@
has_catch_all = true;
}
for (int32_t j = 0; j < encoded_catch_handler_size; j++) {
- uint16_t encoded_catch_handler_handlers_type_idx =
- DecodeUnsignedLeb128(&encoded_catch_handler_list);
+ dex::TypeIndex encoded_catch_handler_handlers_type_idx =
+ dex::TypeIndex(DecodeUnsignedLeb128(&encoded_catch_handler_list));
// Add to set of types to resolve if not already in the dex cache resolved types
if (!method_handle->IsResolvedTypeIdx(encoded_catch_handler_handlers_type_idx,
pointer_size)) {
@@ -1030,7 +1030,7 @@
}
}
- std::set<std::pair<uint16_t, const DexFile*>>& exceptions_to_resolve_;
+ std::set<std::pair<dex::TypeIndex, const DexFile*>>& exceptions_to_resolve_;
};
class RecordImageClassesVisitor : public ClassVisitor {
@@ -1078,7 +1078,7 @@
// Resolve exception classes referenced by the loaded classes. The catch logic assumes
// exceptions are resolved by the verifier when there is a catch block in an interested method.
// Do this here so that exception classes appear to have been specified image classes.
- std::set<std::pair<uint16_t, const DexFile*>> unresolved_exception_types;
+ std::set<std::pair<dex::TypeIndex, const DexFile*>> unresolved_exception_types;
StackHandleScope<1> hs(self);
Handle<mirror::Class> java_lang_Throwable(
hs.NewHandle(class_linker->FindSystemClass(self, "Ljava/lang/Throwable;")));
@@ -1086,8 +1086,8 @@
unresolved_exception_types.clear();
ResolveCatchBlockExceptionsClassVisitor visitor(unresolved_exception_types);
class_linker->VisitClasses(&visitor);
- for (const std::pair<uint16_t, const DexFile*>& exception_type : unresolved_exception_types) {
- uint16_t exception_type_idx = exception_type.first;
+ for (const auto& exception_type : unresolved_exception_types) {
+ dex::TypeIndex exception_type_idx = exception_type.first;
const DexFile* dex_file = exception_type.second;
StackHandleScope<2> hs2(self);
Handle<mirror::DexCache> dex_cache(hs2.NewHandle(class_linker->RegisterDexFile(*dex_file,
@@ -1338,7 +1338,7 @@
bool CompilerDriver::CanAccessTypeWithoutChecks(uint32_t referrer_idx,
Handle<mirror::DexCache> dex_cache,
- uint32_t type_idx) {
+ dex::TypeIndex type_idx) {
// Get type from dex cache assuming it was populated by the verifier
mirror::Class* resolved_class = dex_cache->GetResolvedType(type_idx);
if (resolved_class == nullptr) {
@@ -1367,7 +1367,7 @@
bool CompilerDriver::CanAccessInstantiableTypeWithoutChecks(uint32_t referrer_idx,
Handle<mirror::DexCache> dex_cache,
- uint32_t type_idx,
+ dex::TypeIndex type_idx,
bool* finalizable) {
// Get type from dex cache assuming it was populated by the verifier.
mirror::Class* resolved_class = dex_cache->GetResolvedType(type_idx);
@@ -1861,7 +1861,7 @@
public:
explicit ResolveTypeVisitor(const ParallelCompilationManager* manager) : manager_(manager) {
}
- virtual void Visit(size_t type_idx) OVERRIDE REQUIRES(!Locks::mutator_lock_) {
+ void Visit(size_t type_idx) OVERRIDE REQUIRES(!Locks::mutator_lock_) {
// Class derived values are more complicated, they require the linker and loader.
ScopedObjectAccess soa(Thread::Current());
ClassLinker* class_linker = manager_->GetClassLinker();
@@ -1872,7 +1872,10 @@
Handle<mirror::DexCache> dex_cache(hs.NewHandle(class_linker->RegisterDexFile(
dex_file,
class_loader.Get())));
- mirror::Class* klass = class_linker->ResolveType(dex_file, type_idx, dex_cache, class_loader);
+ mirror::Class* klass = class_linker->ResolveType(dex_file,
+ dex::TypeIndex(type_idx),
+ dex_cache,
+ class_loader);
if (klass == nullptr) {
soa.Self()->AssertPendingException();
@@ -1952,9 +1955,9 @@
for (const DexFile* dex_file : dex_files) {
// Fetch the list of unverified classes and turn it into a set for faster
// lookups.
- const std::vector<uint16_t>& unverified_classes =
+ const std::vector<dex::TypeIndex>& unverified_classes =
verifier_deps->GetUnverifiedClasses(*dex_file);
- std::set<uint16_t> set(unverified_classes.begin(), unverified_classes.end());
+ std::set<dex::TypeIndex> set(unverified_classes.begin(), unverified_classes.end());
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);
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index 1bd3546..c7719fb 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -31,6 +31,7 @@
#include "class_reference.h"
#include "compiler.h"
#include "dex_file.h"
+#include "dex_file_types.h"
#include "driver/compiled_method_storage.h"
#include "jit/offline_profiling_info.h"
#include "invoke_type.h"
@@ -188,14 +189,14 @@
// Are runtime access checks necessary in the compiled code?
bool CanAccessTypeWithoutChecks(uint32_t referrer_idx,
Handle<mirror::DexCache> dex_cache,
- uint32_t type_idx)
+ dex::TypeIndex type_idx)
REQUIRES_SHARED(Locks::mutator_lock_);
// Are runtime access and instantiable checks necessary in the code?
// out_is_finalizable is set to whether the type is finalizable.
bool CanAccessInstantiableTypeWithoutChecks(uint32_t referrer_idx,
Handle<mirror::DexCache> dex_cache,
- uint32_t type_idx,
+ dex::TypeIndex type_idx,
bool* out_is_finalizable)
REQUIRES_SHARED(Locks::mutator_lock_);
@@ -207,7 +208,7 @@
mirror::Class* ResolveClass(
const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
- Handle<mirror::ClassLoader> class_loader, uint16_t type_index,
+ Handle<mirror::ClassLoader> class_loader, dex::TypeIndex type_index,
const DexCompilationUnit* mUnit)
REQUIRES_SHARED(Locks::mutator_lock_);
@@ -234,9 +235,11 @@
// Can we fast-path an SGET/SPUT access to a static field? If yes, compute the type index
// of the declaring class in the referrer's dex file.
- std::pair<bool, bool> IsFastStaticField(
- mirror::DexCache* dex_cache, mirror::Class* referrer_class,
- ArtField* resolved_field, uint16_t field_idx, uint32_t* storage_index)
+ std::pair<bool, bool> IsFastStaticField(mirror::DexCache* dex_cache,
+ mirror::Class* referrer_class,
+ ArtField* resolved_field,
+ uint16_t field_idx,
+ dex::TypeIndex* storage_index)
REQUIRES_SHARED(Locks::mutator_lock_);
// Return whether the declaring class of `resolved_method` is
@@ -248,7 +251,7 @@
mirror::Class* referrer_class,
ArtMethod* resolved_method,
uint16_t method_idx,
- uint32_t* storage_index)
+ dex::TypeIndex* storage_index)
REQUIRES_SHARED(Locks::mutator_lock_);
// Resolve a method. Returns null on failure, including incompatible class change.
@@ -395,7 +398,7 @@
mirror::Class* referrer_class,
ArtMember* resolved_member,
uint16_t member_idx,
- uint32_t* storage_index)
+ dex::TypeIndex* storage_index)
REQUIRES_SHARED(Locks::mutator_lock_);
// Can `referrer_class` access the resolved `member`?
diff --git a/compiler/driver/compiler_driver_test.cc b/compiler/driver/compiler_driver_test.cc
index 9679a79..f40c712 100644
--- a/compiler/driver/compiler_driver_test.cc
+++ b/compiler/driver/compiler_driver_test.cc
@@ -24,6 +24,7 @@
#include "class_linker-inl.h"
#include "common_compiler_test.h"
#include "dex_file.h"
+#include "dex_file_types.h"
#include "gc/heap.h"
#include "mirror/class-inl.h"
#include "mirror/class_loader.h"
@@ -115,9 +116,9 @@
}
EXPECT_EQ(dex.NumTypeIds(), dex_cache->NumResolvedTypes());
for (size_t i = 0; i < dex_cache->NumResolvedTypes(); i++) {
- mirror::Class* type = dex_cache->GetResolvedType(i);
+ mirror::Class* type = dex_cache->GetResolvedType(dex::TypeIndex(i));
EXPECT_TRUE(type != nullptr) << "type_idx=" << i
- << " " << dex.GetTypeDescriptor(dex.GetTypeId(i));
+ << " " << dex.GetTypeDescriptor(dex.GetTypeId(dex::TypeIndex(i)));
}
EXPECT_EQ(dex.NumMethodIds(), dex_cache->NumResolvedMethods());
auto* cl = Runtime::Current()->GetClassLinker();
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index d7b7403..a882a88 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -32,6 +32,7 @@
#include "class_linker-inl.h"
#include "compiled_method.h"
#include "dex_file-inl.h"
+#include "dex_file_types.h"
#include "driver/compiler_driver.h"
#include "elf_file.h"
#include "elf_utils.h"
@@ -837,19 +838,64 @@
return true;
}
-class ImageWriter::NonImageClassesVisitor : public ClassVisitor {
+class ImageWriter::PruneClassesVisitor : public ClassVisitor {
public:
- explicit NonImageClassesVisitor(ImageWriter* image_writer) : image_writer_(image_writer) {}
+ PruneClassesVisitor(ImageWriter* image_writer, ObjPtr<mirror::ClassLoader> class_loader)
+ : image_writer_(image_writer),
+ class_loader_(class_loader),
+ classes_to_prune_(),
+ defined_class_count_(0u) { }
- bool operator()(ObjPtr<Class> klass) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
+ bool operator()(ObjPtr<mirror::Class> klass) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
if (!image_writer_->KeepClass(klass.Ptr())) {
classes_to_prune_.insert(klass.Ptr());
+ if (klass->GetClassLoader() == class_loader_) {
+ ++defined_class_count_;
+ }
}
return true;
}
- std::unordered_set<mirror::Class*> classes_to_prune_;
+ size_t Prune() REQUIRES_SHARED(Locks::mutator_lock_) {
+ ClassTable* class_table =
+ Runtime::Current()->GetClassLinker()->ClassTableForClassLoader(class_loader_);
+ for (mirror::Class* klass : classes_to_prune_) {
+ std::string storage;
+ const char* descriptor = klass->GetDescriptor(&storage);
+ bool result = class_table->Remove(descriptor);
+ DCHECK(result);
+ }
+ return defined_class_count_;
+ }
+
+ private:
ImageWriter* const image_writer_;
+ const ObjPtr<mirror::ClassLoader> class_loader_;
+ std::unordered_set<mirror::Class*> classes_to_prune_;
+ size_t defined_class_count_;
+};
+
+class ImageWriter::PruneClassLoaderClassesVisitor : public ClassLoaderVisitor {
+ public:
+ explicit PruneClassLoaderClassesVisitor(ImageWriter* image_writer)
+ : image_writer_(image_writer), removed_class_count_(0) {}
+
+ virtual void Visit(ObjPtr<mirror::ClassLoader> class_loader) OVERRIDE
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ PruneClassesVisitor classes_visitor(image_writer_, class_loader);
+ ClassTable* class_table =
+ Runtime::Current()->GetClassLinker()->ClassTableForClassLoader(class_loader);
+ class_table->Visit(classes_visitor);
+ removed_class_count_ += classes_visitor.Prune();
+ }
+
+ size_t GetRemovedClassCount() const {
+ return removed_class_count_;
+ }
+
+ private:
+ ImageWriter* const image_writer_;
+ size_t removed_class_count_;
};
void ImageWriter::PruneNonImageClasses() {
@@ -861,21 +907,13 @@
// path dex caches.
class_linker->ClearClassTableStrongRoots();
- // Make a list of classes we would like to prune.
- NonImageClassesVisitor visitor(this);
- class_linker->VisitClasses(&visitor);
-
// Remove the undesired classes from the class roots.
- VLOG(compiler) << "Pruning " << visitor.classes_to_prune_.size() << " classes";
- for (mirror::Class* klass : visitor.classes_to_prune_) {
- std::string temp;
- const char* name = klass->GetDescriptor(&temp);
- VLOG(compiler) << "Pruning class " << name;
- if (!compile_app_image_) {
- DCHECK(IsBootClassLoaderClass(klass));
- }
- bool result = class_linker->RemoveClass(name, klass->GetClassLoader());
- DCHECK(result);
+ {
+ ReaderMutexLock mu(self, *Locks::classlinker_classes_lock_);
+ PruneClassLoaderClassesVisitor class_loader_visitor(this);
+ class_loader_visitor.Visit(nullptr); // Visit boot class loader.
+ class_linker->VisitClassLoaders(&class_loader_visitor);
+ VLOG(compiler) << "Pruned " << class_loader_visitor.GetRemovedClassCount() << " classes";
}
// Clear references to removed classes from the DexCaches.
@@ -890,9 +928,9 @@
}
ObjPtr<mirror::DexCache> dex_cache = self->DecodeJObject(data.weak_root)->AsDexCache();
for (size_t i = 0; i < dex_cache->NumResolvedTypes(); i++) {
- Class* klass = dex_cache->GetResolvedType(i);
+ Class* klass = dex_cache->GetResolvedType(dex::TypeIndex(i));
if (klass != nullptr && !KeepClass(klass)) {
- dex_cache->SetResolvedType(i, nullptr);
+ dex_cache->SetResolvedType(dex::TypeIndex(i), nullptr);
}
}
ArtMethod** resolved_methods = dex_cache->GetResolvedMethods();
diff --git a/compiler/image_writer.h b/compiler/image_writer.h
index 24fad46..ad6ffd8 100644
--- a/compiler/image_writer.h
+++ b/compiler/image_writer.h
@@ -588,7 +588,8 @@
class FixupVisitor;
class GetRootsVisitor;
class NativeLocationVisitor;
- class NonImageClassesVisitor;
+ class PruneClassesVisitor;
+ class PruneClassLoaderClassesVisitor;
class VisitReferencesVisitor;
DISALLOW_COPY_AND_ASSIGN(ImageWriter);
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index f9173f5..bde00cf 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -260,16 +260,7 @@
// Data to write to a separate section.
dchecked_vector<uint32_t> class_offsets_;
- void InitTypeLookupTable(const DexFile& dex_file, uint8_t* storage) const {
- lookup_table_.reset(TypeLookupTable::Create(dex_file, storage));
- }
-
- TypeLookupTable* GetTypeLookupTable() const {
- return lookup_table_.get();
- }
-
private:
- mutable std::unique_ptr<TypeLookupTable> lookup_table_;
size_t GetClassOffsetsRawSize() const {
return class_offsets_.size() * sizeof(class_offsets_[0]);
}
@@ -2481,8 +2472,15 @@
// Create the lookup table. When `nullptr` is given as the storage buffer,
// TypeLookupTable allocates its own and OatDexFile takes ownership.
- oat_dex_file->InitTypeLookupTable(*opened_dex_files[i], /* storage */ nullptr);
- TypeLookupTable* table = oat_dex_file->GetTypeLookupTable();
+ const DexFile& dex_file = *opened_dex_files[i];
+ {
+ std::unique_ptr<TypeLookupTable> type_lookup_table =
+ TypeLookupTable::Create(dex_file, /* storage */ nullptr);
+ type_lookup_table_oat_dex_files_.push_back(
+ std::make_unique<art::OatDexFile>(std::move(type_lookup_table)));
+ dex_file.SetOatDexFile(type_lookup_table_oat_dex_files_.back().get());
+ }
+ TypeLookupTable* const table = type_lookup_table_oat_dex_files_.back()->GetTypeLookupTable();
// Type tables are required to be 4 byte aligned.
size_t initial_offset = oat_size_;
diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h
index 3d08ad3..b92ba76 100644
--- a/compiler/oat_writer.h
+++ b/compiler/oat_writer.h
@@ -363,6 +363,9 @@
// Offset of the oat data from the start of the mmapped region of the elf file.
size_t oat_data_offset_;
+ // Fake OatDexFiles to hold type lookup tables for the compiler.
+ std::vector<std::unique_ptr<art::OatDexFile>> type_lookup_table_oat_dex_files_;
+
// data to write
std::unique_ptr<OatHeader> oat_header_;
dchecked_vector<OatDexFile> oat_dex_files_;
diff --git a/compiler/optimizing/bounds_check_elimination_test.cc b/compiler/optimizing/bounds_check_elimination_test.cc
index b7c24ff..dfa1504 100644
--- a/compiler/optimizing/bounds_check_elimination_test.cc
+++ b/compiler/optimizing/bounds_check_elimination_test.cc
@@ -70,9 +70,9 @@
graph_->AddBlock(entry);
graph_->SetEntryBlock(entry);
HInstruction* parameter1 = new (&allocator_)
- HParameterValue(graph_->GetDexFile(), 0, 0, Primitive::kPrimNot); // array
+ HParameterValue(graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot); // array
HInstruction* parameter2 = new (&allocator_)
- HParameterValue(graph_->GetDexFile(), 0, 0, Primitive::kPrimInt); // i
+ HParameterValue(graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt); // i
entry->AddInstruction(parameter1);
entry->AddInstruction(parameter2);
@@ -167,9 +167,9 @@
graph_->AddBlock(entry);
graph_->SetEntryBlock(entry);
HInstruction* parameter1 = new (&allocator_)
- HParameterValue(graph_->GetDexFile(), 0, 0, Primitive::kPrimNot); // array
+ HParameterValue(graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot); // array
HInstruction* parameter2 = new (&allocator_)
- HParameterValue(graph_->GetDexFile(), 0, 0, Primitive::kPrimInt); // i
+ HParameterValue(graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt); // i
entry->AddInstruction(parameter1);
entry->AddInstruction(parameter2);
@@ -231,9 +231,9 @@
graph_->AddBlock(entry);
graph_->SetEntryBlock(entry);
HInstruction* parameter1 = new (&allocator_)
- HParameterValue(graph_->GetDexFile(), 0, 0, Primitive::kPrimNot); // array
+ HParameterValue(graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot); // array
HInstruction* parameter2 = new (&allocator_)
- HParameterValue(graph_->GetDexFile(), 0, 0, Primitive::kPrimInt); // i
+ HParameterValue(graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt); // i
entry->AddInstruction(parameter1);
entry->AddInstruction(parameter2);
@@ -295,7 +295,7 @@
graph_->AddBlock(entry);
graph_->SetEntryBlock(entry);
HInstruction* parameter = new (&allocator_) HParameterValue(
- graph_->GetDexFile(), 0, 0, Primitive::kPrimNot);
+ graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
entry->AddInstruction(parameter);
HInstruction* constant_5 = graph_->GetIntConstant(5);
@@ -364,7 +364,7 @@
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
HInstruction* parameter = new (allocator) HParameterValue(
- graph->GetDexFile(), 0, 0, Primitive::kPrimNot);
+ graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
entry->AddInstruction(parameter);
HInstruction* constant_initial = graph->GetIntConstant(initial);
@@ -479,7 +479,7 @@
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
HInstruction* parameter = new (allocator) HParameterValue(
- graph->GetDexFile(), 0, 0, Primitive::kPrimNot);
+ graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
entry->AddInstruction(parameter);
HInstruction* constant_initial = graph->GetIntConstant(initial);
@@ -600,7 +600,7 @@
constant_10,
graph->GetCurrentMethod(),
0,
- Primitive::kPrimInt,
+ dex::TypeIndex(static_cast<uint16_t>(Primitive::kPrimInt)),
graph->GetDexFile(),
kQuickAllocArray);
block->AddInstruction(new_array);
@@ -692,7 +692,7 @@
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
HInstruction* parameter = new (allocator) HParameterValue(
- graph->GetDexFile(), 0, 0, Primitive::kPrimNot);
+ graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
entry->AddInstruction(parameter);
HInstruction* constant_initial = graph->GetIntConstant(initial);
@@ -795,7 +795,7 @@
graph_->AddBlock(entry);
graph_->SetEntryBlock(entry);
HInstruction* parameter = new (&allocator_) HParameterValue(
- graph_->GetDexFile(), 0, 0, Primitive::kPrimNot);
+ graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
entry->AddInstruction(parameter);
HInstruction* constant_0 = graph_->GetIntConstant(0);
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index a341086..8a6b94e 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -383,7 +383,7 @@
SaveLiveRegisters(codegen, locations);
InvokeRuntimeCallingConvention calling_convention;
- __ LoadImmediate(calling_convention.GetRegisterAt(0), cls_->GetTypeIndex());
+ __ LoadImmediate(calling_convention.GetRegisterAt(0), cls_->GetTypeIndex().index_);
QuickEntrypointEnum entrypoint = do_clinit_ ? kQuickInitializeStaticStorage
: kQuickInitializeType;
arm_codegen->InvokeRuntime(entrypoint, at_, dex_pc_, this);
@@ -3953,7 +3953,7 @@
void InstructionCodeGeneratorARM::VisitNewArray(HNewArray* instruction) {
InvokeRuntimeCallingConvention calling_convention;
- __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
+ __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex().index_);
// Note: if heap poisoning is enabled, the entry point takes cares
// of poisoning the reference.
codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc());
@@ -5743,7 +5743,7 @@
void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) {
LocationSummary* locations = cls->GetLocations();
if (cls->NeedsAccessCheck()) {
- codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex());
+ codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex().index_);
codegen_->InvokeRuntime(kQuickInitializeTypeAndVerifyAccess, cls, cls->GetDexPc());
CheckEntrypointTypes<kQuickInitializeTypeAndVerifyAccess, void*, uint32_t>();
return;
@@ -5830,7 +5830,7 @@
current_method,
ArtMethod::DexCacheResolvedTypesOffset(kArmPointerSize).Int32Value());
// /* GcRoot<mirror::Class> */ out = out[type_index]
- size_t offset = CodeGenerator::GetCacheOffset(cls->GetTypeIndex());
+ size_t offset = CodeGenerator::GetCacheOffset(cls->GetTypeIndex().index_);
GenerateGcRootFieldLoad(cls, out_loc, out, offset, read_barrier_option);
generate_null_check = !cls->IsInDexCache();
}
@@ -7324,8 +7324,8 @@
}
CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeTypePatch(
- const DexFile& dex_file, uint32_t type_index) {
- return NewPcRelativePatch(dex_file, type_index, &pc_relative_type_patches_);
+ const DexFile& dex_file, dex::TypeIndex type_index) {
+ return NewPcRelativePatch(dex_file, type_index.index_, &pc_relative_type_patches_);
}
CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeDexCacheArrayPatch(
@@ -7347,7 +7347,7 @@
}
Literal* CodeGeneratorARM::DeduplicateBootImageTypeLiteral(const DexFile& dex_file,
- uint32_t type_index) {
+ dex::TypeIndex type_index) {
return boot_image_type_patches_.GetOrCreate(
TypeReference(&dex_file, type_index),
[this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
@@ -7452,7 +7452,7 @@
uint32_t literal_offset = literal->GetLabel()->Position();
linker_patches->push_back(LinkerPatch::TypePatch(literal_offset,
target_type.dex_file,
- target_type.type_index));
+ target_type.type_index.index_));
}
EmitPcRelativeLinkerPatches<LinkerPatch::RelativeTypePatch>(pc_relative_type_patches_,
linker_patches);
diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h
index 8ace3da..a4ccb57 100644
--- a/compiler/optimizing/code_generator_arm.h
+++ b/compiler/optimizing/code_generator_arm.h
@@ -19,6 +19,7 @@
#include "base/enums.h"
#include "code_generator.h"
+#include "dex_file_types.h"
#include "driver/compiler_options.h"
#include "nodes.h"
#include "string_reference.h"
@@ -481,11 +482,11 @@
};
PcRelativePatchInfo* NewPcRelativeStringPatch(const DexFile& dex_file, uint32_t string_index);
- PcRelativePatchInfo* NewPcRelativeTypePatch(const DexFile& dex_file, uint32_t type_index);
+ PcRelativePatchInfo* NewPcRelativeTypePatch(const DexFile& dex_file, dex::TypeIndex type_index);
PcRelativePatchInfo* NewPcRelativeDexCacheArrayPatch(const DexFile& dex_file,
uint32_t element_offset);
Literal* DeduplicateBootImageStringLiteral(const DexFile& dex_file, uint32_t string_index);
- Literal* DeduplicateBootImageTypeLiteral(const DexFile& dex_file, uint32_t type_index);
+ Literal* DeduplicateBootImageTypeLiteral(const DexFile& dex_file, dex::TypeIndex type_index);
Literal* DeduplicateBootImageAddressLiteral(uint32_t address);
Literal* DeduplicateDexCacheAddressLiteral(uint32_t address);
Literal* DeduplicateJitStringLiteral(const DexFile& dex_file, uint32_t string_index);
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index c9e563b..59e1784 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -288,7 +288,7 @@
SaveLiveRegisters(codegen, locations);
InvokeRuntimeCallingConvention calling_convention;
- __ Mov(calling_convention.GetRegisterAt(0).W(), cls_->GetTypeIndex());
+ __ Mov(calling_convention.GetRegisterAt(0).W(), cls_->GetTypeIndex().index_);
QuickEntrypointEnum entrypoint = do_clinit_ ? kQuickInitializeStaticStorage
: kQuickInitializeType;
arm64_codegen->InvokeRuntime(entrypoint, at_, dex_pc_, this);
@@ -4102,9 +4102,9 @@
vixl::aarch64::Label* CodeGeneratorARM64::NewPcRelativeTypePatch(
const DexFile& dex_file,
- uint32_t type_index,
+ dex::TypeIndex type_index,
vixl::aarch64::Label* adrp_label) {
- return NewPcRelativePatch(dex_file, type_index, adrp_label, &pc_relative_type_patches_);
+ return NewPcRelativePatch(dex_file, type_index.index_, adrp_label, &pc_relative_type_patches_);
}
vixl::aarch64::Label* CodeGeneratorARM64::NewPcRelativeDexCacheArrayPatch(
@@ -4136,7 +4136,7 @@
}
vixl::aarch64::Literal<uint32_t>* CodeGeneratorARM64::DeduplicateBootImageTypeLiteral(
- const DexFile& dex_file, uint32_t type_index) {
+ const DexFile& dex_file, dex::TypeIndex type_index) {
return boot_image_type_patches_.GetOrCreate(
TypeReference(&dex_file, type_index),
[this]() { return __ CreateLiteralDestroyedWithPool<uint32_t>(/* placeholder */ 0u); });
@@ -4257,7 +4257,7 @@
vixl::aarch64::Literal<uint32_t>* literal = entry.second;
linker_patches->push_back(LinkerPatch::TypePatch(literal->GetOffset(),
target_type.dex_file,
- target_type.type_index));
+ target_type.type_index.index_));
}
EmitPcRelativeLinkerPatches<LinkerPatch::RelativeTypePatch>(pc_relative_type_patches_,
linker_patches);
@@ -4381,7 +4381,7 @@
void InstructionCodeGeneratorARM64::VisitLoadClass(HLoadClass* cls) {
if (cls->NeedsAccessCheck()) {
- codegen_->MoveConstant(cls->GetLocations()->GetTemp(0), cls->GetTypeIndex());
+ codegen_->MoveConstant(cls->GetLocations()->GetTemp(0), cls->GetTypeIndex().index_);
codegen_->InvokeRuntime(kQuickInitializeTypeAndVerifyAccess, cls, cls->GetDexPc());
CheckEntrypointTypes<kQuickInitializeTypeAndVerifyAccess, void*, uint32_t>();
return;
@@ -4417,7 +4417,7 @@
DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
// Add ADRP with its PC-relative type patch.
const DexFile& dex_file = cls->GetDexFile();
- uint32_t type_index = cls->GetTypeIndex();
+ dex::TypeIndex type_index = cls->GetTypeIndex();
vixl::aarch64::Label* adrp_label = codegen_->NewPcRelativeTypePatch(dex_file, type_index);
codegen_->EmitAdrpPlaceholder(adrp_label, out.X());
// Add ADD with its PC-relative type patch.
@@ -4485,7 +4485,7 @@
GenerateGcRootFieldLoad(cls,
out_loc,
out.X(),
- CodeGenerator::GetCacheOffset(cls->GetTypeIndex()),
+ CodeGenerator::GetCacheOffset(cls->GetTypeIndex().index_),
/* fixup_label */ nullptr,
read_barrier_option);
generate_null_check = !cls->IsInDexCache();
@@ -4775,7 +4775,7 @@
InvokeRuntimeCallingConvention calling_convention;
Register type_index = RegisterFrom(locations->GetTemp(0), Primitive::kPrimInt);
DCHECK(type_index.Is(w0));
- __ Mov(type_index, instruction->GetTypeIndex());
+ __ Mov(type_index, instruction->GetTypeIndex().index_);
// Note: if heap poisoning is enabled, the entry point takes cares
// of poisoning the reference.
codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc());
diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h
index a2ab607..1545fd3 100644
--- a/compiler/optimizing/code_generator_arm64.h
+++ b/compiler/optimizing/code_generator_arm64.h
@@ -20,6 +20,7 @@
#include "arch/arm64/quick_method_frame_info_arm64.h"
#include "code_generator.h"
#include "common_arm64.h"
+#include "dex_file_types.h"
#include "driver/compiler_options.h"
#include "nodes.h"
#include "parallel_move_resolver.h"
@@ -547,7 +548,7 @@
// ADRP (pass `adrp_label = null`) or the ADD (pass `adrp_label` pointing
// to the associated ADRP patch label).
vixl::aarch64::Label* NewPcRelativeTypePatch(const DexFile& dex_file,
- uint32_t type_index,
+ dex::TypeIndex type_index,
vixl::aarch64::Label* adrp_label = nullptr);
// Add a new PC-relative dex cache array patch for an instruction and return
@@ -562,7 +563,7 @@
vixl::aarch64::Literal<uint32_t>* DeduplicateBootImageStringLiteral(const DexFile& dex_file,
uint32_t string_index);
vixl::aarch64::Literal<uint32_t>* DeduplicateBootImageTypeLiteral(const DexFile& dex_file,
- uint32_t type_index);
+ dex::TypeIndex type_index);
vixl::aarch64::Literal<uint32_t>* DeduplicateBootImageAddressLiteral(uint64_t address);
vixl::aarch64::Literal<uint64_t>* DeduplicateDexCacheAddressLiteral(uint64_t address);
vixl::aarch64::Literal<uint32_t>* DeduplicateJitStringLiteral(const DexFile& dex_file,
diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc
index 61e6b4b..b8d9a91 100644
--- a/compiler/optimizing/code_generator_arm_vixl.cc
+++ b/compiler/optimizing/code_generator_arm_vixl.cc
@@ -398,7 +398,7 @@
SaveLiveRegisters(codegen, locations);
InvokeRuntimeCallingConventionARMVIXL calling_convention;
- __ Mov(calling_convention.GetRegisterAt(0), cls_->GetTypeIndex());
+ __ Mov(calling_convention.GetRegisterAt(0), cls_->GetTypeIndex().index_);
QuickEntrypointEnum entrypoint = do_clinit_ ? kQuickInitializeStaticStorage
: kQuickInitializeType;
arm_codegen->InvokeRuntime(entrypoint, at_, dex_pc_, this);
@@ -3217,7 +3217,7 @@
void InstructionCodeGeneratorARMVIXL::VisitNewArray(HNewArray* instruction) {
InvokeRuntimeCallingConventionARMVIXL calling_convention;
- __ Mov(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
+ __ Mov(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex().index_);
// Note: if heap poisoning is enabled, the entry point takes cares
// of poisoning the reference.
codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc());
@@ -4968,7 +4968,7 @@
void InstructionCodeGeneratorARMVIXL::VisitLoadClass(HLoadClass* cls) {
LocationSummary* locations = cls->GetLocations();
if (cls->NeedsAccessCheck()) {
- codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex());
+ codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex().index_);
codegen_->InvokeRuntime(kQuickInitializeTypeAndVerifyAccess, cls, cls->GetDexPc());
CheckEntrypointTypes<kQuickInitializeTypeAndVerifyAccess, void*, uint32_t>();
return;
@@ -5000,7 +5000,7 @@
ArtMethod::DexCacheResolvedTypesOffset(kArmPointerSize).Int32Value();
GetAssembler()->LoadFromOffset(kLoadWord, out, current_method, resolved_types_offset);
// /* GcRoot<mirror::Class> */ out = out[type_index]
- size_t offset = CodeGenerator::GetCacheOffset(cls->GetTypeIndex());
+ size_t offset = CodeGenerator::GetCacheOffset(cls->GetTypeIndex().index_);
GenerateGcRootFieldLoad(cls, out_loc, out, offset, kEmitCompilerReadBarrier);
generate_null_check = !cls->IsInDexCache();
break;
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index fcbb8f0..8f94834 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -224,7 +224,7 @@
SaveLiveRegisters(codegen, locations);
InvokeRuntimeCallingConvention calling_convention;
- __ LoadConst32(calling_convention.GetRegisterAt(0), cls_->GetTypeIndex());
+ __ LoadConst32(calling_convention.GetRegisterAt(0), cls_->GetTypeIndex().index_);
QuickEntrypointEnum entrypoint = do_clinit_ ? kQuickInitializeStaticStorage
: kQuickInitializeType;
@@ -1056,7 +1056,7 @@
uint32_t literal_offset = __ GetLabelLocation(literal->GetLabel());
linker_patches->push_back(LinkerPatch::TypePatch(literal_offset,
target_type.dex_file,
- target_type.type_index));
+ target_type.type_index.index_));
}
for (const auto& entry : boot_image_address_patches_) {
DCHECK(GetCompilerOptions().GetIncludePatchInformation());
@@ -1073,8 +1073,8 @@
}
CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewPcRelativeTypePatch(
- const DexFile& dex_file, uint32_t type_index) {
- return NewPcRelativePatch(dex_file, type_index, &pc_relative_type_patches_);
+ const DexFile& dex_file, dex::TypeIndex type_index) {
+ return NewPcRelativePatch(dex_file, type_index.index_, &pc_relative_type_patches_);
}
CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewPcRelativeDexCacheArrayPatch(
@@ -1117,7 +1117,7 @@
}
Literal* CodeGeneratorMIPS::DeduplicateBootImageTypeLiteral(const DexFile& dex_file,
- uint32_t type_index) {
+ dex::TypeIndex type_index) {
return boot_image_type_patches_.GetOrCreate(
TypeReference(&dex_file, type_index),
[this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
@@ -5539,7 +5539,7 @@
void InstructionCodeGeneratorMIPS::VisitLoadClass(HLoadClass* cls) {
LocationSummary* locations = cls->GetLocations();
if (cls->NeedsAccessCheck()) {
- codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex());
+ codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex().index_);
codegen_->InvokeRuntime(kQuickInitializeTypeAndVerifyAccess, cls, cls->GetDexPc());
CheckEntrypointTypes<kQuickInitializeTypeAndVerifyAccess, void*, uint32_t>();
return;
@@ -5633,7 +5633,7 @@
base_or_current_method_reg,
ArtMethod::DexCacheResolvedTypesOffset(kArmPointerSize).Int32Value());
// /* GcRoot<mirror::Class> */ out = out[type_index]
- size_t offset = CodeGenerator::GetCacheOffset(cls->GetTypeIndex());
+ size_t offset = CodeGenerator::GetCacheOffset(cls->GetTypeIndex().index_);
GenerateGcRootFieldLoad(cls, out_loc, out, offset);
generate_null_check = !cls->IsInDexCache();
}
@@ -5975,7 +5975,7 @@
Register current_method_register = calling_convention.GetRegisterAt(2);
__ Lw(current_method_register, SP, kCurrentMethodStackOffset);
// Move an uint16_t value to a register.
- __ LoadConst32(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
+ __ LoadConst32(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex().index_);
codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc());
CheckEntrypointTypes<kQuickAllocArrayWithAccessCheck,
void*, uint32_t, int32_t, ArtMethod*>();
diff --git a/compiler/optimizing/code_generator_mips.h b/compiler/optimizing/code_generator_mips.h
index e132819..e225d20 100644
--- a/compiler/optimizing/code_generator_mips.h
+++ b/compiler/optimizing/code_generator_mips.h
@@ -449,11 +449,11 @@
};
PcRelativePatchInfo* NewPcRelativeStringPatch(const DexFile& dex_file, uint32_t string_index);
- PcRelativePatchInfo* NewPcRelativeTypePatch(const DexFile& dex_file, uint32_t type_index);
+ PcRelativePatchInfo* NewPcRelativeTypePatch(const DexFile& dex_file, dex::TypeIndex type_index);
PcRelativePatchInfo* NewPcRelativeDexCacheArrayPatch(const DexFile& dex_file,
uint32_t element_offset);
Literal* DeduplicateBootImageStringLiteral(const DexFile& dex_file, uint32_t string_index);
- Literal* DeduplicateBootImageTypeLiteral(const DexFile& dex_file, uint32_t type_index);
+ Literal* DeduplicateBootImageTypeLiteral(const DexFile& dex_file, dex::TypeIndex type_index);
Literal* DeduplicateBootImageAddressLiteral(uint32_t address);
void EmitPcRelativeAddressPlaceholder(PcRelativePatchInfo* info, Register out, Register base);
diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc
index 1a54935..02b01c8 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -180,7 +180,7 @@
SaveLiveRegisters(codegen, locations);
InvokeRuntimeCallingConvention calling_convention;
- __ LoadConst32(calling_convention.GetRegisterAt(0), cls_->GetTypeIndex());
+ __ LoadConst32(calling_convention.GetRegisterAt(0), cls_->GetTypeIndex().index_);
QuickEntrypointEnum entrypoint = do_clinit_ ? kQuickInitializeStaticStorage
: kQuickInitializeType;
mips64_codegen->InvokeRuntime(entrypoint, at_, dex_pc_, this);
@@ -3157,7 +3157,7 @@
void InstructionCodeGeneratorMIPS64::VisitLoadClass(HLoadClass* cls) {
LocationSummary* locations = cls->GetLocations();
if (cls->NeedsAccessCheck()) {
- codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex());
+ codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex().index_);
codegen_->InvokeRuntime(kQuickInitializeTypeAndVerifyAccess, cls, cls->GetDexPc());
CheckEntrypointTypes<kQuickInitializeTypeAndVerifyAccess, void*, uint32_t>();
return;
@@ -3174,7 +3174,7 @@
__ LoadFromOffset(kLoadDoubleword, out, current_method,
ArtMethod::DexCacheResolvedTypesOffset(kMips64PointerSize).Int32Value());
__ LoadFromOffset(
- kLoadUnsignedWord, out, out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex()));
+ kLoadUnsignedWord, out, out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex().index_));
// TODO: We will need a read barrier here.
if (!cls->IsInDexCache() || cls->MustGenerateClinitCheck()) {
DCHECK(cls->CanCallRuntime());
@@ -3382,7 +3382,8 @@
void InstructionCodeGeneratorMIPS64::VisitNewArray(HNewArray* instruction) {
LocationSummary* locations = instruction->GetLocations();
// Move an uint16_t value to a register.
- __ LoadConst32(locations->GetTemp(0).AsRegister<GpuRegister>(), instruction->GetTypeIndex());
+ __ LoadConst32(locations->GetTemp(0).AsRegister<GpuRegister>(),
+ instruction->GetTypeIndex().index_);
codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc());
CheckEntrypointTypes<kQuickAllocArrayWithAccessCheck, void*, uint32_t, int32_t, ArtMethod*>();
}
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 3849437..51e902a 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -265,7 +265,7 @@
SaveLiveRegisters(codegen, locations);
InvokeRuntimeCallingConvention calling_convention;
- __ movl(calling_convention.GetRegisterAt(0), Immediate(cls_->GetTypeIndex()));
+ __ movl(calling_convention.GetRegisterAt(0), Immediate(cls_->GetTypeIndex().index_));
x86_codegen->InvokeRuntime(do_clinit_ ? kQuickInitializeStaticStorage
: kQuickInitializeType,
at_, dex_pc_, this);
@@ -4168,7 +4168,7 @@
void InstructionCodeGeneratorX86::VisitNewArray(HNewArray* instruction) {
InvokeRuntimeCallingConvention calling_convention;
- __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction->GetTypeIndex()));
+ __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction->GetTypeIndex().index_));
// Note: if heap poisoning is enabled, the entry point takes cares
// of poisoning the reference.
codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc());
@@ -4612,7 +4612,7 @@
}
void CodeGeneratorX86::RecordTypePatch(HLoadClass* load_class) {
- type_patches_.emplace_back(load_class->GetDexFile(), load_class->GetTypeIndex());
+ type_patches_.emplace_back(load_class->GetDexFile(), load_class->GetTypeIndex().index_);
__ Bind(&type_patches_.back().label);
}
@@ -6060,7 +6060,7 @@
void InstructionCodeGeneratorX86::VisitLoadClass(HLoadClass* cls) {
LocationSummary* locations = cls->GetLocations();
if (cls->NeedsAccessCheck()) {
- codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex());
+ codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex().index_);
codegen_->InvokeRuntime(kQuickInitializeTypeAndVerifyAccess, cls, cls->GetDexPc());
CheckEntrypointTypes<kQuickInitializeTypeAndVerifyAccess, void*, uint32_t>();
return;
@@ -6142,7 +6142,8 @@
// /* GcRoot<mirror::Class> */ out = out[type_index]
GenerateGcRootFieldLoad(cls,
out_loc,
- Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())),
+ Address(out,
+ CodeGenerator::GetCacheOffset(cls->GetTypeIndex().index_)),
/* fixup_label */ nullptr,
read_barrier_option);
generate_null_check = !cls->IsInDexCache();
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 02f5491..3467313 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -246,7 +246,8 @@
SaveLiveRegisters(codegen, locations);
InvokeRuntimeCallingConvention calling_convention;
- __ movl(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(cls_->GetTypeIndex()));
+ __ movl(CpuRegister(calling_convention.GetRegisterAt(0)),
+ Immediate(cls_->GetTypeIndex().index_));
x86_64_codegen->InvokeRuntime(do_clinit_ ? kQuickInitializeStaticStorage : kQuickInitializeType,
at_,
dex_pc_,
@@ -1110,7 +1111,7 @@
}
void CodeGeneratorX86_64::RecordTypePatch(HLoadClass* load_class) {
- type_patches_.emplace_back(load_class->GetDexFile(), load_class->GetTypeIndex());
+ type_patches_.emplace_back(load_class->GetDexFile(), load_class->GetTypeIndex().index_);
__ Bind(&type_patches_.back().label);
}
@@ -4098,7 +4099,7 @@
void InstructionCodeGeneratorX86_64::VisitNewArray(HNewArray* instruction) {
InvokeRuntimeCallingConvention calling_convention;
codegen_->Load64BitValue(CpuRegister(calling_convention.GetRegisterAt(0)),
- instruction->GetTypeIndex());
+ instruction->GetTypeIndex().index_);
// Note: if heap poisoning is enabled, the entry point takes cares
// of poisoning the reference.
codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc());
@@ -5485,7 +5486,7 @@
void InstructionCodeGeneratorX86_64::VisitLoadClass(HLoadClass* cls) {
LocationSummary* locations = cls->GetLocations();
if (cls->NeedsAccessCheck()) {
- codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex());
+ codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex().index_);
codegen_->InvokeRuntime(kQuickInitializeTypeAndVerifyAccess, cls, cls->GetDexPc());
CheckEntrypointTypes<kQuickInitializeTypeAndVerifyAccess, void*, uint32_t>();
return;
@@ -5568,7 +5569,7 @@
GenerateGcRootFieldLoad(
cls,
out_loc,
- Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())),
+ Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex().index_)),
/* fixup_label */ nullptr,
read_barrier_option);
generate_null_check = !cls->IsInDexCache();
diff --git a/compiler/optimizing/constant_folding_test.cc b/compiler/optimizing/constant_folding_test.cc
index 5fac3ac..7ef28ed 100644
--- a/compiler/optimizing/constant_folding_test.cc
+++ b/compiler/optimizing/constant_folding_test.cc
@@ -756,7 +756,7 @@
// Make various unsigned comparisons with zero against a parameter.
HInstruction* parameter = new (&allocator_) HParameterValue(
- graph_->GetDexFile(), 0, 0, Primitive::kPrimInt, true);
+ graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt, true);
entry_block->AddInstruction(parameter);
entry_block->AddInstruction(new (&allocator_) HGoto());
diff --git a/compiler/optimizing/gvn_test.cc b/compiler/optimizing/gvn_test.cc
index 6abf00e..437d35c 100644
--- a/compiler/optimizing/gvn_test.cc
+++ b/compiler/optimizing/gvn_test.cc
@@ -35,7 +35,7 @@
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
HInstruction* parameter = new (&allocator) HParameterValue(graph->GetDexFile(),
- 0,
+ dex::TypeIndex(0),
0,
Primitive::kPrimNot);
entry->AddInstruction(parameter);
@@ -120,7 +120,7 @@
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
HInstruction* parameter = new (&allocator) HParameterValue(graph->GetDexFile(),
- 0,
+ dex::TypeIndex(0),
0,
Primitive::kPrimNot);
entry->AddInstruction(parameter);
@@ -204,7 +204,7 @@
graph->SetEntryBlock(entry);
HInstruction* parameter = new (&allocator) HParameterValue(graph->GetDexFile(),
- 0,
+ dex::TypeIndex(0),
0,
Primitive::kPrimNot);
entry->AddInstruction(parameter);
@@ -352,7 +352,7 @@
inner_loop_exit->AddSuccessor(outer_loop_header);
HInstruction* parameter = new (&allocator) HParameterValue(graph->GetDexFile(),
- 0,
+ dex::TypeIndex(0),
0,
Primitive::kPrimBoolean);
entry->AddInstruction(parameter);
diff --git a/compiler/optimizing/induction_var_analysis_test.cc b/compiler/optimizing/induction_var_analysis_test.cc
index 031f1d7..3425b88 100644
--- a/compiler/optimizing/induction_var_analysis_test.cc
+++ b/compiler/optimizing/induction_var_analysis_test.cc
@@ -80,7 +80,7 @@
// Provide entry and exit instructions.
parameter_ = new (&allocator_) HParameterValue(
- graph_->GetDexFile(), 0, 0, Primitive::kPrimNot, true);
+ graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot, true);
entry_->AddInstruction(parameter_);
constant0_ = graph_->GetIntConstant(0);
constant1_ = graph_->GetIntConstant(1);
diff --git a/compiler/optimizing/induction_var_range_test.cc b/compiler/optimizing/induction_var_range_test.cc
index 8bbdd4a..4c99e3c 100644
--- a/compiler/optimizing/induction_var_range_test.cc
+++ b/compiler/optimizing/induction_var_range_test.cc
@@ -62,9 +62,15 @@
graph_->SetEntryBlock(entry_block_);
graph_->SetExitBlock(exit_block_);
// Two parameters.
- x_ = new (&allocator_) HParameterValue(graph_->GetDexFile(), 0, 0, Primitive::kPrimInt);
+ x_ = new (&allocator_) HParameterValue(graph_->GetDexFile(),
+ dex::TypeIndex(0),
+ 0,
+ Primitive::kPrimInt);
entry_block_->AddInstruction(x_);
- y_ = new (&allocator_) HParameterValue(graph_->GetDexFile(), 0, 0, Primitive::kPrimInt);
+ y_ = new (&allocator_) HParameterValue(graph_->GetDexFile(),
+ dex::TypeIndex(0),
+ 0,
+ Primitive::kPrimInt);
entry_block_->AddInstruction(y_);
// Set arbitrary range analysis hint while testing private methods.
SetHint(x_);
@@ -572,7 +578,8 @@
HInstruction* new_array = new (&allocator_)
HNewArray(x_,
graph_->GetCurrentMethod(),
- 0, Primitive::kPrimInt,
+ 0,
+ dex::TypeIndex(Primitive::kPrimInt),
graph_->GetDexFile(),
kQuickAllocArray);
entry_block_->AddInstruction(new_array);
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index 7fe54b9..16a465a 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -197,15 +197,15 @@
}
}
-static uint32_t FindClassIndexIn(mirror::Class* cls,
- const DexFile& dex_file,
- Handle<mirror::DexCache> dex_cache)
+static dex::TypeIndex FindClassIndexIn(mirror::Class* cls,
+ const DexFile& dex_file,
+ Handle<mirror::DexCache> dex_cache)
REQUIRES_SHARED(Locks::mutator_lock_) {
- uint32_t index = DexFile::kDexNoIndex;
+ dex::TypeIndex index;
if (cls->GetDexCache() == nullptr) {
DCHECK(cls->IsArrayClass()) << cls->PrettyClass();
index = cls->FindTypeIndexInOtherDexFile(dex_file);
- } else if (cls->GetDexTypeIndex() == DexFile::kDexNoIndex16) {
+ } else if (!cls->GetDexTypeIndex().IsValid()) {
DCHECK(cls->IsProxyClass()) << cls->PrettyClass();
// TODO: deal with proxy classes.
} else if (IsSameDexFile(cls->GetDexFile(), dex_file)) {
@@ -223,8 +223,8 @@
// We cannot guarantee the entry in the dex cache will resolve to the same class,
// as there may be different class loaders. So only return the index if it's
// the right class in the dex cache already.
- if (index != DexFile::kDexNoIndex && dex_cache->GetResolvedType(index) != cls) {
- index = DexFile::kDexNoIndex;
+ if (index.IsValid() && dex_cache->GetResolvedType(index) != cls) {
+ index = dex::TypeIndex::Invalid();
}
}
@@ -363,9 +363,9 @@
<< invoke_instruction->DebugName();
const DexFile& caller_dex_file = *caller_compilation_unit_.GetDexFile();
- uint32_t class_index = FindClassIndexIn(
+ dex::TypeIndex class_index = FindClassIndexIn(
ic.GetMonomorphicType(), caller_dex_file, caller_compilation_unit_.GetDexCache());
- if (class_index == DexFile::kDexNoIndex) {
+ if (!class_index.IsValid()) {
VLOG(compiler) << "Call to " << ArtMethod::PrettyMethod(resolved_method)
<< " from inline cache is not inlined because its class is not"
<< " accessible to the caller";
@@ -417,7 +417,7 @@
HInstruction* HInliner::AddTypeGuard(HInstruction* receiver,
HInstruction* cursor,
HBasicBlock* bb_cursor,
- uint32_t class_index,
+ dex::TypeIndex class_index,
bool is_referrer,
HInstruction* invoke_instruction,
bool with_deoptimization) {
@@ -489,10 +489,10 @@
HInstruction* cursor = invoke_instruction->GetPrevious();
HBasicBlock* bb_cursor = invoke_instruction->GetBlock();
- uint32_t class_index = FindClassIndexIn(
+ dex::TypeIndex class_index = FindClassIndexIn(
ic.GetTypeAt(i), caller_dex_file, caller_compilation_unit_.GetDexCache());
HInstruction* return_replacement = nullptr;
- if (class_index == DexFile::kDexNoIndex ||
+ if (!class_index.IsValid() ||
!TryBuildAndInline(invoke_instruction, method, &return_replacement)) {
all_targets_inlined = false;
} else {
diff --git a/compiler/optimizing/inliner.h b/compiler/optimizing/inliner.h
index a1dcd58..682393e 100644
--- a/compiler/optimizing/inliner.h
+++ b/compiler/optimizing/inliner.h
@@ -17,6 +17,7 @@
#ifndef ART_COMPILER_OPTIMIZING_INLINER_H_
#define ART_COMPILER_OPTIMIZING_INLINER_H_
+#include "dex_file_types.h"
#include "invoke_type.h"
#include "optimization.h"
@@ -150,7 +151,7 @@
HInstruction* AddTypeGuard(HInstruction* receiver,
HInstruction* cursor,
HBasicBlock* bb_cursor,
- uint32_t class_index,
+ dex::TypeIndex class_index,
bool is_referrer,
HInstruction* invoke_instruction,
bool with_deoptimization)
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index b44137d..40de5ce 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -908,7 +908,7 @@
false /* is_unresolved */);
}
-bool HInstructionBuilder::BuildNewInstance(uint16_t type_index, uint32_t dex_pc) {
+bool HInstructionBuilder::BuildNewInstance(dex::TypeIndex type_index, uint32_t dex_pc) {
ScopedObjectAccess soa(Thread::Current());
StackHandleScope<1> hs(soa.Self());
Handle<mirror::DexCache> dex_cache = dex_compilation_unit_->GetDexCache();
@@ -1004,7 +1004,7 @@
Handle<mirror::Class> resolved_method_class(hs.NewHandle(resolved_method->GetDeclaringClass()));
// The index at which the method's class is stored in the DexCache's type array.
- uint32_t storage_index = DexFile::kDexNoIndex;
+ dex::TypeIndex storage_index;
bool is_outer_class = (resolved_method->GetDeclaringClass() == outer_class.Get());
if (is_outer_class) {
storage_index = outer_class->GetDexTypeIndex();
@@ -1021,7 +1021,7 @@
if (IsInitialized(resolved_method_class)) {
*clinit_check_requirement = HInvokeStaticOrDirect::ClinitCheckRequirement::kNone;
- } else if (storage_index != DexFile::kDexNoIndex) {
+ } else if (storage_index.IsValid()) {
*clinit_check_requirement = HInvokeStaticOrDirect::ClinitCheckRequirement::kExplicit;
HLoadClass* load_class = new (arena_) HLoadClass(
graph_->GetCurrentMethod(),
@@ -1297,7 +1297,7 @@
return GetClassFrom(compiler_driver_, *dex_compilation_unit_);
}
-bool HInstructionBuilder::IsOutermostCompilingClass(uint16_t type_index) const {
+bool HInstructionBuilder::IsOutermostCompilingClass(dex::TypeIndex type_index) const {
ScopedObjectAccess soa(Thread::Current());
StackHandleScope<3> hs(soa.Self());
Handle<mirror::DexCache> dex_cache = dex_compilation_unit_->GetDexCache();
@@ -1360,7 +1360,7 @@
Handle<mirror::Class> outer_class(hs.NewHandle(GetOutermostCompilingClass()));
// The index at which the field's class is stored in the DexCache's type array.
- uint32_t storage_index;
+ dex::TypeIndex storage_index;
bool is_outer_class = (outer_class.Get() == resolved_field->GetDeclaringClass());
if (is_outer_class) {
storage_index = outer_class->GetDexTypeIndex();
@@ -1497,7 +1497,7 @@
}
void HInstructionBuilder::BuildFilledNewArray(uint32_t dex_pc,
- uint32_t type_index,
+ dex::TypeIndex type_index,
uint32_t number_of_vreg_arguments,
bool is_range,
uint32_t* args,
@@ -1644,7 +1644,7 @@
void HInstructionBuilder::BuildTypeCheck(const Instruction& instruction,
uint8_t destination,
uint8_t reference,
- uint16_t type_index,
+ dex::TypeIndex type_index,
uint32_t dex_pc) {
ScopedObjectAccess soa(Thread::Current());
StackHandleScope<1> hs(soa.Self());
@@ -1684,14 +1684,14 @@
}
}
-bool HInstructionBuilder::NeedsAccessCheck(uint32_t type_index,
+bool HInstructionBuilder::NeedsAccessCheck(dex::TypeIndex type_index,
Handle<mirror::DexCache> dex_cache,
bool* finalizable) const {
return !compiler_driver_->CanAccessInstantiableTypeWithoutChecks(
dex_compilation_unit_->GetDexMethodIndex(), dex_cache, type_index, finalizable);
}
-bool HInstructionBuilder::NeedsAccessCheck(uint32_t type_index, bool* finalizable) const {
+bool HInstructionBuilder::NeedsAccessCheck(dex::TypeIndex type_index, bool* finalizable) const {
ScopedObjectAccess soa(Thread::Current());
Handle<mirror::DexCache> dex_cache = dex_compilation_unit_->GetDexCache();
return NeedsAccessCheck(type_index, dex_cache, finalizable);
@@ -2449,7 +2449,7 @@
}
case Instruction::NEW_INSTANCE: {
- if (!BuildNewInstance(instruction.VRegB_21c(), dex_pc)) {
+ if (!BuildNewInstance(dex::TypeIndex(instruction.VRegB_21c()), dex_pc)) {
return false;
}
UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
@@ -2457,7 +2457,7 @@
}
case Instruction::NEW_ARRAY: {
- uint16_t type_index = instruction.VRegC_22c();
+ dex::TypeIndex type_index(instruction.VRegC_22c());
HInstruction* length = LoadLocal(instruction.VRegB_22c(), Primitive::kPrimInt);
bool finalizable;
QuickEntrypointEnum entrypoint = NeedsAccessCheck(type_index, &finalizable)
@@ -2475,7 +2475,7 @@
case Instruction::FILLED_NEW_ARRAY: {
uint32_t number_of_vreg_arguments = instruction.VRegA_35c();
- uint32_t type_index = instruction.VRegB_35c();
+ dex::TypeIndex type_index(instruction.VRegB_35c());
uint32_t args[5];
instruction.GetVarArgs(args);
BuildFilledNewArray(dex_pc, type_index, number_of_vreg_arguments, false, args, 0);
@@ -2484,7 +2484,7 @@
case Instruction::FILLED_NEW_ARRAY_RANGE: {
uint32_t number_of_vreg_arguments = instruction.VRegA_3rc();
- uint32_t type_index = instruction.VRegB_3rc();
+ dex::TypeIndex type_index(instruction.VRegB_3rc());
uint32_t register_index = instruction.VRegC_3rc();
BuildFilledNewArray(
dex_pc, type_index, number_of_vreg_arguments, true, nullptr, register_index);
@@ -2641,7 +2641,7 @@
}
case Instruction::CONST_CLASS: {
- uint16_t type_index = instruction.VRegB_21c();
+ dex::TypeIndex type_index(instruction.VRegB_21c());
// `CanAccessTypeWithoutChecks` will tell whether the method being
// built is trying to access its own class, so that the generated
// code can optimize for this case. However, the optimization does not
@@ -2682,14 +2682,14 @@
case Instruction::INSTANCE_OF: {
uint8_t destination = instruction.VRegA_22c();
uint8_t reference = instruction.VRegB_22c();
- uint16_t type_index = instruction.VRegC_22c();
+ dex::TypeIndex type_index(instruction.VRegC_22c());
BuildTypeCheck(instruction, destination, reference, type_index, dex_pc);
break;
}
case Instruction::CHECK_CAST: {
uint8_t reference = instruction.VRegA_21c();
- uint16_t type_index = instruction.VRegB_21c();
+ dex::TypeIndex type_index(instruction.VRegB_21c());
BuildTypeCheck(instruction, -1, reference, type_index, dex_pc);
break;
}
diff --git a/compiler/optimizing/instruction_builder.h b/compiler/optimizing/instruction_builder.h
index aa34ddd..f29e522 100644
--- a/compiler/optimizing/instruction_builder.h
+++ b/compiler/optimizing/instruction_builder.h
@@ -20,6 +20,7 @@
#include "base/arena_containers.h"
#include "base/arena_object.h"
#include "block_builder.h"
+#include "dex_file_types.h"
#include "driver/compiler_driver.h"
#include "driver/compiler_driver-inl.h"
#include "driver/dex_compilation_unit.h"
@@ -100,11 +101,11 @@
// Returns whether the current method needs access check for the type.
// Output parameter finalizable is set to whether the type is finalizable.
- bool NeedsAccessCheck(uint32_t type_index,
+ bool NeedsAccessCheck(dex::TypeIndex type_index,
Handle<mirror::DexCache> dex_cache,
/*out*/bool* finalizable) const
REQUIRES_SHARED(Locks::mutator_lock_);
- bool NeedsAccessCheck(uint32_t type_index, /*out*/bool* finalizable) const;
+ bool NeedsAccessCheck(dex::TypeIndex type_index, /*out*/bool* finalizable) const;
template<typename T>
void Unop_12x(const Instruction& instruction, Primitive::Type type, uint32_t dex_pc);
@@ -176,7 +177,7 @@
// Builds a new array node and the instructions that fill it.
void BuildFilledNewArray(uint32_t dex_pc,
- uint32_t type_index,
+ dex::TypeIndex type_index,
uint32_t number_of_vreg_arguments,
bool is_range,
uint32_t* args,
@@ -205,7 +206,7 @@
void BuildTypeCheck(const Instruction& instruction,
uint8_t destination,
uint8_t reference,
- uint16_t type_index,
+ dex::TypeIndex type_index,
uint32_t dex_pc);
// Builds an instruction sequence for a switch statement.
@@ -218,7 +219,7 @@
mirror::Class* GetCompilingClass() const;
// Returns whether `type_index` points to the outer-most compiling method's class.
- bool IsOutermostCompilingClass(uint16_t type_index) const;
+ bool IsOutermostCompilingClass(dex::TypeIndex type_index) const;
void PotentiallySimplifyFakeString(uint16_t original_dex_register,
uint32_t dex_pc,
@@ -258,7 +259,7 @@
REQUIRES_SHARED(Locks::mutator_lock_);
// Build a HNewInstance instruction.
- bool BuildNewInstance(uint16_t type_index, uint32_t dex_pc);
+ bool BuildNewInstance(dex::TypeIndex type_index, uint32_t dex_pc);
// Return whether the compiler can assume `cls` is initialized.
bool IsInitialized(Handle<mirror::Class> cls) const
diff --git a/compiler/optimizing/licm_test.cc b/compiler/optimizing/licm_test.cc
index 2a62643..8c34dc6 100644
--- a/compiler/optimizing/licm_test.cc
+++ b/compiler/optimizing/licm_test.cc
@@ -63,7 +63,10 @@
return_->AddSuccessor(exit_);
// Provide boiler-plate instructions.
- parameter_ = new (&allocator_) HParameterValue(graph_->GetDexFile(), 0, 0, Primitive::kPrimNot);
+ parameter_ = new (&allocator_) HParameterValue(graph_->GetDexFile(),
+ dex::TypeIndex(0),
+ 0,
+ Primitive::kPrimNot);
entry_->AddInstruction(parameter_);
int_constant_ = graph_->GetIntConstant(42);
float_constant_ = graph_->GetFloatConstant(42.0f);
diff --git a/compiler/optimizing/loop_optimization_test.cc b/compiler/optimizing/loop_optimization_test.cc
index 7805a69..9a6b493 100644
--- a/compiler/optimizing/loop_optimization_test.cc
+++ b/compiler/optimizing/loop_optimization_test.cc
@@ -48,7 +48,10 @@
graph_->AddBlock(exit_block_);
graph_->SetEntryBlock(entry_block_);
graph_->SetExitBlock(exit_block_);
- parameter_ = new (&allocator_) HParameterValue(graph_->GetDexFile(), 0, 0, Primitive::kPrimInt);
+ parameter_ = new (&allocator_) HParameterValue(graph_->GetDexFile(),
+ dex::TypeIndex(0),
+ 0,
+ Primitive::kPrimInt);
entry_block_->AddInstruction(parameter_);
return_block_->AddInstruction(new (&allocator_) HReturnVoid());
exit_block_->AddInstruction(new (&allocator_) HExit());
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 215ed54..eebc49c 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -29,6 +29,7 @@
#include "base/stl_util.h"
#include "base/transform_array_ref.h"
#include "dex_file.h"
+#include "dex_file_types.h"
#include "entrypoints/quick/quick_entrypoints_enum.h"
#include "handle.h"
#include "handle_scope.h"
@@ -800,7 +801,7 @@
}
// Catch block information constructor.
- TryCatchInformation(uint16_t catch_type_index, const DexFile& dex_file)
+ TryCatchInformation(dex::TypeIndex catch_type_index, const DexFile& dex_file)
: try_entry_(nullptr),
catch_dex_file_(&dex_file),
catch_type_index_(catch_type_index) {}
@@ -816,10 +817,10 @@
bool IsCatchAllTypeIndex() const {
DCHECK(IsCatchBlock());
- return catch_type_index_ == DexFile::kDexNoIndex16;
+ return !catch_type_index_.IsValid();
}
- uint16_t GetCatchTypeIndex() const {
+ dex::TypeIndex GetCatchTypeIndex() const {
DCHECK(IsCatchBlock());
return catch_type_index_;
}
@@ -836,7 +837,7 @@
// Exception type information. Only set for catch blocks.
const DexFile* catch_dex_file_;
- const uint16_t catch_type_index_;
+ const dex::TypeIndex catch_type_index_;
};
static constexpr size_t kNoLifetime = -1;
@@ -3671,7 +3672,7 @@
HNewInstance(HInstruction* cls,
HCurrentMethod* current_method,
uint32_t dex_pc,
- uint16_t type_index,
+ dex::TypeIndex type_index,
const DexFile& dex_file,
bool needs_access_check,
bool finalizable,
@@ -3686,7 +3687,7 @@
SetRawInputAt(1, current_method);
}
- uint16_t GetTypeIndex() const { return type_index_; }
+ dex::TypeIndex GetTypeIndex() const { return type_index_; }
const DexFile& GetDexFile() const { return dex_file_; }
// Calls runtime so needs an environment.
@@ -3719,7 +3720,7 @@
static_assert(kNumberOfNewInstancePackedBits <= kMaxNumberOfPackedBits,
"Too many packed fields.");
- const uint16_t type_index_;
+ const dex::TypeIndex type_index_;
const DexFile& dex_file_;
QuickEntrypointEnum entrypoint_;
@@ -4265,7 +4266,7 @@
HNewArray(HInstruction* length,
HCurrentMethod* current_method,
uint32_t dex_pc,
- uint16_t type_index,
+ dex::TypeIndex type_index,
const DexFile& dex_file,
QuickEntrypointEnum entrypoint)
: HExpression(Primitive::kPrimNot, SideEffects::CanTriggerGC(), dex_pc),
@@ -4276,7 +4277,7 @@
SetRawInputAt(1, current_method);
}
- uint16_t GetTypeIndex() const { return type_index_; }
+ dex::TypeIndex GetTypeIndex() const { return type_index_; }
const DexFile& GetDexFile() const { return dex_file_; }
// Calls runtime so needs an environment.
@@ -4292,7 +4293,7 @@
DECLARE_INSTRUCTION(NewArray);
private:
- const uint16_t type_index_;
+ const dex::TypeIndex type_index_;
const DexFile& dex_file_;
const QuickEntrypointEnum entrypoint_;
@@ -4829,7 +4830,7 @@
class HParameterValue FINAL : public HExpression<0> {
public:
HParameterValue(const DexFile& dex_file,
- uint16_t type_index,
+ dex::TypeIndex type_index,
uint8_t index,
Primitive::Type parameter_type,
bool is_this = false)
@@ -4842,7 +4843,7 @@
}
const DexFile& GetDexFile() const { return dex_file_; }
- uint16_t GetTypeIndex() const { return type_index_; }
+ dex::TypeIndex GetTypeIndex() const { return type_index_; }
uint8_t GetIndex() const { return index_; }
bool IsThis() const { return GetPackedFlag<kFlagIsThis>(); }
@@ -4860,7 +4861,7 @@
"Too many packed fields.");
const DexFile& dex_file_;
- const uint16_t type_index_;
+ const dex::TypeIndex type_index_;
// The index of this parameter in the parameters list. Must be less
// than HGraph::number_of_in_vregs_.
const uint8_t index_;
@@ -5455,7 +5456,7 @@
};
HLoadClass(HCurrentMethod* current_method,
- uint16_t type_index,
+ dex::TypeIndex type_index,
const DexFile& dex_file,
bool is_referrers_class,
uint32_t dex_pc,
@@ -5487,7 +5488,7 @@
void SetLoadKindWithTypeReference(LoadKind load_kind,
const DexFile& dex_file,
- uint32_t type_index) {
+ dex::TypeIndex type_index) {
DCHECK(HasTypeReference(load_kind));
DCHECK(IsSameDexFile(dex_file_, dex_file));
DCHECK_EQ(type_index_, type_index);
@@ -5511,7 +5512,7 @@
bool InstructionDataEquals(const HInstruction* other) const;
- size_t ComputeHashCode() const OVERRIDE { return type_index_; }
+ size_t ComputeHashCode() const OVERRIDE { return type_index_.index_; }
bool CanBeNull() const OVERRIDE { return false; }
@@ -5547,7 +5548,7 @@
loaded_class_rti_ = rti;
}
- uint32_t GetTypeIndex() const { return type_index_; }
+ dex::TypeIndex GetTypeIndex() const { return type_index_; }
const DexFile& GetDexFile() const { return dex_file_; }
uint32_t GetDexCacheElementOffset() const;
@@ -5630,7 +5631,7 @@
// for PC-relative loads, i.e. kDexCachePcRelative or kBootImageLinkTimePcRelative.
HUserRecord<HInstruction*> special_input_;
- const uint16_t type_index_;
+ const dex::TypeIndex type_index_;
const DexFile& dex_file_;
union {
diff --git a/compiler/optimizing/nodes_test.cc b/compiler/optimizing/nodes_test.cc
index d4e2a58..5d9a652 100644
--- a/compiler/optimizing/nodes_test.cc
+++ b/compiler/optimizing/nodes_test.cc
@@ -35,7 +35,7 @@
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
HInstruction* parameter = new (&allocator) HParameterValue(
- graph->GetDexFile(), 0, 0, Primitive::kPrimNot);
+ graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
entry->AddInstruction(parameter);
entry->AddInstruction(new (&allocator) HGoto());
@@ -78,9 +78,9 @@
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
HInstruction* parameter1 = new (&allocator) HParameterValue(
- graph->GetDexFile(), 0, 0, Primitive::kPrimNot);
+ graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
HInstruction* parameter2 = new (&allocator) HParameterValue(
- graph->GetDexFile(), 0, 0, Primitive::kPrimNot);
+ graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
entry->AddInstruction(parameter1);
entry->AddInstruction(parameter2);
entry->AddInstruction(new (&allocator) HExit());
@@ -106,7 +106,7 @@
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
HInstruction* parameter = new (&allocator) HParameterValue(
- graph->GetDexFile(), 0, 0, Primitive::kPrimNot);
+ graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
entry->AddInstruction(parameter);
ASSERT_FALSE(parameter->HasUses());
@@ -127,7 +127,7 @@
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
HInstruction* parameter1 = new (&allocator) HParameterValue(
- graph->GetDexFile(), 0, 0, Primitive::kPrimNot);
+ graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
HInstruction* with_environment = new (&allocator) HNullCheck(parameter1, 0);
entry->AddInstruction(parameter1);
entry->AddInstruction(with_environment);
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 85519c9..604d99c 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -61,6 +61,7 @@
#include "debug/method_debug_info.h"
#include "dex/verification_results.h"
#include "dex/verified_method.h"
+#include "dex_file_types.h"
#include "driver/compiler_driver-inl.h"
#include "driver/compiler_options.h"
#include "driver/dex_compilation_unit.h"
@@ -948,7 +949,7 @@
graph->SetArtMethod(method);
ScopedObjectAccess soa(Thread::Current());
interpreter_metadata = method->GetQuickenedInfo(class_linker->GetImagePointerSize());
- uint16_t type_index = method->GetDeclaringClass()->GetDexTypeIndex();
+ dex::TypeIndex type_index = method->GetDeclaringClass()->GetDexTypeIndex();
// Update the dex cache if the type is not in it yet. Note that under AOT,
// the verifier must have set it, but under JIT, there's no guarantee, as we
diff --git a/compiler/optimizing/prepare_for_register_allocation.cc b/compiler/optimizing/prepare_for_register_allocation.cc
index 0db6088..f9ac3a0 100644
--- a/compiler/optimizing/prepare_for_register_allocation.cc
+++ b/compiler/optimizing/prepare_for_register_allocation.cc
@@ -143,7 +143,7 @@
// - or the load class has only one use.
if (instruction->IsFinalizable() || has_only_one_use || load_class->NeedsAccessCheck()) {
instruction->SetEntrypoint(kQuickAllocObject);
- instruction->ReplaceInput(GetGraph()->GetIntConstant(load_class->GetTypeIndex()), 0);
+ instruction->ReplaceInput(GetGraph()->GetIntConstant(load_class->GetTypeIndex().index_), 0);
if (has_only_one_use) {
// We've just removed the only use of the HLoadClass. Since we don't run DCE after this pass,
// do it manually if possible.
diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc
index d588dea..c191c66 100644
--- a/compiler/optimizing/reference_type_propagation.cc
+++ b/compiler/optimizing/reference_type_propagation.cc
@@ -96,7 +96,7 @@
void VisitBoundType(HBoundType* instr) OVERRIDE;
void VisitNullCheck(HNullCheck* instr) OVERRIDE;
void UpdateReferenceTypeInfo(HInstruction* instr,
- uint16_t type_idx,
+ dex::TypeIndex type_idx,
const DexFile& dex_file,
bool is_exact);
@@ -463,7 +463,7 @@
}
void ReferenceTypePropagation::RTPVisitor::UpdateReferenceTypeInfo(HInstruction* instr,
- uint16_t type_idx,
+ dex::TypeIndex type_idx,
const DexFile& dex_file,
bool is_exact) {
DCHECK_EQ(instr->GetType(), Primitive::kPrimNot);
@@ -484,7 +484,7 @@
static mirror::Class* GetClassFromDexCache(Thread* self,
const DexFile& dex_file,
- uint16_t type_idx,
+ dex::TypeIndex type_idx,
Handle<mirror::DexCache> hint_dex_cache)
REQUIRES_SHARED(Locks::mutator_lock_) {
mirror::DexCache* dex_cache = FindDexCacheWithHint(self, dex_file, hint_dex_cache);
diff --git a/compiler/optimizing/register_allocator_test.cc b/compiler/optimizing/register_allocator_test.cc
index 55ea99e..559f409 100644
--- a/compiler/optimizing/register_allocator_test.cc
+++ b/compiler/optimizing/register_allocator_test.cc
@@ -20,6 +20,7 @@
#include "code_generator.h"
#include "code_generator_x86.h"
#include "dex_file.h"
+#include "dex_file_types.h"
#include "dex_instruction.h"
#include "driver/compiler_options.h"
#include "nodes.h"
@@ -495,7 +496,7 @@
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
HInstruction* parameter = new (allocator) HParameterValue(
- graph->GetDexFile(), 0, 0, Primitive::kPrimNot);
+ graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
entry->AddInstruction(parameter);
HBasicBlock* block = new (allocator) HBasicBlock(graph);
@@ -658,7 +659,7 @@
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
HInstruction* parameter = new (allocator) HParameterValue(
- graph->GetDexFile(), 0, 0, Primitive::kPrimNot);
+ graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
entry->AddInstruction(parameter);
HBasicBlock* block = new (allocator) HBasicBlock(graph);
@@ -742,7 +743,7 @@
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
HInstruction* parameter = new (allocator) HParameterValue(
- graph->GetDexFile(), 0, 0, Primitive::kPrimInt);
+ graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt);
entry->AddInstruction(parameter);
HInstruction* constant1 = graph->GetIntConstant(1);
@@ -821,9 +822,9 @@
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
HInstruction* first = new (allocator) HParameterValue(
- graph->GetDexFile(), 0, 0, Primitive::kPrimInt);
+ graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt);
HInstruction* second = new (allocator) HParameterValue(
- graph->GetDexFile(), 0, 0, Primitive::kPrimInt);
+ graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt);
entry->AddInstruction(first);
entry->AddInstruction(second);
@@ -883,13 +884,13 @@
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
HInstruction* one = new (&allocator) HParameterValue(
- graph->GetDexFile(), 0, 0, Primitive::kPrimInt);
+ graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt);
HInstruction* two = new (&allocator) HParameterValue(
- graph->GetDexFile(), 0, 0, Primitive::kPrimInt);
+ graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt);
HInstruction* three = new (&allocator) HParameterValue(
- graph->GetDexFile(), 0, 0, Primitive::kPrimInt);
+ graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt);
HInstruction* four = new (&allocator) HParameterValue(
- graph->GetDexFile(), 0, 0, Primitive::kPrimInt);
+ graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt);
entry->AddInstruction(one);
entry->AddInstruction(two);
entry->AddInstruction(three);
diff --git a/compiler/optimizing/sharpening.cc b/compiler/optimizing/sharpening.cc
index 15254ed..a127708 100644
--- a/compiler/optimizing/sharpening.cc
+++ b/compiler/optimizing/sharpening.cc
@@ -147,7 +147,7 @@
DCHECK(!load_class->IsInBootImage()) << "HLoadClass should not be optimized before sharpening.";
const DexFile& dex_file = load_class->GetDexFile();
- uint32_t type_index = load_class->GetTypeIndex();
+ dex::TypeIndex type_index = load_class->GetTypeIndex();
bool is_in_dex_cache = false;
bool is_in_boot_image = false;
@@ -197,7 +197,7 @@
// inlined frames are used correctly for OOM stack trace.
// TODO: Write a test for this. Bug: 29416588
desired_load_kind = HLoadClass::LoadKind::kDexCacheAddress;
- void* dex_cache_element_address = &dex_cache->GetResolvedTypes()[type_index];
+ void* dex_cache_element_address = &dex_cache->GetResolvedTypes()[type_index.index_];
address = reinterpret_cast64<uint64_t>(dex_cache_element_address);
}
// AOT app compilation. Check if the class is in the boot image.
diff --git a/compiler/utils/test_dex_file_builder_test.cc b/compiler/utils/test_dex_file_builder_test.cc
index da4ac79..922f8b1 100644
--- a/compiler/utils/test_dex_file_builder_test.cc
+++ b/compiler/utils/test_dex_file_builder_test.cc
@@ -62,7 +62,8 @@
};
ASSERT_EQ(arraysize(expected_types), dex_file->NumTypeIds());
for (size_t i = 0; i != arraysize(expected_types); ++i) {
- EXPECT_STREQ(expected_types[i], dex_file->GetTypeDescriptor(dex_file->GetTypeId(i))) << i;
+ EXPECT_STREQ(expected_types[i],
+ dex_file->GetTypeDescriptor(dex_file->GetTypeId(dex::TypeIndex(i)))) << i;
}
ASSERT_EQ(1u, dex_file->NumFieldIds());
diff --git a/compiler/utils/type_reference.h b/compiler/utils/type_reference.h
index d0c1656..a0fa1a4 100644
--- a/compiler/utils/type_reference.h
+++ b/compiler/utils/type_reference.h
@@ -20,6 +20,7 @@
#include <stdint.h>
#include "base/logging.h"
+#include "dex_file_types.h"
#include "string_reference.h"
namespace art {
@@ -28,10 +29,10 @@
// A type is located by its DexFile and the string_ids_ table index into that DexFile.
struct TypeReference {
- TypeReference(const DexFile* file, uint32_t index) : dex_file(file), type_index(index) { }
+ TypeReference(const DexFile* file, dex::TypeIndex index) : dex_file(file), type_index(index) { }
const DexFile* dex_file;
- uint32_t type_index;
+ dex::TypeIndex type_index;
};
// Compare the actual referenced type names. Used for type reference deduplication.
diff --git a/compiler/verifier_deps_test.cc b/compiler/verifier_deps_test.cc
index 6b690aa..03d3f4e 100644
--- a/compiler/verifier_deps_test.cc
+++ b/compiler/verifier_deps_test.cc
@@ -23,6 +23,7 @@
#include "compiler/driver/compiler_driver.h"
#include "compiler_callbacks.h"
#include "dex_file.h"
+#include "dex_file_types.h"
#include "handle_scope-inl.h"
#include "verifier/method_verifier-inl.h"
#include "mirror/class_loader.h"
@@ -207,8 +208,8 @@
hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader_)));
MutableHandle<mirror::Class> cls(hs.NewHandle<mirror::Class>(nullptr));
for (const DexFile* dex_file : dex_files_) {
- const std::vector<uint16_t>& unverified_classes = deps.GetUnverifiedClasses(*dex_file);
- std::set<uint16_t> set(unverified_classes.begin(), unverified_classes.end());
+ const std::vector<dex::TypeIndex>& unverified_classes = deps.GetUnverifiedClasses(*dex_file);
+ std::set<dex::TypeIndex> set(unverified_classes.begin(), unverified_classes.end());
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);
@@ -228,10 +229,10 @@
bool HasUnverifiedClass(const std::string& cls) {
const DexFile::TypeId* type_id = primary_dex_file_->FindTypeId(cls.c_str());
DCHECK(type_id != nullptr);
- uint16_t index = primary_dex_file_->GetIndexForTypeId(*type_id);
+ dex::TypeIndex index = primary_dex_file_->GetIndexForTypeId(*type_id);
MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
for (const auto& dex_dep : verifier_deps_->dex_deps_) {
- for (uint16_t entry : dex_dep.second->unverified_classes_) {
+ for (dex::TypeIndex entry : dex_dep.second->unverified_classes_) {
if (index == entry) {
return true;
}
diff --git a/dexdump/dexdump.cc b/dexdump/dexdump.cc
index 30de28e..03d6227 100644
--- a/dexdump/dexdump.cc
+++ b/dexdump/dexdump.cc
@@ -45,6 +45,7 @@
#include "base/stringprintf.h"
#include "dexdump_cfg.h"
#include "dex_file-inl.h"
+#include "dex_file_types.h"
#include "dex_instruction-inl.h"
namespace art {
@@ -482,7 +483,7 @@
}
case DexFile::kDexAnnotationType: {
const u4 str_idx = static_cast<u4>(readVarWidth(data, arg, false));
- fputs(pDexFile->StringByTypeIdx(str_idx), gOutFile);
+ fputs(pDexFile->StringByTypeIdx(dex::TypeIndex(str_idx)), gOutFile);
break;
}
case DexFile::kDexAnnotationField:
@@ -511,7 +512,7 @@
}
case DexFile::kDexAnnotationAnnotation: {
const u4 type_idx = DecodeUnsignedLeb128(data);
- fputs(pDexFile->StringByTypeIdx(type_idx), gOutFile);
+ fputs(pDexFile->StringByTypeIdx(dex::TypeIndex(type_idx)), gOutFile);
// Decode and display all name=value pairs.
const u4 size = DecodeUnsignedLeb128(data);
for (u4 i = 0; i < size; i++) {
@@ -592,10 +593,10 @@
// General class information.
const DexFile::ClassDef& pClassDef = pDexFile->GetClassDef(idx);
fprintf(gOutFile, "Class #%d header:\n", idx);
- fprintf(gOutFile, "class_idx : %d\n", pClassDef.class_idx_);
+ fprintf(gOutFile, "class_idx : %d\n", pClassDef.class_idx_.index_);
fprintf(gOutFile, "access_flags : %d (0x%04x)\n",
pClassDef.access_flags_, pClassDef.access_flags_);
- fprintf(gOutFile, "superclass_idx : %d\n", pClassDef.superclass_idx_);
+ fprintf(gOutFile, "superclass_idx : %d\n", pClassDef.superclass_idx_.index_);
fprintf(gOutFile, "interfaces_off : %d (0x%06x)\n",
pClassDef.interfaces_off_, pClassDef.interfaces_off_);
fprintf(gOutFile, "source_file_idx : %d\n", pClassDef.source_file_idx_);
@@ -747,9 +748,8 @@
const u4 end = start + pTry->insn_count_;
fprintf(gOutFile, " 0x%04x - 0x%04x\n", start, end);
for (CatchHandlerIterator it(*pCode, *pTry); it.HasNext(); it.Next()) {
- const u2 tidx = it.GetHandlerTypeIndex();
- const char* descriptor =
- (tidx == DexFile::kDexNoIndex16) ? "<any>" : pDexFile->StringByTypeIdx(tidx);
+ const dex::TypeIndex tidx = it.GetHandlerTypeIndex();
+ const char* descriptor = (!tidx.IsValid()) ? "<any>" : pDexFile->StringByTypeIdx(tidx);
fprintf(gOutFile, " %s -> 0x%04x\n", descriptor, it.GetHandlerAddress());
} // for
} // for
@@ -834,7 +834,7 @@
break;
case Instruction::kIndexTypeRef:
if (index < pDexFile->GetHeader().type_ids_size_) {
- const char* tp = pDexFile->StringByTypeIdx(index);
+ const char* tp = pDexFile->StringByTypeIdx(dex::TypeIndex(index));
outSize = snprintf(buf.get(), bufSize, "%s // type@%0*x", tp, width, index);
} else {
outSize = snprintf(buf.get(), bufSize, "<type?> // type@%0*x", width, index);
@@ -1461,7 +1461,7 @@
// General class information.
char* accessStr = createAccessFlagStr(pClassDef.access_flags_, kAccessForClass);
const char* superclassDescriptor;
- if (pClassDef.superclass_idx_ == DexFile::kDexNoIndex16) {
+ if (!pClassDef.superclass_idx_.IsValid()) {
superclassDescriptor = nullptr;
} else {
superclassDescriptor = pDexFile->StringByTypeIdx(pClassDef.superclass_idx_);
diff --git a/dexlayout/dex_ir.cc b/dexlayout/dex_ir.cc
index c3c763f..67f3e09 100644
--- a/dexlayout/dex_ir.cc
+++ b/dexlayout/dex_ir.cc
@@ -319,7 +319,7 @@
}
void Collections::CreateTypeId(const DexFile& dex_file, uint32_t i) {
- const DexFile::TypeId& disk_type_id = dex_file.GetTypeId(i);
+ const DexFile::TypeId& disk_type_id = dex_file.GetTypeId(dex::TypeIndex(i));
TypeId* type_id = new TypeId(GetStringId(disk_type_id.descriptor_idx_));
type_ids_.AddIndexedItem(type_id, TypeIdsOffset() + i * TypeId::ItemSize(), i);
}
@@ -330,22 +330,22 @@
TypeList* parameter_type_list = CreateTypeList(type_list, disk_proto_id.parameters_off_);
ProtoId* proto_id = new ProtoId(GetStringId(disk_proto_id.shorty_idx_),
- GetTypeId(disk_proto_id.return_type_idx_),
+ GetTypeId(disk_proto_id.return_type_idx_.index_),
parameter_type_list);
proto_ids_.AddIndexedItem(proto_id, ProtoIdsOffset() + i * ProtoId::ItemSize(), i);
}
void Collections::CreateFieldId(const DexFile& dex_file, uint32_t i) {
const DexFile::FieldId& disk_field_id = dex_file.GetFieldId(i);
- FieldId* field_id = new FieldId(GetTypeId(disk_field_id.class_idx_),
- GetTypeId(disk_field_id.type_idx_),
+ FieldId* field_id = new FieldId(GetTypeId(disk_field_id.class_idx_.index_),
+ GetTypeId(disk_field_id.type_idx_.index_),
GetStringId(disk_field_id.name_idx_));
field_ids_.AddIndexedItem(field_id, FieldIdsOffset() + i * FieldId::ItemSize(), i);
}
void Collections::CreateMethodId(const DexFile& dex_file, uint32_t i) {
const DexFile::MethodId& disk_method_id = dex_file.GetMethodId(i);
- MethodId* method_id = new MethodId(GetTypeId(disk_method_id.class_idx_),
+ MethodId* method_id = new MethodId(GetTypeId(disk_method_id.class_idx_.index_),
GetProtoId(disk_method_id.proto_idx_),
GetStringId(disk_method_id.name_idx_));
method_ids_.AddIndexedItem(method_id, MethodIdsOffset() + i * MethodId::ItemSize(), i);
@@ -353,9 +353,9 @@
void Collections::CreateClassDef(const DexFile& dex_file, uint32_t i) {
const DexFile::ClassDef& disk_class_def = dex_file.GetClassDef(i);
- const TypeId* class_type = GetTypeId(disk_class_def.class_idx_);
+ const TypeId* class_type = GetTypeId(disk_class_def.class_idx_.index_);
uint32_t access_flags = disk_class_def.access_flags_;
- const TypeId* superclass = GetTypeIdOrNullPtr(disk_class_def.superclass_idx_);
+ const TypeId* superclass = GetTypeIdOrNullPtr(disk_class_def.superclass_idx_.index_);
const DexFile::TypeList* type_list = dex_file.GetInterfacesList(disk_class_def);
TypeList* interfaces_type_list = CreateTypeList(type_list, disk_class_def.interfaces_off_);
@@ -393,7 +393,7 @@
TypeIdVector* type_vector = new TypeIdVector();
uint32_t size = dex_type_list->Size();
for (uint32_t index = 0; index < size; ++index) {
- type_vector->push_back(GetTypeId(dex_type_list->GetTypeItem(index).type_idx_));
+ type_vector->push_back(GetTypeId(dex_type_list->GetTypeItem(index).type_idx_.index_));
}
TypeList* new_type_list = new TypeList(type_vector);
type_lists_.AddItem(new_type_list, offset);
@@ -597,8 +597,8 @@
bool catch_all = false;
TypeAddrPairVector* addr_pairs = new TypeAddrPairVector();
for (CatchHandlerIterator it(disk_code_item, *disk_try_item); it.HasNext(); it.Next()) {
- const uint16_t type_index = it.GetHandlerTypeIndex();
- const TypeId* type_id = GetTypeIdOrNullPtr(type_index);
+ const dex::TypeIndex type_index = it.GetHandlerTypeIndex();
+ const TypeId* type_id = GetTypeIdOrNullPtr(type_index.index_);
catch_all |= type_id == nullptr;
addr_pairs->push_back(std::unique_ptr<const TypeAddrPair>(
new TypeAddrPair(type_id, it.GetHandlerAddress())));
diff --git a/dexlayout/dex_visualize.cc b/dexlayout/dex_visualize.cc
index 7c55659..05ad98f 100644
--- a/dexlayout/dex_visualize.cc
+++ b/dexlayout/dex_visualize.cc
@@ -350,7 +350,7 @@
const uint32_t class_defs_size = header->GetCollections().ClassDefsSize();
for (uint32_t class_index = 0; class_index < class_defs_size; class_index++) {
dex_ir::ClassDef* class_def = header->GetCollections().GetClassDef(class_index);
- uint16_t type_idx = class_def->ClassType()->GetIndex();
+ dex::TypeIndex type_idx(class_def->ClassType()->GetIndex());
if (profile_info_ != nullptr && !profile_info_->ContainsClass(*dex_file, type_idx)) {
continue;
}
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 4c01c14..3ad0f1e 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -794,7 +794,7 @@
uint32_t oat_class_offset = oat_dex_file.GetOatClassOffset(class_def_index);
const OatFile::OatClass oat_class = oat_dex_file.GetOatClass(class_def_index);
os << StringPrintf("%zd: %s (offset=0x%08x) (type_idx=%d)",
- class_def_index, descriptor, oat_class_offset, class_def.class_idx_)
+ class_def_index, descriptor, oat_class_offset, class_def.class_idx_.index_)
<< " (" << oat_class.GetStatus() << ")"
<< " (" << oat_class.GetType() << ")\n";
// TODO: include bitmap here if type is kOatClassSomeCompiled?
diff --git a/profman/profile_assistant_test.cc b/profman/profile_assistant_test.cc
index cd0aa6f..776c31a 100644
--- a/profman/profile_assistant_test.cc
+++ b/profman/profile_assistant_test.cc
@@ -42,7 +42,7 @@
ASSERT_TRUE(info->AddMethodIndex(dex_location2, dex_location_checksum2, i));
}
for (uint16_t i = 0; i < number_of_classes; i++) {
- ASSERT_TRUE(info->AddClassIndex(dex_location1, dex_location_checksum1, i));
+ ASSERT_TRUE(info->AddClassIndex(dex_location1, dex_location_checksum1, dex::TypeIndex(i)));
}
ASSERT_TRUE(info->Save(GetFd(profile)));
diff --git a/runtime/arch/stub_test.cc b/runtime/arch/stub_test.cc
index bbf9a8b..6665897 100644
--- a/runtime/arch/stub_test.cc
+++ b/runtime/arch/stub_test.cc
@@ -1063,7 +1063,7 @@
EXPECT_FALSE(self->IsExceptionPending());
{
// Use an arbitrary method from c to use as referrer
- size_t result = Invoke3(static_cast<size_t>(c->GetDexTypeIndex()), // type_idx
+ size_t result = Invoke3(static_cast<size_t>(c->GetDexTypeIndex().index_), // type_idx
// arbitrary
reinterpret_cast<size_t>(c->GetVirtualMethod(0, kRuntimePointerSize)),
0U,
@@ -1197,7 +1197,7 @@
if ((false)) {
// Use an arbitrary method from c to use as referrer
size_t result = Invoke3(
- static_cast<size_t>(c->GetDexTypeIndex()), // type_idx
+ static_cast<size_t>(c->GetDexTypeIndex().index_), // type_idx
10U,
// arbitrary
reinterpret_cast<size_t>(c_obj->GetVirtualMethod(0, kRuntimePointerSize)),
diff --git a/runtime/art_field.cc b/runtime/art_field.cc
index b46b058..25b8ed2 100644
--- a/runtime/art_field.cc
+++ b/runtime/art_field.cc
@@ -48,7 +48,7 @@
return Runtime::Current()->GetClassLinker()->FindSystemClass(Thread::Current(), descriptor);
}
-ObjPtr<mirror::Class> ArtField::ResolveGetType(uint32_t type_idx) {
+ObjPtr<mirror::Class> ArtField::ResolveGetType(dex::TypeIndex type_idx) {
return Runtime::Current()->GetClassLinker()->ResolveType(type_idx, this);
}
diff --git a/runtime/art_field.h b/runtime/art_field.h
index 7c2f490..cacb324 100644
--- a/runtime/art_field.h
+++ b/runtime/art_field.h
@@ -19,6 +19,7 @@
#include <jni.h>
+#include "dex_file_types.h"
#include "gc_root.h"
#include "modifiers.h"
#include "obj_ptr.h"
@@ -216,7 +217,8 @@
private:
ObjPtr<mirror::Class> ProxyFindSystemClass(const char* descriptor)
REQUIRES_SHARED(Locks::mutator_lock_);
- ObjPtr<mirror::Class> ResolveGetType(uint32_t type_idx) REQUIRES_SHARED(Locks::mutator_lock_);
+ ObjPtr<mirror::Class> ResolveGetType(dex::TypeIndex type_idx)
+ REQUIRES_SHARED(Locks::mutator_lock_);
ObjPtr<mirror::String> ResolveGetStringName(Thread* self,
const DexFile& dex_file,
uint32_t string_idx,
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h
index a652178..2dfdc16 100644
--- a/runtime/art_method-inl.h
+++ b/runtime/art_method-inl.h
@@ -183,17 +183,17 @@
}
template <bool kWithCheck>
-inline mirror::Class* ArtMethod::GetDexCacheResolvedType(uint32_t type_index,
+inline mirror::Class* ArtMethod::GetDexCacheResolvedType(dex::TypeIndex type_index,
PointerSize pointer_size) {
if (kWithCheck) {
mirror::DexCache* dex_cache =
GetInterfaceMethodIfProxy(pointer_size)->GetDeclaringClass()->GetDexCache();
- if (UNLIKELY(type_index >= dex_cache->NumResolvedTypes())) {
- ThrowArrayIndexOutOfBoundsException(type_index, dex_cache->NumResolvedTypes());
+ if (UNLIKELY(type_index.index_ >= dex_cache->NumResolvedTypes())) {
+ ThrowArrayIndexOutOfBoundsException(type_index.index_, dex_cache->NumResolvedTypes());
return nullptr;
}
}
- mirror::Class* klass = GetDexCacheResolvedTypes(pointer_size)[type_index].Read();
+ mirror::Class* klass = GetDexCacheResolvedTypes(pointer_size)[type_index.index_].Read();
return (klass != nullptr && !klass->IsErroneous()) ? klass : nullptr;
}
@@ -210,7 +210,7 @@
return GetDexCacheResolvedTypes(pointer_size) == other->GetDexCacheResolvedTypes(pointer_size);
}
-inline mirror::Class* ArtMethod::GetClassFromTypeIndex(uint16_t type_idx,
+inline mirror::Class* ArtMethod::GetClassFromTypeIndex(dex::TypeIndex type_idx,
bool resolve,
PointerSize pointer_size) {
mirror::Class* type = GetDexCacheResolvedType(type_idx, pointer_size);
@@ -336,7 +336,7 @@
return GetDeclaringClass()->GetDexFile().GetCodeItem(GetCodeItemOffset());
}
-inline bool ArtMethod::IsResolvedTypeIdx(uint16_t type_idx, PointerSize pointer_size) {
+inline bool ArtMethod::IsResolvedTypeIdx(dex::TypeIndex type_idx, PointerSize pointer_size) {
DCHECK(!IsProxyMethod());
return GetDexCacheResolvedType(type_idx, pointer_size) != nullptr;
}
@@ -383,11 +383,10 @@
const DexFile* dex_file = GetDexFile();
const DexFile::MethodId& method_id = dex_file->GetMethodId(GetDexMethodIndex());
const DexFile::ProtoId& proto_id = dex_file->GetMethodPrototype(method_id);
- uint16_t return_type_idx = proto_id.return_type_idx_;
- return dex_file->GetTypeDescriptor(dex_file->GetTypeId(return_type_idx));
+ return dex_file->GetTypeDescriptor(dex_file->GetTypeId(proto_id.return_type_idx_));
}
-inline const char* ArtMethod::GetTypeDescriptorFromTypeIdx(uint16_t type_idx) {
+inline const char* ArtMethod::GetTypeDescriptorFromTypeIdx(dex::TypeIndex type_idx) {
DCHECK(!IsProxyMethod());
const DexFile* dex_file = GetDexFile();
return dex_file->GetTypeDescriptor(dex_file->GetTypeId(type_idx));
@@ -440,7 +439,7 @@
const DexFile* dex_file = GetDexFile();
const DexFile::MethodId& method_id = dex_file->GetMethodId(GetDexMethodIndex());
const DexFile::ProtoId& proto_id = dex_file->GetMethodPrototype(method_id);
- uint16_t return_type_idx = proto_id.return_type_idx_;
+ dex::TypeIndex return_type_idx = proto_id.return_type_idx_;
mirror::Class* type = GetDexCacheResolvedType(return_type_idx, pointer_size);
if (type == nullptr && resolve) {
type = Runtime::Current()->GetClassLinker()->ResolveType(return_type_idx, this);
diff --git a/runtime/art_method.cc b/runtime/art_method.cc
index c550a1b..d1454b6 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -199,9 +199,9 @@
// Iterate over the catch handlers associated with dex_pc.
PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
for (CatchHandlerIterator it(*code_item, dex_pc); it.HasNext(); it.Next()) {
- uint16_t iter_type_idx = it.GetHandlerTypeIndex();
+ dex::TypeIndex iter_type_idx = it.GetHandlerTypeIndex();
// Catch all case
- if (iter_type_idx == DexFile::kDexNoIndex16) {
+ if (!iter_type_idx.IsValid()) {
found_dex_pc = it.GetHandlerAddress();
break;
}
@@ -476,7 +476,11 @@
}
// The table is in the .vdex file.
const OatFile::OatDexFile* oat_dex_file = GetDexCache()->GetDexFile()->GetOatDexFile();
- return oat_dex_file->GetOatFile()->DexBegin() + header->vmap_table_offset_;
+ const OatFile* oat_file = oat_dex_file->GetOatFile();
+ if (oat_file == nullptr) {
+ return nullptr;
+ }
+ return oat_file->DexBegin() + header->vmap_table_offset_;
} else {
return oat_method.GetVmapTable();
}
diff --git a/runtime/art_method.h b/runtime/art_method.h
index b31999f..0e1d7e7 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -343,7 +343,7 @@
REQUIRES_SHARED(Locks::mutator_lock_);
template <bool kWithCheck = true>
- mirror::Class* GetDexCacheResolvedType(uint32_t type_idx, PointerSize pointer_size)
+ mirror::Class* GetDexCacheResolvedType(dex::TypeIndex type_idx, PointerSize pointer_size)
REQUIRES_SHARED(Locks::mutator_lock_);
void SetDexCacheResolvedTypes(GcRoot<mirror::Class>* new_dex_cache_types,
PointerSize pointer_size)
@@ -355,7 +355,9 @@
REQUIRES_SHARED(Locks::mutator_lock_);
// Get the Class* from the type index into this method's dex cache.
- mirror::Class* GetClassFromTypeIndex(uint16_t type_idx, bool resolve, PointerSize pointer_size)
+ mirror::Class* GetClassFromTypeIndex(dex::TypeIndex type_idx,
+ bool resolve,
+ PointerSize pointer_size)
REQUIRES_SHARED(Locks::mutator_lock_);
// Returns true if this method has the same name and signature of the other method.
@@ -527,7 +529,7 @@
const DexFile::CodeItem* GetCodeItem() REQUIRES_SHARED(Locks::mutator_lock_);
- bool IsResolvedTypeIdx(uint16_t type_idx, PointerSize pointer_size)
+ bool IsResolvedTypeIdx(dex::TypeIndex type_idx, PointerSize pointer_size)
REQUIRES_SHARED(Locks::mutator_lock_);
int32_t GetLineNumFromDexPC(uint32_t dex_pc) REQUIRES_SHARED(Locks::mutator_lock_);
@@ -544,7 +546,7 @@
const char* GetReturnTypeDescriptor() REQUIRES_SHARED(Locks::mutator_lock_);
- const char* GetTypeDescriptorFromTypeIdx(uint16_t type_idx)
+ const char* GetTypeDescriptorFromTypeIdx(dex::TypeIndex type_idx)
REQUIRES_SHARED(Locks::mutator_lock_);
// May cause thread suspension due to GetClassFromTypeIdx calling ResolveType this caused a large
diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h
index 7359243..81adaeb 100644
--- a/runtime/class_linker-inl.h
+++ b/runtime/class_linker-inl.h
@@ -86,7 +86,7 @@
return string.Ptr();
}
-inline mirror::Class* ClassLinker::ResolveType(uint16_t type_idx, ArtMethod* referrer) {
+inline mirror::Class* ClassLinker::ResolveType(dex::TypeIndex type_idx, ArtMethod* referrer) {
Thread::PoisonObjectPointersIfDebug();
ObjPtr<mirror::Class> resolved_type =
referrer->GetDexCacheResolvedType(type_idx, image_pointer_size_);
@@ -103,7 +103,7 @@
return resolved_type.Ptr();
}
-inline mirror::Class* ClassLinker::ResolveType(uint16_t type_idx, ArtField* referrer) {
+inline mirror::Class* ClassLinker::ResolveType(dex::TypeIndex type_idx, ArtField* referrer) {
Thread::PoisonObjectPointersIfDebug();
ObjPtr<mirror::Class> declaring_class = referrer->GetDeclaringClass();
ObjPtr<mirror::DexCache> dex_cache_ptr = declaring_class->GetDexCache();
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 4905514..0fdf4e1 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -240,6 +240,12 @@
ScopedLocalRef<jthrowable> cause(env, env->ExceptionOccurred());
CHECK(cause.get() != nullptr);
+ // Boot classpath classes should not fail initialization.
+ if (!Runtime::Current()->IsAotCompiler()) {
+ std::string tmp;
+ CHECK(klass->GetClassLoader() != nullptr) << klass->GetDescriptor(&tmp);
+ }
+
env->ExceptionClear();
bool is_error = env->IsInstanceOf(cause.get(), WellKnownClasses::java_lang_Error);
env->Throw(cause.get());
@@ -730,10 +736,12 @@
const DexFile& dex_file = java_lang_Object->GetDexFile();
const DexFile::TypeId* void_type_id = dex_file.FindTypeId("V");
CHECK(void_type_id != nullptr);
- uint16_t void_type_idx = dex_file.GetIndexForTypeId(*void_type_id);
+ dex::TypeIndex void_type_idx = dex_file.GetIndexForTypeId(*void_type_id);
// Now we resolve void type so the dex cache contains it. We use java.lang.Object class
// as referrer so the used dex cache is core's one.
- ObjPtr<mirror::Class> resolved_type = ResolveType(dex_file, void_type_idx, java_lang_Object.Get());
+ ObjPtr<mirror::Class> resolved_type = ResolveType(dex_file,
+ void_type_idx,
+ java_lang_Object.Get());
CHECK_EQ(resolved_type, GetClassRoot(kPrimitiveVoid));
self->AssertNoPendingException();
}
@@ -1941,13 +1949,36 @@
void Visit(ObjPtr<mirror::ClassLoader> class_loader)
REQUIRES_SHARED(Locks::classlinker_classes_lock_, Locks::mutator_lock_) OVERRIDE {
ClassTable* const class_table = class_loader->GetClassTable();
- if (!done_ && class_table != nullptr && !class_table->Visit(*visitor_)) {
- // If the visitor ClassTable returns false it means that we don't need to continue.
- done_ = true;
+ if (!done_ && class_table != nullptr) {
+ DefiningClassLoaderFilterVisitor visitor(class_loader, visitor_);
+ if (!class_table->Visit(visitor)) {
+ // If the visitor ClassTable returns false it means that we don't need to continue.
+ done_ = true;
+ }
}
}
private:
+ // Class visitor that limits the class visits from a ClassTable to the classes with
+ // the provided defining class loader. This filter is used to avoid multiple visits
+ // of the same class which can be recorded for multiple initiating class loaders.
+ class DefiningClassLoaderFilterVisitor : public ClassVisitor {
+ public:
+ DefiningClassLoaderFilterVisitor(ObjPtr<mirror::ClassLoader> defining_class_loader,
+ ClassVisitor* visitor)
+ : defining_class_loader_(defining_class_loader), visitor_(visitor) { }
+
+ bool operator()(ObjPtr<mirror::Class> klass) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (klass->GetClassLoader() != defining_class_loader_) {
+ return true;
+ }
+ return (*visitor_)(klass);
+ }
+
+ ObjPtr<mirror::ClassLoader> const defining_class_loader_;
+ ClassVisitor* const visitor_;
+ };
+
ClassVisitor* const visitor_;
// If done is true then we don't need to do any more visiting.
bool done_;
@@ -2532,56 +2563,109 @@
}
} else {
ScopedObjectAccessUnchecked soa(self);
- ObjPtr<mirror::Class> cp_klass;
- if (FindClassInBaseDexClassLoader(soa, self, descriptor, hash, class_loader, &cp_klass)) {
- // The chain was understood. So the value in cp_klass is either the class we were looking
- // for, or not found.
- if (cp_klass != nullptr) {
- return cp_klass.Ptr();
- }
- // TODO: We handle the boot classpath loader in FindClassInBaseDexClassLoader. Try to unify
- // this and the branch above. TODO: throw the right exception here.
+ ObjPtr<mirror::Class> result_ptr;
+ bool descriptor_equals;
+ bool known_hierarchy =
+ FindClassInBaseDexClassLoader(soa, self, descriptor, hash, class_loader, &result_ptr);
+ if (result_ptr != nullptr) {
+ // The chain was understood and we found the class. We still need to add the class to
+ // the class table to protect from racy programs that can try and redefine the path list
+ // which would change the Class<?> returned for subsequent evaluation of const-class.
+ DCHECK(known_hierarchy);
+ DCHECK(result_ptr->DescriptorEquals(descriptor));
+ descriptor_equals = true;
+ } else {
+ // Either the chain wasn't understood or the class wasn't found.
+ //
+ // If the chain was understood and but we did not find the class, let the Java-side
+ // rediscover all this and throw the exception with the right stack trace. Note that
+ // the Java-side could still succeed for racy programs if another thread is actively
+ // modifying the class loader's path list.
- // We'll let the Java-side rediscover all this and throw the exception with the right stack
- // trace.
- }
-
- if (Runtime::Current()->IsAotCompiler()) {
- // Oops, compile-time, can't run actual class-loader code.
- ObjPtr<mirror::Throwable> pre_allocated = Runtime::Current()->GetPreAllocatedNoClassDefFoundError();
- self->SetException(pre_allocated);
- return nullptr;
- }
-
- ScopedLocalRef<jobject> class_loader_object(soa.Env(),
- soa.AddLocalReference<jobject>(class_loader.Get()));
- std::string class_name_string(DescriptorToDot(descriptor));
- ScopedLocalRef<jobject> result(soa.Env(), nullptr);
- {
- ScopedThreadStateChange tsc(self, kNative);
- ScopedLocalRef<jobject> class_name_object(soa.Env(),
- soa.Env()->NewStringUTF(class_name_string.c_str()));
- if (class_name_object.get() == nullptr) {
- DCHECK(self->IsExceptionPending()); // OOME.
+ if (Runtime::Current()->IsAotCompiler()) {
+ // Oops, compile-time, can't run actual class-loader code.
+ ObjPtr<mirror::Throwable> pre_allocated =
+ Runtime::Current()->GetPreAllocatedNoClassDefFoundError();
+ self->SetException(pre_allocated);
return nullptr;
}
- CHECK(class_loader_object.get() != nullptr);
- result.reset(soa.Env()->CallObjectMethod(class_loader_object.get(),
- WellKnownClasses::java_lang_ClassLoader_loadClass,
- class_name_object.get()));
+
+ ScopedLocalRef<jobject> class_loader_object(
+ soa.Env(), soa.AddLocalReference<jobject>(class_loader.Get()));
+ std::string class_name_string(DescriptorToDot(descriptor));
+ ScopedLocalRef<jobject> result(soa.Env(), nullptr);
+ {
+ ScopedThreadStateChange tsc(self, kNative);
+ ScopedLocalRef<jobject> class_name_object(
+ soa.Env(), soa.Env()->NewStringUTF(class_name_string.c_str()));
+ if (class_name_object.get() == nullptr) {
+ DCHECK(self->IsExceptionPending()); // OOME.
+ return nullptr;
+ }
+ CHECK(class_loader_object.get() != nullptr);
+ result.reset(soa.Env()->CallObjectMethod(class_loader_object.get(),
+ WellKnownClasses::java_lang_ClassLoader_loadClass,
+ class_name_object.get()));
+ }
+ if (self->IsExceptionPending()) {
+ // If the ClassLoader threw, pass that exception up.
+ // However, to comply with the RI behavior, first check if another thread succeeded.
+ result_ptr = LookupClass(self, descriptor, hash, class_loader.Get());
+ if (result_ptr != nullptr && result_ptr->IsResolved()) {
+ self->ClearException();
+ return result_ptr.Ptr();
+ }
+ return nullptr;
+ } else if (result.get() == nullptr) {
+ // broken loader - throw NPE to be compatible with Dalvik
+ ThrowNullPointerException(StringPrintf("ClassLoader.loadClass returned null for %s",
+ class_name_string.c_str()).c_str());
+ return nullptr;
+ }
+ result_ptr = soa.Decode<mirror::Class>(result.get());
+ // Check the name of the returned class.
+ descriptor_equals = result_ptr->DescriptorEquals(descriptor);
}
- if (self->IsExceptionPending()) {
- // If the ClassLoader threw, pass that exception up.
- return nullptr;
- } else if (result.get() == nullptr) {
- // broken loader - throw NPE to be compatible with Dalvik
- ThrowNullPointerException(StringPrintf("ClassLoader.loadClass returned null for %s",
- class_name_string.c_str()).c_str());
- return nullptr;
- } else {
- // success, return mirror::Class*
- return soa.Decode<mirror::Class>(result.get()).Ptr();
+
+ // Try to insert the class to the class table, checking for mismatch.
+ ObjPtr<mirror::Class> old;
+ {
+ ReaderMutexLock mu(self, *Locks::classlinker_classes_lock_);
+ ClassTable* const class_table = InsertClassTableForClassLoader(class_loader.Get());
+ old = class_table->Lookup(descriptor, hash);
+ if (old == nullptr) {
+ old = result_ptr; // For the comparison below, after releasing the lock.
+ if (descriptor_equals) {
+ class_table->InsertWithHash(result_ptr.Ptr(), hash);
+ Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(class_loader.Get());
+ } // else throw below, after releasing the lock.
+ }
}
+ if (UNLIKELY(old != result_ptr)) {
+ // Return `old` (even if `!descriptor_equals`) to mimic the RI behavior for parallel
+ // capable class loaders. (All class loaders are considered parallel capable on Android.)
+ mirror::Class* loader_class = class_loader->GetClass();
+ const char* loader_class_name =
+ loader_class->GetDexFile().StringByTypeIdx(loader_class->GetDexTypeIndex());
+ LOG(WARNING) << "Initiating class loader of type " << DescriptorToDot(loader_class_name)
+ << " is not well-behaved; it a returned different Class for racing loadClass(\""
+ << DescriptorToDot(descriptor) << "\").";
+ return old.Ptr();
+ }
+ if (UNLIKELY(!descriptor_equals)) {
+ std::string result_storage;
+ const char* result_name = result_ptr->GetDescriptor(&result_storage);
+ std::string loader_storage;
+ const char* loader_class_name = class_loader->GetClass()->GetDescriptor(&loader_storage);
+ ThrowNoClassDefFoundError(
+ "Initiating class loader of type %s returned class %s instead of %s.",
+ DescriptorToDot(loader_class_name).c_str(),
+ DescriptorToDot(result_name).c_str(),
+ DescriptorToDot(descriptor).c_str());
+ return nullptr;
+ }
+ // success, return mirror::Class*
+ return result_ptr.Ptr();
}
UNREACHABLE();
}
@@ -3662,12 +3746,6 @@
Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(klass);
}
-bool ClassLinker::RemoveClass(const char* descriptor, ObjPtr<mirror::ClassLoader> class_loader) {
- WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
- ClassTable* const class_table = ClassTableForClassLoader(class_loader);
- return class_table != nullptr && class_table->Remove(descriptor);
-}
-
mirror::Class* ClassLinker::LookupClass(Thread* self,
const char* descriptor,
size_t hash,
@@ -4000,7 +4078,7 @@
const OatFile::OatDexFile* oat_dex_file = dex_file.GetOatDexFile();
// In case we run without an image there won't be a backing oat file.
- if (oat_dex_file == nullptr) {
+ if (oat_dex_file == nullptr || oat_dex_file->GetOatFile() == nullptr) {
return false;
}
@@ -4090,7 +4168,7 @@
for (; iterator.HasNext(); iterator.Next()) {
// Ensure exception types are resolved so that they don't need resolution to be delivered,
// unresolved exception types will be ignored by exception delivery
- if (iterator.GetHandlerTypeIndex() != DexFile::kDexNoIndex16) {
+ if (iterator.GetHandlerTypeIndex().IsValid()) {
ObjPtr<mirror::Class> exception_type = ResolveType(iterator.GetHandlerTypeIndex(), method);
if (exception_type == nullptr) {
DCHECK(Thread::Current()->IsExceptionPending());
@@ -4756,7 +4834,7 @@
const DexFile* dex_file = m->GetDexFile();
const DexFile::MethodId& method_id = dex_file->GetMethodId(m->GetDexMethodIndex());
const DexFile::ProtoId& proto_id = dex_file->GetMethodPrototype(method_id);
- uint16_t return_type_idx = proto_id.return_type_idx_;
+ dex::TypeIndex return_type_idx = proto_id.return_type_idx_;
std::string return_type = dex_file->PrettyType(return_type_idx);
std::string class_loader = mirror::Object::PrettyTypeOf(m->GetDeclaringClass()->GetClassLoader());
ThrowWrappedLinkageError(klass.Get(),
@@ -4774,7 +4852,7 @@
ArtMethod* method,
ArtMethod* m,
uint32_t index,
- uint32_t arg_type_idx)
+ dex::TypeIndex arg_type_idx)
REQUIRES_SHARED(Locks::mutator_lock_) {
DCHECK(Thread::Current()->IsExceptionPending());
DCHECK(!m->IsProxyMethod());
@@ -4864,7 +4942,7 @@
}
for (uint32_t i = 0; i < num_types; ++i) {
StackHandleScope<1> hs(self);
- uint32_t param_type_idx = types1->GetTypeItem(i).type_idx_;
+ dex::TypeIndex param_type_idx = types1->GetTypeItem(i).type_idx_;
Handle<mirror::Class> param_type(hs.NewHandle(
method1->GetClassFromTypeIndex(param_type_idx, true /* resolve */, pointer_size)));
if (UNLIKELY(param_type.Get() == nullptr)) {
@@ -4872,7 +4950,7 @@
method1, i, param_type_idx);
return false;
}
- uint32_t other_param_type_idx = types2->GetTypeItem(i).type_idx_;
+ dex::TypeIndex other_param_type_idx = types2->GetTypeItem(i).type_idx_;
ObjPtr<mirror::Class> other_param_type =
method2->GetClassFromTypeIndex(other_param_type_idx, true /* resolve */, pointer_size);
if (UNLIKELY(other_param_type == nullptr)) {
@@ -5356,8 +5434,8 @@
bool ClassLinker::LoadSuperAndInterfaces(Handle<mirror::Class> klass, const DexFile& dex_file) {
CHECK_EQ(mirror::Class::kStatusIdx, klass->GetStatus());
const DexFile::ClassDef& class_def = dex_file.GetClassDef(klass->GetDexClassDefIndex());
- uint16_t super_class_idx = class_def.superclass_idx_;
- if (super_class_idx != DexFile::kDexNoIndex16) {
+ dex::TypeIndex super_class_idx = class_def.superclass_idx_;
+ if (super_class_idx.IsValid()) {
// Check that a class does not inherit from itself directly.
//
// TODO: This is a cheap check to detect the straightforward case
@@ -5394,7 +5472,7 @@
const DexFile::TypeList* interfaces = dex_file.GetInterfacesList(class_def);
if (interfaces != nullptr) {
for (size_t i = 0; i < interfaces->Size(); i++) {
- uint16_t idx = interfaces->GetTypeItem(i).type_idx_;
+ dex::TypeIndex idx = interfaces->GetTypeItem(i).type_idx_;
ObjPtr<mirror::Class> interface = ResolveType(dex_file, idx, klass.Get());
if (interface == nullptr) {
DCHECK(Thread::Current()->IsExceptionPending());
@@ -7510,7 +7588,7 @@
}
ObjPtr<mirror::Class> ClassLinker::LookupResolvedType(const DexFile& dex_file,
- uint16_t type_idx,
+ dex::TypeIndex type_idx,
ObjPtr<mirror::DexCache> dex_cache,
ObjPtr<mirror::ClassLoader> class_loader) {
ObjPtr<mirror::Class> type = dex_cache->GetResolvedType(type_idx);
@@ -7536,7 +7614,7 @@
}
mirror::Class* ClassLinker::ResolveType(const DexFile& dex_file,
- uint16_t type_idx,
+ dex::TypeIndex type_idx,
ObjPtr<mirror::Class> referrer) {
StackHandleScope<2> hs(Thread::Current());
Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache()));
@@ -7545,7 +7623,7 @@
}
mirror::Class* ClassLinker::ResolveType(const DexFile& dex_file,
- uint16_t type_idx,
+ dex::TypeIndex type_idx,
Handle<mirror::DexCache> dex_cache,
Handle<mirror::ClassLoader> class_loader) {
DCHECK(dex_cache.Get() != nullptr);
@@ -7939,7 +8017,7 @@
int32_t i = 0;
MutableHandle<mirror::Class> param_class = hs.NewHandle<mirror::Class>(nullptr);
for (; it.HasNext(); it.Next()) {
- const uint16_t type_idx = it.GetTypeIdx();
+ const dex::TypeIndex type_idx = it.GetTypeIdx();
param_class.Assign(ResolveType(dex_file, type_idx, dex_cache, class_loader));
if (param_class.Get() == nullptr) {
DCHECK(self->IsExceptionPending());
@@ -8350,10 +8428,10 @@
dex_file->GetBaseLocation(),
dex_file->GetLocationChecksum());
size_t num_resolved = 0;
- std::unordered_set<uint16_t> class_set;
+ std::unordered_set<dex::TypeIndex> class_set;
CHECK_EQ(num_types, dex_cache->NumResolvedTypes());
for (size_t i = 0; i < num_types; ++i) {
- ObjPtr<mirror::Class> klass = dex_cache->GetResolvedType(i);
+ ObjPtr<mirror::Class> klass = dex_cache->GetResolvedType(dex::TypeIndex(i));
// Filter out null class loader since that is the boot class loader.
if (klass == nullptr || (ignore_boot_classes && klass->GetClassLoader() == nullptr)) {
continue;
@@ -8418,7 +8496,7 @@
VLOG(profiler) << "Found opened dex file for " << dex_file->GetLocation() << " with "
<< info.GetClasses().size() << " classes";
DCHECK_EQ(dex_file->GetLocationChecksum(), info.GetLocationChecksum());
- for (uint16_t type_idx : info.GetClasses()) {
+ for (dex::TypeIndex type_idx : info.GetClasses()) {
const DexFile::TypeId& type_id = dex_file->GetTypeId(type_idx);
const char* descriptor = dex_file->GetTypeDescriptor(type_id);
ret.insert(descriptor);
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 1d29e31..88028ea 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -32,6 +32,7 @@
#include "class_table.h"
#include "dex_cache_resolved_classes.h"
#include "dex_file.h"
+#include "dex_file_types.h"
#include "gc_root.h"
#include "jni.h"
#include "mirror/class.h"
@@ -217,12 +218,6 @@
mirror::Class* FindPrimitiveClass(char type) REQUIRES_SHARED(Locks::mutator_lock_);
- // General class unloading is not supported, this is used to prune
- // unwanted classes during image writing.
- bool RemoveClass(const char* descriptor, ObjPtr<mirror::ClassLoader> class_loader)
- REQUIRES(!Locks::classlinker_classes_lock_)
- REQUIRES_SHARED(Locks::mutator_lock_);
-
void DumpAllClasses(int flags)
REQUIRES(!Locks::classlinker_classes_lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
@@ -255,7 +250,7 @@
// result in the DexCache. The referrer is used to identify the
// target DexCache and ClassLoader to use for resolution.
mirror::Class* ResolveType(const DexFile& dex_file,
- uint16_t type_idx,
+ dex::TypeIndex type_idx,
ObjPtr<mirror::Class> referrer)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!dex_lock_, !Roles::uninterruptible_);
@@ -263,18 +258,18 @@
// Resolve a Type with the given index from the DexFile, storing the
// result in the DexCache. The referrer is used to identify the
// target DexCache and ClassLoader to use for resolution.
- mirror::Class* ResolveType(uint16_t type_idx, ArtMethod* referrer)
+ mirror::Class* ResolveType(dex::TypeIndex type_idx, ArtMethod* referrer)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!dex_lock_, !Roles::uninterruptible_);
- mirror::Class* ResolveType(uint16_t type_idx, ArtField* referrer)
+ mirror::Class* ResolveType(dex::TypeIndex type_idx, ArtField* referrer)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!dex_lock_, !Roles::uninterruptible_);
// Look up a resolved type with the given ID from the DexFile. The ClassLoader is used to search
// for the type, since it may be referenced from but not contained within the given DexFile.
ObjPtr<mirror::Class> LookupResolvedType(const DexFile& dex_file,
- uint16_t type_idx,
+ dex::TypeIndex type_idx,
ObjPtr<mirror::DexCache> dex_cache,
ObjPtr<mirror::ClassLoader> class_loader)
REQUIRES_SHARED(Locks::mutator_lock_);
@@ -284,7 +279,7 @@
// type, since it may be referenced from but not contained within
// the given DexFile.
mirror::Class* ResolveType(const DexFile& dex_file,
- uint16_t type_idx,
+ dex::TypeIndex type_idx,
Handle<mirror::DexCache> dex_cache,
Handle<mirror::ClassLoader> class_loader)
REQUIRES_SHARED(Locks::mutator_lock_)
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index 44590ba..9e17be2 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -25,6 +25,7 @@
#include "class_linker-inl.h"
#include "common_runtime_test.h"
#include "dex_file.h"
+#include "dex_file_types.h"
#include "experimental_flags.h"
#include "entrypoints/entrypoint_utils-inl.h"
#include "gc/heap.h"
@@ -429,7 +430,7 @@
}
// Verify all the types referenced by this file
for (size_t i = 0; i < dex.NumTypeIds(); i++) {
- const DexFile::TypeId& type_id = dex.GetTypeId(i);
+ const DexFile::TypeId& type_id = dex.GetTypeId(dex::TypeIndex(i));
const char* descriptor = dex.GetTypeDescriptor(type_id);
AssertDexFileClass(class_loader, descriptor);
}
@@ -891,7 +892,7 @@
hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("MyClass"))));
AssertNonExistentClass("LMyClass;");
ObjPtr<mirror::Class> klass = class_linker_->FindClass(soa.Self(), "LMyClass;", class_loader);
- uint32_t type_idx = klass->GetClassDef()->class_idx_;
+ dex::TypeIndex type_idx = klass->GetClassDef()->class_idx_;
ObjPtr<mirror::DexCache> dex_cache = klass->GetDexCache();
const DexFile& dex_file = klass->GetDexFile();
EXPECT_OBJ_PTR_EQ(dex_cache->GetResolvedType(type_idx), klass);
@@ -1154,7 +1155,7 @@
ArtMethod* getS0 = klass->FindDirectMethod("getS0", "()Ljava/lang/Object;", kRuntimePointerSize);
const DexFile::TypeId* type_id = dex_file->FindTypeId("LStaticsFromCode;");
ASSERT_TRUE(type_id != nullptr);
- uint32_t type_idx = dex_file->GetIndexForTypeId(*type_id);
+ dex::TypeIndex type_idx = dex_file->GetIndexForTypeId(*type_id);
mirror::Class* uninit = ResolveVerifyAndClinit(type_idx, clinit, soa.Self(), true, false);
EXPECT_TRUE(uninit != nullptr);
EXPECT_FALSE(uninit->IsInitialized());
diff --git a/runtime/class_table.cc b/runtime/class_table.cc
index b44104e..bd477ea 100644
--- a/runtime/class_table.cc
+++ b/runtime/class_table.cc
@@ -142,7 +142,6 @@
bool ClassTable::ClassDescriptorHashEquals::operator()(const GcRoot<mirror::Class>& a,
const GcRoot<mirror::Class>& b) const {
- DCHECK_EQ(a.Read()->GetClassLoader(), b.Read()->GetClassLoader());
std::string temp;
return a.Read()->DescriptorEquals(b.Read()->GetDescriptor(&temp));
}
@@ -170,7 +169,7 @@
const DexFile* dex_file = ObjPtr<mirror::DexCache>::DownCast(obj)->GetDexFile();
if (dex_file != nullptr && dex_file->GetOatDexFile() != nullptr) {
const OatFile* oat_file = dex_file->GetOatDexFile()->GetOatFile();
- if (!oat_file->GetBssGcRoots().empty()) {
+ if (oat_file != nullptr && !oat_file->GetBssGcRoots().empty()) {
InsertOatFileLocked(oat_file); // Ignore return value.
}
}
diff --git a/runtime/dex_cache_resolved_classes.h b/runtime/dex_cache_resolved_classes.h
index 0febbed..f53ca4a 100644
--- a/runtime/dex_cache_resolved_classes.h
+++ b/runtime/dex_cache_resolved_classes.h
@@ -21,6 +21,8 @@
#include <unordered_set>
#include <vector>
+#include "dex_file_types.h"
+
namespace art {
// Data structure for passing around which classes belonging to a dex cache / dex file are resolved.
@@ -59,7 +61,7 @@
return location_checksum_;
}
- const std::unordered_set<uint16_t>& GetClasses() const {
+ const std::unordered_set<dex::TypeIndex>& GetClasses() const {
return classes_;
}
@@ -68,7 +70,7 @@
const std::string base_location_;
const uint32_t location_checksum_;
// Array of resolved class def indexes.
- mutable std::unordered_set<uint16_t> classes_;
+ mutable std::unordered_set<dex::TypeIndex> classes_;
};
inline bool operator<(const DexCacheResolvedClasses& a, const DexCacheResolvedClasses& b) {
diff --git a/runtime/dex_file-inl.h b/runtime/dex_file-inl.h
index 621b2c5..77a63c1 100644
--- a/runtime/dex_file-inl.h
+++ b/runtime/dex_file-inl.h
@@ -58,12 +58,12 @@
return StringDataAndUtf16LengthByIdx(idx, &unicode_length);
}
-inline const char* DexFile::StringByTypeIdx(uint32_t idx, uint32_t* unicode_length) const {
+inline const char* DexFile::StringByTypeIdx(dex::TypeIndex idx, uint32_t* unicode_length) const {
const TypeId& type_id = GetTypeId(idx);
return StringDataAndUtf16LengthByIdx(type_id.descriptor_idx_, unicode_length);
}
-inline const char* DexFile::StringByTypeIdx(uint32_t idx) const {
+inline const char* DexFile::StringByTypeIdx(dex::TypeIndex idx) const {
const TypeId& type_id = GetTypeId(idx);
return StringDataByIdx(type_id.descriptor_idx_);
}
diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc
index 2ef7509..cc544fd 100644
--- a/runtime/dex_file.cc
+++ b/runtime/dex_file.cc
@@ -26,6 +26,7 @@
#include <memory>
#include <sstream>
+#include <type_traits>
#include "base/enums.h"
#include "base/file_magic.h"
@@ -44,6 +45,9 @@
namespace art {
+static_assert(sizeof(dex::TypeIndex) == sizeof(uint16_t), "TypeIndex size is wrong");
+static_assert(std::is_trivially_copyable<dex::TypeIndex>::value, "TypeIndex not trivial");
+
static constexpr OatDexFile* kNoOatDexFile = nullptr;
const char* DexFile::kClassesDex = "classes.dex";
@@ -550,7 +554,7 @@
return atoi(version);
}
-const DexFile::ClassDef* DexFile::FindClassDef(uint16_t type_idx) const {
+const DexFile::ClassDef* DexFile::FindClassDef(dex::TypeIndex type_idx) const {
size_t num_class_defs = NumClassDefs();
// Fast path for rare no class defs case.
if (num_class_defs == 0) {
@@ -597,9 +601,9 @@
const DexFile::StringId& name,
const DexFile::TypeId& type) const {
// Binary search MethodIds knowing that they are sorted by class_idx, name_idx then proto_idx
- const uint16_t class_idx = GetIndexForTypeId(declaring_klass);
+ const dex::TypeIndex class_idx = GetIndexForTypeId(declaring_klass);
const uint32_t name_idx = GetIndexForStringId(name);
- const uint16_t type_idx = GetIndexForTypeId(type);
+ const dex::TypeIndex type_idx = GetIndexForTypeId(type);
int32_t lo = 0;
int32_t hi = NumFieldIds() - 1;
while (hi >= lo) {
@@ -632,7 +636,7 @@
const DexFile::StringId& name,
const DexFile::ProtoId& signature) const {
// Binary search MethodIds knowing that they are sorted by class_idx, name_idx then proto_idx
- const uint16_t class_idx = GetIndexForTypeId(declaring_klass);
+ const dex::TypeIndex class_idx = GetIndexForTypeId(declaring_klass);
const uint32_t name_idx = GetIndexForStringId(name);
const uint16_t proto_idx = GetIndexForProtoId(signature);
int32_t lo = 0;
@@ -687,7 +691,7 @@
int32_t hi = NumTypeIds() - 1;
while (hi >= lo) {
int32_t mid = (hi + lo) / 2;
- const TypeId& type_id = GetTypeId(mid);
+ const TypeId& type_id = GetTypeId(dex::TypeIndex(mid));
const DexFile::StringId& str_id = GetStringId(type_id.descriptor_idx_);
const char* str = GetStringData(str_id);
int compare = CompareModifiedUtf8ToModifiedUtf8AsUtf16CodePointValues(string, str);
@@ -726,7 +730,7 @@
int32_t hi = NumTypeIds() - 1;
while (hi >= lo) {
int32_t mid = (hi + lo) / 2;
- const TypeId& type_id = GetTypeId(mid);
+ const TypeId& type_id = GetTypeId(dex::TypeIndex(mid));
if (string_idx > type_id.descriptor_idx_) {
lo = mid + 1;
} else if (string_idx < type_id.descriptor_idx_) {
@@ -738,20 +742,20 @@
return nullptr;
}
-const DexFile::ProtoId* DexFile::FindProtoId(uint16_t return_type_idx,
- const uint16_t* signature_type_idxs,
+const DexFile::ProtoId* DexFile::FindProtoId(dex::TypeIndex return_type_idx,
+ const dex::TypeIndex* signature_type_idxs,
uint32_t signature_length) const {
int32_t lo = 0;
int32_t hi = NumProtoIds() - 1;
while (hi >= lo) {
int32_t mid = (hi + lo) / 2;
const DexFile::ProtoId& proto = GetProtoId(mid);
- int compare = return_type_idx - proto.return_type_idx_;
+ int compare = return_type_idx.index_ - proto.return_type_idx_.index_;
if (compare == 0) {
DexFileParameterIterator it(*this, proto);
size_t i = 0;
while (it.HasNext() && i < signature_length && compare == 0) {
- compare = signature_type_idxs[i] - it.GetTypeIdx();
+ compare = signature_type_idxs[i].index_ - it.GetTypeIdx().index_;
it.Next();
i++;
}
@@ -775,8 +779,9 @@
}
// Given a signature place the type ids into the given vector
-bool DexFile::CreateTypeList(const StringPiece& signature, uint16_t* return_type_idx,
- std::vector<uint16_t>* param_type_idxs) const {
+bool DexFile::CreateTypeList(const StringPiece& signature,
+ dex::TypeIndex* return_type_idx,
+ std::vector<dex::TypeIndex>* param_type_idxs) const {
if (signature[0] != '(') {
return false;
}
@@ -813,7 +818,7 @@
if (type_id == nullptr) {
return false;
}
- uint16_t type_idx = GetIndexForTypeId(*type_id);
+ dex::TypeIndex type_idx = GetIndexForTypeId(*type_id);
if (!process_return) {
param_type_idxs->push_back(type_idx);
} else {
@@ -825,8 +830,8 @@
}
const Signature DexFile::CreateSignature(const StringPiece& signature) const {
- uint16_t return_type_idx;
- std::vector<uint16_t> param_type_indices;
+ dex::TypeIndex return_type_idx;
+ std::vector<dex::TypeIndex> param_type_indices;
bool success = CreateTypeList(signature, &return_type_idx, ¶m_type_indices);
if (!success) {
return Signature::NoSignature();
@@ -971,7 +976,8 @@
}
local_in_reg[reg].name_ = StringDataByIdx(name_idx);
- local_in_reg[reg].descriptor_ = StringByTypeIdx(descriptor_idx);
+ local_in_reg[reg].descriptor_ =
+ StringByTypeIdx(dex::TypeIndex(dchecked_integral_cast<uint16_t>(descriptor_idx)));;
local_in_reg[reg].signature_ = StringDataByIdx(signature_idx);
local_in_reg[reg].start_address_ = address;
local_in_reg[reg].reg_ = reg;
@@ -1225,9 +1231,9 @@
return result;
}
-std::string DexFile::PrettyType(uint32_t type_idx) const {
- if (type_idx >= NumTypeIds()) {
- return StringPrintf("<<invalid-type-idx-%d>>", type_idx);
+std::string DexFile::PrettyType(dex::TypeIndex type_idx) const {
+ if (type_idx.index_ >= NumTypeIds()) {
+ return StringPrintf("<<invalid-type-idx-%d>>", type_idx.index_);
}
const DexFile::TypeId& type_id = GetTypeId(type_idx);
return PrettyDescriptor(GetTypeDescriptor(type_id));
@@ -1457,14 +1463,14 @@
void CatchHandlerIterator::Next() {
if (remaining_count_ > 0) {
- handler_.type_idx_ = DecodeUnsignedLeb128(¤t_data_);
+ handler_.type_idx_ = dex::TypeIndex(DecodeUnsignedLeb128(¤t_data_));
handler_.address_ = DecodeUnsignedLeb128(¤t_data_);
remaining_count_--;
return;
}
if (catch_all_) {
- handler_.type_idx_ = DexFile::kDexNoIndex16;
+ handler_.type_idx_ = dex::TypeIndex(DexFile::kDexNoIndex16);
handler_.address_ = DecodeUnsignedLeb128(¤t_data_);
catch_all_ = false;
return;
@@ -1474,4 +1480,13 @@
remaining_count_ = -1;
}
+namespace dex {
+
+std::ostream& operator<<(std::ostream& os, const TypeIndex& index) {
+ os << "TypeIndex[" << index.index_ << "]";
+ return os;
+}
+
+} // namespace dex
+
} // namespace art
diff --git a/runtime/dex_file.h b/runtime/dex_file.h
index da9fa50..2384eb6 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex_file.h
@@ -23,6 +23,7 @@
#include "base/logging.h"
#include "base/value_object.h"
+#include "dex_file_types.h"
#include "globals.h"
#include "invoke_type.h"
#include "jni.h"
@@ -159,17 +160,28 @@
// Raw field_id_item.
struct FieldId {
- uint16_t class_idx_; // index into type_ids_ array for defining class
- uint16_t type_idx_; // index into type_ids_ array for field type
+ dex::TypeIndex class_idx_; // index into type_ids_ array for defining class
+ dex::TypeIndex type_idx_; // index into type_ids_ array for field type
uint32_t name_idx_; // index into string_ids_ array for field name
private:
DISALLOW_COPY_AND_ASSIGN(FieldId);
};
+ // Raw proto_id_item.
+ struct ProtoId {
+ uint32_t shorty_idx_; // index into string_ids array for shorty descriptor
+ dex::TypeIndex return_type_idx_; // index into type_ids array for return type
+ uint16_t pad_; // padding = 0
+ uint32_t parameters_off_; // file offset to type_list for parameter types
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ProtoId);
+ };
+
// Raw method_id_item.
struct MethodId {
- uint16_t class_idx_; // index into type_ids_ array for defining class
+ dex::TypeIndex class_idx_; // index into type_ids_ array for defining class
uint16_t proto_idx_; // index into proto_ids_ array for method prototype
uint32_t name_idx_; // index into string_ids_ array for method name
@@ -177,23 +189,12 @@
DISALLOW_COPY_AND_ASSIGN(MethodId);
};
- // Raw proto_id_item.
- struct ProtoId {
- uint32_t shorty_idx_; // index into string_ids array for shorty descriptor
- uint16_t return_type_idx_; // index into type_ids array for return type
- uint16_t pad_; // padding = 0
- uint32_t parameters_off_; // file offset to type_list for parameter types
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ProtoId);
- };
-
// Raw class_def_item.
struct ClassDef {
- uint16_t class_idx_; // index into type_ids_ array for this class
+ dex::TypeIndex class_idx_; // index into type_ids_ array for this class
uint16_t pad1_; // padding = 0
uint32_t access_flags_;
- uint16_t superclass_idx_; // index into type_ids_ array for superclass
+ dex::TypeIndex superclass_idx_; // index into type_ids_ array for superclass
uint16_t pad2_; // padding = 0
uint32_t interfaces_off_; // file offset to TypeList
uint32_t source_file_idx_; // index into string_ids_ for source file name
@@ -225,7 +226,7 @@
// Raw type_item.
struct TypeItem {
- uint16_t type_idx_; // index into type_ids section
+ dex::TypeIndex type_idx_; // index into type_ids section
private:
DISALLOW_COPY_AND_ASSIGN(TypeItem);
@@ -540,23 +541,23 @@
}
// Returns the TypeId at the specified index.
- const TypeId& GetTypeId(uint32_t idx) const {
- DCHECK_LT(idx, NumTypeIds()) << GetLocation();
- return type_ids_[idx];
+ const TypeId& GetTypeId(dex::TypeIndex idx) const {
+ DCHECK_LT(idx.index_, NumTypeIds()) << GetLocation();
+ return type_ids_[idx.index_];
}
- uint16_t GetIndexForTypeId(const TypeId& type_id) const {
+ dex::TypeIndex GetIndexForTypeId(const TypeId& type_id) const {
CHECK_GE(&type_id, type_ids_) << GetLocation();
CHECK_LT(&type_id, type_ids_ + header_->type_ids_size_) << GetLocation();
size_t result = &type_id - type_ids_;
DCHECK_LT(result, 65536U) << GetLocation();
- return static_cast<uint16_t>(result);
+ return dex::TypeIndex(static_cast<uint16_t>(result));
}
// Get the descriptor string associated with a given type index.
- const char* StringByTypeIdx(uint32_t idx, uint32_t* unicode_length) const;
+ const char* StringByTypeIdx(dex::TypeIndex idx, uint32_t* unicode_length) const;
- const char* StringByTypeIdx(uint32_t idx) const;
+ const char* StringByTypeIdx(dex::TypeIndex idx) const;
// Returns the type descriptor string of a type id.
const char* GetTypeDescriptor(const TypeId& type_id) const;
@@ -671,7 +672,7 @@
const char* GetClassDescriptor(const ClassDef& class_def) const;
// Looks up a class definition by its type index.
- const ClassDef* FindClassDef(uint16_t type_idx) const;
+ const ClassDef* FindClassDef(dex::TypeIndex type_idx) const;
const TypeList* GetInterfacesList(const ClassDef& class_def) const {
if (class_def.interfaces_off_ == 0) {
@@ -711,7 +712,7 @@
}
// Returns the ProtoId at the specified index.
- const ProtoId& GetProtoId(uint32_t idx) const {
+ const ProtoId& GetProtoId(uint16_t idx) const {
DCHECK_LT(idx, NumProtoIds()) << GetLocation();
return proto_ids_[idx];
}
@@ -723,16 +724,18 @@
}
// Looks up a proto id for a given return type and signature type list
- const ProtoId* FindProtoId(uint16_t return_type_idx,
- const uint16_t* signature_type_idxs, uint32_t signature_length) const;
- const ProtoId* FindProtoId(uint16_t return_type_idx,
- const std::vector<uint16_t>& signature_type_idxs) const {
+ const ProtoId* FindProtoId(dex::TypeIndex return_type_idx,
+ const dex::TypeIndex* signature_type_idxs,
+ uint32_t signature_length) const;
+ const ProtoId* FindProtoId(dex::TypeIndex return_type_idx,
+ const std::vector<dex::TypeIndex>& signature_type_idxs) const {
return FindProtoId(return_type_idx, &signature_type_idxs[0], signature_type_idxs.size());
}
// Given a signature place the type ids into the given vector, returns true on success
- bool CreateTypeList(const StringPiece& signature, uint16_t* return_type_idx,
- std::vector<uint16_t>* param_type_idxs) const;
+ bool CreateTypeList(const StringPiece& signature,
+ dex::TypeIndex* return_type_idx,
+ std::vector<dex::TypeIndex>* param_type_idxs) const;
// Create a Signature from the given string signature or return Signature::NoSignature if not
// possible.
@@ -1010,6 +1013,11 @@
return oat_dex_file_;
}
+ // Used by oat writer.
+ void SetOatDexFile(OatDexFile* oat_dex_file) const {
+ oat_dex_file_ = oat_dex_file;
+ }
+
// Utility methods for reading integral values from a buffer.
static int32_t ReadSignedInt(const uint8_t* ptr, int zwidth);
static uint32_t ReadUnsignedInt(const uint8_t* ptr, int zwidth, bool fill_on_right);
@@ -1021,7 +1029,7 @@
// Returns a human-readable form of the field at an index.
std::string PrettyField(uint32_t field_idx, bool with_type = true) const;
// Returns a human-readable form of the type at an index.
- std::string PrettyType(uint32_t type_idx) const;
+ std::string PrettyType(dex::TypeIndex type_idx) const;
private:
static std::unique_ptr<const DexFile> OpenFile(int fd,
@@ -1138,9 +1146,10 @@
// If this dex file was loaded from an oat file, oat_dex_file_ contains a
// pointer to the OatDexFile it was loaded from. Otherwise oat_dex_file_ is
// null.
- const OatDexFile* oat_dex_file_;
+ mutable const OatDexFile* oat_dex_file_;
friend class DexFileVerifierTest;
+ friend class OatWriter;
ART_FRIEND_TEST(ClassLinkerTest, RegisterDexFileName); // for constructor
};
@@ -1165,11 +1174,11 @@
bool HasNext() const { return pos_ < size_; }
size_t Size() const { return size_; }
void Next() { ++pos_; }
- uint16_t GetTypeIdx() {
+ dex::TypeIndex GetTypeIdx() {
return type_list_->GetTypeItem(pos_).type_idx_;
}
const char* GetDescriptor() {
- return dex_file_.StringByTypeIdx(GetTypeIdx());
+ return dex_file_.StringByTypeIdx(dex::TypeIndex(GetTypeIdx()));
}
private:
const DexFile& dex_file_;
@@ -1455,7 +1464,7 @@
Init(handler_data);
}
- uint16_t GetHandlerTypeIndex() const {
+ dex::TypeIndex GetHandlerTypeIndex() const {
return handler_.type_idx_;
}
uint32_t GetHandlerAddress() const {
@@ -1476,7 +1485,7 @@
void Init(const uint8_t* handler_data);
struct CatchHandlerItem {
- uint16_t type_idx_; // type index of the caught exception type
+ dex::TypeIndex type_idx_; // type index of the caught exception type
uint32_t address_; // handler address
} handler_;
const uint8_t* current_data_; // the current handler in dex file.
diff --git a/runtime/dex_file_annotations.cc b/runtime/dex_file_annotations.cc
index 835f456..3fe2c40 100644
--- a/runtime/dex_file_annotations.cc
+++ b/runtime/dex_file_annotations.cc
@@ -90,7 +90,7 @@
const uint8_t* annotation = annotation_item->annotation_;
uint32_t type_index = DecodeUnsignedLeb128(&annotation);
- if (strcmp(descriptor, dex_file.StringByTypeIdx(type_index)) == 0) {
+ if (strcmp(descriptor, dex_file.StringByTypeIdx(dex::TypeIndex(type_index))) == 0) {
result = annotation_item;
break;
}
@@ -246,7 +246,7 @@
StackHandleScope<2> hs(self);
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
Handle<mirror::Class> annotation_class(hs.NewHandle(
- class_linker->ResolveType(klass->GetDexFile(), type_index, klass.Get())));
+ class_linker->ResolveType(klass->GetDexFile(), dex::TypeIndex(type_index), klass.Get())));
if (annotation_class.Get() == nullptr) {
LOG(INFO) << "Unable to resolve " << klass->PrettyClass() << " annotation class " << type_index;
DCHECK(Thread::Current()->IsExceptionPending());
@@ -370,13 +370,14 @@
if (result_style == DexFile::kAllRaw) {
annotation_value->value_.SetI(index);
} else {
+ dex::TypeIndex type_index(index);
element_object = Runtime::Current()->GetClassLinker()->ResolveType(
- klass->GetDexFile(), index, klass.Get());
+ klass->GetDexFile(), type_index, klass.Get());
set_object = true;
if (element_object == nullptr) {
CHECK(self->IsExceptionPending());
if (result_style == DexFile::kAllObjects) {
- const char* msg = dex_file.StringByTypeIdx(index);
+ const char* msg = dex_file.StringByTypeIdx(type_index);
self->ThrowNewWrappedException("Ljava/lang/TypeNotPresentException;", msg);
element_object = self->GetException();
self->ClearException();
@@ -665,7 +666,7 @@
const uint8_t* annotation = annotation_item->annotation_;
uint32_t type_index = DecodeUnsignedLeb128(&annotation);
mirror::Class* resolved_class = Runtime::Current()->GetClassLinker()->ResolveType(
- klass->GetDexFile(), type_index, klass.Get());
+ klass->GetDexFile(), dex::TypeIndex(type_index), klass.Get());
if (resolved_class == nullptr) {
std::string temp;
LOG(WARNING) << StringPrintf("Unable to resolve %s annotation class %d",
@@ -1345,7 +1346,9 @@
break;
}
case kType: {
- mirror::Class* resolved = linker_->ResolveType(dex_file_, jval_.i, *dex_cache_,
+ mirror::Class* resolved = linker_->ResolveType(dex_file_,
+ dex::TypeIndex(jval_.i),
+ *dex_cache_,
*class_loader_);
field->SetObject<kTransactionActive>(field->GetDeclaringClass(), resolved);
break;
diff --git a/runtime/dex_file_test.cc b/runtime/dex_file_test.cc
index 8e1501f..f94d07b 100644
--- a/runtime/dex_file_test.cc
+++ b/runtime/dex_file_test.cc
@@ -415,14 +415,14 @@
TEST_F(DexFileTest, FindTypeId) {
for (size_t i = 0; i < java_lang_dex_file_->NumTypeIds(); i++) {
- const char* type_str = java_lang_dex_file_->StringByTypeIdx(i);
+ const char* type_str = java_lang_dex_file_->StringByTypeIdx(dex::TypeIndex(i));
const DexFile::StringId* type_str_id = java_lang_dex_file_->FindStringId(type_str);
ASSERT_TRUE(type_str_id != nullptr);
uint32_t type_str_idx = java_lang_dex_file_->GetIndexForStringId(*type_str_id);
const DexFile::TypeId* type_id = java_lang_dex_file_->FindTypeId(type_str_idx);
ASSERT_EQ(type_id, java_lang_dex_file_->FindTypeId(type_str));
ASSERT_TRUE(type_id != nullptr);
- EXPECT_EQ(java_lang_dex_file_->GetIndexForTypeId(*type_id), i);
+ EXPECT_EQ(java_lang_dex_file_->GetIndexForTypeId(*type_id).index_, i);
}
}
@@ -430,7 +430,7 @@
for (size_t i = 0; i < java_lang_dex_file_->NumProtoIds(); i++) {
const DexFile::ProtoId& to_find = java_lang_dex_file_->GetProtoId(i);
const DexFile::TypeList* to_find_tl = java_lang_dex_file_->GetProtoParameters(to_find);
- std::vector<uint16_t> to_find_types;
+ std::vector<dex::TypeIndex> to_find_types;
if (to_find_tl != nullptr) {
for (size_t j = 0; j < to_find_tl->Size(); j++) {
to_find_types.push_back(to_find_tl->GetTypeItem(j).type_idx_);
diff --git a/runtime/dex_file_types.h b/runtime/dex_file_types.h
new file mode 100644
index 0000000..c6d95a1
--- /dev/null
+++ b/runtime/dex_file_types.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_DEX_FILE_TYPES_H_
+#define ART_RUNTIME_DEX_FILE_TYPES_H_
+
+#include <limits>
+#include <ostream>
+
+namespace art {
+namespace dex {
+
+class TypeIndex {
+ public:
+ uint16_t index_;
+
+ TypeIndex() : index_(std::numeric_limits<decltype(index_)>::max()) {}
+ explicit TypeIndex(uint16_t idx) : index_(idx) {}
+
+ bool IsValid() const {
+ return index_ != std::numeric_limits<decltype(index_)>::max();
+ }
+ static TypeIndex Invalid() {
+ return TypeIndex(std::numeric_limits<decltype(index_)>::max());
+ }
+
+ bool operator==(const TypeIndex& other) const {
+ return index_ == other.index_;
+ }
+ bool operator!=(const TypeIndex& other) const {
+ return index_ != other.index_;
+ }
+ bool operator<(const TypeIndex& other) const {
+ return index_ < other.index_;
+ }
+ bool operator<=(const TypeIndex& other) const {
+ return index_ <= other.index_;
+ }
+ bool operator>(const TypeIndex& other) const {
+ return index_ > other.index_;
+ }
+ bool operator>=(const TypeIndex& other) const {
+ return index_ >= other.index_;
+ }
+};
+std::ostream& operator<<(std::ostream& os, const TypeIndex& index);
+
+} // namespace dex
+} // namespace art
+
+namespace std {
+
+template<> struct hash<art::dex::TypeIndex> {
+ size_t operator()(const art::dex::TypeIndex& index) const {
+ return hash<uint16_t>()(index.index_);
+ }
+};
+
+} // namespace std
+
+#endif // ART_RUNTIME_DEX_FILE_TYPES_H_
diff --git a/runtime/dex_file_verifier.cc b/runtime/dex_file_verifier.cc
index be25803..68e9f73 100644
--- a/runtime/dex_file_verifier.cc
+++ b/runtime/dex_file_verifier.cc
@@ -76,8 +76,9 @@
return dex_file_->StringDataByIdx(idx);
}
-const char* DexFileVerifier::CheckLoadStringByTypeIdx(uint32_t type_idx, const char* error_string) {
- if (UNLIKELY(!CheckIndex(type_idx, dex_file_->NumTypeIds(), error_string))) {
+const char* DexFileVerifier::CheckLoadStringByTypeIdx(dex::TypeIndex type_idx,
+ const char* error_string) {
+ if (UNLIKELY(!CheckIndex(type_idx.index_, dex_file_->NumTypeIds(), error_string))) {
return nullptr;
}
const DexFile::TypeId& type_id = dex_file_->GetTypeId(type_idx);
@@ -525,7 +526,7 @@
bool DexFileVerifier::CheckClassDataItemField(uint32_t idx,
uint32_t access_flags,
uint32_t class_access_flags,
- uint16_t class_type_index,
+ dex::TypeIndex class_type_index,
bool expect_static) {
// Check for overflow.
if (!CheckIndex(idx, header_->field_ids_size_, "class_data_item field_idx")) {
@@ -533,13 +534,13 @@
}
// Check that it's the right class.
- uint16_t my_class_index =
+ dex::TypeIndex my_class_index =
(reinterpret_cast<const DexFile::FieldId*>(begin_ + header_->field_ids_off_) + idx)->
class_idx_;
if (class_type_index != my_class_index) {
ErrorStringPrintf("Field's class index unexpected, %" PRIu16 "vs %" PRIu16,
- my_class_index,
- class_type_index);
+ my_class_index.index_,
+ class_type_index.index_);
return false;
}
@@ -563,7 +564,7 @@
bool DexFileVerifier::CheckClassDataItemMethod(uint32_t idx,
uint32_t access_flags,
uint32_t class_access_flags,
- uint16_t class_type_index,
+ dex::TypeIndex class_type_index,
uint32_t code_offset,
std::unordered_set<uint32_t>* direct_method_indexes,
bool expect_direct) {
@@ -574,13 +575,13 @@
}
// Check that it's the right class.
- uint16_t my_class_index =
+ dex::TypeIndex my_class_index =
(reinterpret_cast<const DexFile::MethodId*>(begin_ + header_->method_ids_off_) + idx)->
class_idx_;
if (class_type_index != my_class_index) {
ErrorStringPrintf("Method's class index unexpected, %" PRIu16 "vs %" PRIu16,
- my_class_index,
- class_type_index);
+ my_class_index.index_,
+ class_type_index.index_);
return false;
}
@@ -789,7 +790,7 @@
bool DexFileVerifier::FindClassFlags(uint32_t index,
bool is_field,
- uint16_t* class_type_index,
+ dex::TypeIndex* class_type_index,
uint32_t* class_access_flags) {
DCHECK(class_type_index != nullptr);
DCHECK(class_access_flags != nullptr);
@@ -811,7 +812,7 @@
}
// Check if that is valid.
- if (*class_type_index >= header_->type_ids_size_) {
+ if (class_type_index->index_ >= header_->type_ids_size_) {
return false;
}
@@ -836,7 +837,7 @@
uint32_t curr_index,
uint32_t prev_index,
bool* have_class,
- uint16_t* class_type_index,
+ dex::TypeIndex* class_type_index,
uint32_t* class_access_flags) {
if (curr_index < prev_index) {
ErrorStringPrintf("out-of-order %s indexes %" PRIu32 " and %" PRIu32,
@@ -862,7 +863,7 @@
template <bool kStatic>
bool DexFileVerifier::CheckIntraClassDataItemFields(ClassDataItemIterator* it,
bool* have_class,
- uint16_t* class_type_index,
+ dex::TypeIndex* class_type_index,
uint32_t* class_access_flags) {
DCHECK(it != nullptr);
// These calls use the raw access flags to check whether the whole dex field is valid.
@@ -897,7 +898,7 @@
ClassDataItemIterator* it,
std::unordered_set<uint32_t>* direct_method_indexes,
bool* have_class,
- uint16_t* class_type_index,
+ dex::TypeIndex* class_type_index,
uint32_t* class_access_flags) {
uint32_t prev_index = 0;
for (; kDirect ? it->HasNextDirectMethod() : it->HasNextVirtualMethod(); it->Next()) {
@@ -935,7 +936,7 @@
// So we need to explicitly search with the first item we find (either field or method), and then,
// as the lookup is expensive, cache the result.
bool have_class = false;
- uint16_t class_type_index;
+ dex::TypeIndex class_type_index;
uint32_t class_access_flags;
// Check fields.
@@ -1682,26 +1683,27 @@
return true;
}
-uint16_t DexFileVerifier::FindFirstClassDataDefiner(const uint8_t* ptr, bool* success) {
+dex::TypeIndex DexFileVerifier::FindFirstClassDataDefiner(const uint8_t* ptr, bool* success) {
ClassDataItemIterator it(*dex_file_, ptr);
*success = true;
if (it.HasNextStaticField() || it.HasNextInstanceField()) {
LOAD_FIELD(field, it.GetMemberIndex(), "first_class_data_definer field_id",
- *success = false; return DexFile::kDexNoIndex16)
+ *success = false; return dex::TypeIndex(DexFile::kDexNoIndex16))
return field->class_idx_;
}
if (it.HasNextDirectMethod() || it.HasNextVirtualMethod()) {
LOAD_METHOD(method, it.GetMemberIndex(), "first_class_data_definer method_id",
- *success = false; return DexFile::kDexNoIndex16)
+ *success = false; return dex::TypeIndex(DexFile::kDexNoIndex16))
return method->class_idx_;
}
- return DexFile::kDexNoIndex16;
+ return dex::TypeIndex(DexFile::kDexNoIndex16);
}
-uint16_t DexFileVerifier::FindFirstAnnotationsDirectoryDefiner(const uint8_t* ptr, bool* success) {
+dex::TypeIndex DexFileVerifier::FindFirstAnnotationsDirectoryDefiner(const uint8_t* ptr,
+ bool* success) {
const DexFile::AnnotationsDirectoryItem* item =
reinterpret_cast<const DexFile::AnnotationsDirectoryItem*>(ptr);
*success = true;
@@ -1709,25 +1711,25 @@
if (item->fields_size_ != 0) {
DexFile::FieldAnnotationsItem* field_items = (DexFile::FieldAnnotationsItem*) (item + 1);
LOAD_FIELD(field, field_items[0].field_idx_, "first_annotations_dir_definer field_id",
- *success = false; return DexFile::kDexNoIndex16)
+ *success = false; return dex::TypeIndex(DexFile::kDexNoIndex16))
return field->class_idx_;
}
if (item->methods_size_ != 0) {
DexFile::MethodAnnotationsItem* method_items = (DexFile::MethodAnnotationsItem*) (item + 1);
LOAD_METHOD(method, method_items[0].method_idx_, "first_annotations_dir_definer method id",
- *success = false; return DexFile::kDexNoIndex16)
+ *success = false; return dex::TypeIndex(DexFile::kDexNoIndex16))
return method->class_idx_;
}
if (item->parameters_size_ != 0) {
DexFile::ParameterAnnotationsItem* parameter_items = (DexFile::ParameterAnnotationsItem*) (item + 1);
LOAD_METHOD(method, parameter_items[0].method_idx_, "first_annotations_dir_definer method id",
- *success = false; return DexFile::kDexNoIndex16)
+ *success = false; return dex::TypeIndex(DexFile::kDexNoIndex16))
return method->class_idx_;
}
- return DexFile::kDexNoIndex16;
+ return dex::TypeIndex(DexFile::kDexNoIndex16);
}
bool DexFileVerifier::CheckInterStringIdItem() {
@@ -1797,7 +1799,8 @@
DexFileParameterIterator it(*dex_file_, *item);
while (it.HasNext() && *shorty != '\0') {
- if (!CheckIndex(it.GetTypeIdx(), dex_file_->NumTypeIds(),
+ if (!CheckIndex(it.GetTypeIdx().index_,
+ dex_file_->NumTypeIds(),
"inter_proto_id_item shorty type_idx")) {
return false;
}
@@ -1824,10 +1827,10 @@
DexFileParameterIterator prev_it(*dex_file_, *prev);
while (curr_it.HasNext() && prev_it.HasNext()) {
- uint16_t prev_idx = prev_it.GetTypeIdx();
- uint16_t curr_idx = curr_it.GetTypeIdx();
- DCHECK_NE(prev_idx, DexFile::kDexNoIndex16);
- DCHECK_NE(curr_idx, DexFile::kDexNoIndex16);
+ dex::TypeIndex prev_idx = prev_it.GetTypeIdx();
+ dex::TypeIndex curr_idx = curr_it.GetTypeIdx();
+ DCHECK_NE(prev_idx, dex::TypeIndex(DexFile::kDexNoIndex16));
+ DCHECK_NE(curr_idx, dex::TypeIndex(DexFile::kDexNoIndex16));
if (prev_idx < curr_idx) {
break;
@@ -1951,7 +1954,7 @@
// Check for duplicate class def.
if (defined_classes_.find(item->class_idx_) != defined_classes_.end()) {
- ErrorStringPrintf("Redefinition of class with type idx: '%d'", item->class_idx_);
+ ErrorStringPrintf("Redefinition of class with type idx: '%d'", item->class_idx_.index_);
return false;
}
defined_classes_.insert(item->class_idx_);
@@ -1985,12 +1988,13 @@
return false;
}
- if (item->superclass_idx_ != DexFile::kDexNoIndex16) {
+ if (item->superclass_idx_.IsValid()) {
if (header_->GetVersion() >= DexFile::kClassDefinitionOrderEnforcedVersion) {
// Check that a class does not inherit from itself directly (by having
// the same type idx as its super class).
if (UNLIKELY(item->superclass_idx_ == item->class_idx_)) {
- ErrorStringPrintf("Class with same type idx as its superclass: '%d'", item->class_idx_);
+ ErrorStringPrintf("Class with same type idx as its superclass: '%d'",
+ item->class_idx_.index_);
return false;
}
@@ -2004,8 +2008,8 @@
ErrorStringPrintf("Invalid class definition ordering:"
" class with type idx: '%d' defined before"
" superclass with type idx: '%d'",
- item->class_idx_,
- item->superclass_idx_);
+ item->class_idx_.index_,
+ item->superclass_idx_.index_);
return false;
}
}
@@ -2029,7 +2033,7 @@
// same type idx as one of its immediate implemented interfaces).
if (UNLIKELY(interfaces->GetTypeItem(i).type_idx_ == item->class_idx_)) {
ErrorStringPrintf("Class with same type idx as implemented interface: '%d'",
- item->class_idx_);
+ item->class_idx_.index_);
return false;
}
@@ -2044,8 +2048,8 @@
ErrorStringPrintf("Invalid class definition ordering:"
" class with type idx: '%d' defined before"
" implemented interface with type idx: '%d'",
- item->class_idx_,
- interfaces->GetTypeItem(i).type_idx_);
+ item->class_idx_.index_,
+ interfaces->GetTypeItem(i).type_idx_.index_);
return false;
}
}
@@ -2065,9 +2069,9 @@
* practice the number of interfaces implemented by any given class is low.
*/
for (uint32_t i = 1; i < size; i++) {
- uint32_t idx1 = interfaces->GetTypeItem(i).type_idx_;
+ dex::TypeIndex idx1 = interfaces->GetTypeItem(i).type_idx_;
for (uint32_t j =0; j < i; j++) {
- uint32_t idx2 = interfaces->GetTypeItem(j).type_idx_;
+ dex::TypeIndex idx2 = interfaces->GetTypeItem(j).type_idx_;
if (UNLIKELY(idx1 == idx2)) {
ErrorStringPrintf("Duplicate interface: '%s'", dex_file_->StringByTypeIdx(idx1));
return false;
@@ -2080,11 +2084,12 @@
if (item->class_data_off_ != 0) {
const uint8_t* data = begin_ + item->class_data_off_;
bool success;
- uint16_t data_definer = FindFirstClassDataDefiner(data, &success);
+ dex::TypeIndex data_definer = FindFirstClassDataDefiner(data, &success);
if (!success) {
return false;
}
- if (UNLIKELY((data_definer != item->class_idx_) && (data_definer != DexFile::kDexNoIndex16))) {
+ if (UNLIKELY((data_definer != item->class_idx_) &&
+ (data_definer != dex::TypeIndex(DexFile::kDexNoIndex16)))) {
ErrorStringPrintf("Invalid class_data_item");
return false;
}
@@ -2099,12 +2104,12 @@
}
const uint8_t* data = begin_ + item->annotations_off_;
bool success;
- uint16_t annotations_definer = FindFirstAnnotationsDirectoryDefiner(data, &success);
+ dex::TypeIndex annotations_definer = FindFirstAnnotationsDirectoryDefiner(data, &success);
if (!success) {
return false;
}
if (UNLIKELY((annotations_definer != item->class_idx_) &&
- (annotations_definer != DexFile::kDexNoIndex16))) {
+ (annotations_definer != dex::TypeIndex(DexFile::kDexNoIndex16)))) {
ErrorStringPrintf("Invalid annotations_directory_item");
return false;
}
@@ -2165,7 +2170,7 @@
bool DexFileVerifier::CheckInterClassDataItem() {
ClassDataItemIterator it(*dex_file_, ptr_);
bool success;
- uint16_t defining_class = FindFirstClassDataDefiner(ptr_, &success);
+ dex::TypeIndex defining_class = FindFirstClassDataDefiner(ptr_, &success);
if (!success) {
return false;
}
@@ -2197,7 +2202,7 @@
const DexFile::AnnotationsDirectoryItem* item =
reinterpret_cast<const DexFile::AnnotationsDirectoryItem*>(ptr_);
bool success;
- uint16_t defining_class = FindFirstAnnotationsDirectoryDefiner(ptr_, &success);
+ dex::TypeIndex defining_class = FindFirstAnnotationsDirectoryDefiner(ptr_, &success);
if (!success) {
return false;
}
@@ -2471,15 +2476,15 @@
static std::string GetClassOrError(const uint8_t* const begin,
const DexFile::Header* const header,
- uint32_t class_idx) {
+ dex::TypeIndex class_idx) {
// The `class_idx` is either `FieldId::class_idx_` or `MethodId::class_idx_` and
// it has already been checked in `DexFileVerifier::CheckClassDataItemField()`
// or `DexFileVerifier::CheckClassDataItemMethod()`, respectively, to match
// a valid defining class.
- CHECK_LT(class_idx, header->type_ids_size_);
+ CHECK_LT(class_idx.index_, header->type_ids_size_);
const DexFile::TypeId* type_id =
- reinterpret_cast<const DexFile::TypeId*>(begin + header->type_ids_off_) + class_idx;
+ reinterpret_cast<const DexFile::TypeId*>(begin + header->type_ids_off_) + class_idx.index_;
// Assume that the data is OK at this point. Type id offsets have been checked at this point.
diff --git a/runtime/dex_file_verifier.h b/runtime/dex_file_verifier.h
index 133e432..19a89de 100644
--- a/runtime/dex_file_verifier.h
+++ b/runtime/dex_file_verifier.h
@@ -20,6 +20,7 @@
#include <unordered_set>
#include "dex_file.h"
+#include "dex_file_types.h"
#include "safe_map.h"
namespace art {
@@ -76,12 +77,12 @@
bool CheckClassDataItemField(uint32_t idx,
uint32_t access_flags,
uint32_t class_access_flags,
- uint16_t class_type_index,
+ dex::TypeIndex class_type_index,
bool expect_static);
bool CheckClassDataItemMethod(uint32_t idx,
uint32_t access_flags,
uint32_t class_access_flags,
- uint16_t class_type_index,
+ dex::TypeIndex class_type_index,
uint32_t code_offset,
std::unordered_set<uint32_t>* direct_method_indexes,
bool expect_direct);
@@ -90,7 +91,7 @@
uint32_t curr_index,
uint32_t prev_index,
bool* have_class,
- uint16_t* class_type_index,
+ dex::TypeIndex* class_type_index,
uint32_t* class_access_flags);
bool CheckPadding(size_t offset, uint32_t aligned_offset);
@@ -104,7 +105,7 @@
template <bool kStatic>
bool CheckIntraClassDataItemFields(ClassDataItemIterator* it,
bool* have_class,
- uint16_t* class_type_index,
+ dex::TypeIndex* class_type_index,
uint32_t* class_access_flags);
// Check all methods of the given type from the given iterator. Load the class data from the first
// method, if necessary (and return it), or use the given values.
@@ -112,7 +113,7 @@
bool CheckIntraClassDataItemMethods(ClassDataItemIterator* it,
std::unordered_set<uint32_t>* direct_method_indexes,
bool* have_class,
- uint16_t* class_type_index,
+ dex::TypeIndex* class_type_index,
uint32_t* class_access_flags);
bool CheckIntraCodeItem();
@@ -130,8 +131,8 @@
// Note: as sometimes kDexNoIndex16, being 0xFFFF, is a valid return value, we need an
// additional out parameter to signal any errors loading an index.
- uint16_t FindFirstClassDataDefiner(const uint8_t* ptr, bool* success);
- uint16_t FindFirstAnnotationsDirectoryDefiner(const uint8_t* ptr, bool* success);
+ dex::TypeIndex FindFirstClassDataDefiner(const uint8_t* ptr, bool* success);
+ dex::TypeIndex FindFirstAnnotationsDirectoryDefiner(const uint8_t* ptr, bool* success);
bool CheckInterStringIdItem();
bool CheckInterTypeIdItem();
@@ -150,7 +151,7 @@
// Load a string by (type) index. Checks whether the index is in bounds, printing the error if
// not. If there is an error, null is returned.
const char* CheckLoadStringByIdx(uint32_t idx, const char* error_fmt);
- const char* CheckLoadStringByTypeIdx(uint32_t type_idx, const char* error_fmt);
+ const char* CheckLoadStringByTypeIdx(dex::TypeIndex type_idx, const char* error_fmt);
// Load a field/method Id by index. Checks whether the index is in bounds, printing the error if
// not. If there is an error, null is returned.
@@ -168,7 +169,7 @@
// linear search. The output values should thus be cached by the caller.
bool FindClassFlags(uint32_t index,
bool is_field,
- uint16_t* class_type_index,
+ dex::TypeIndex* class_type_index,
uint32_t* class_access_flags);
// Check validity of the given access flags, interpreted for a field in the context of a class
diff --git a/runtime/dex_file_verifier_test.cc b/runtime/dex_file_verifier_test.cc
index 3801c22..0e0929f 100644
--- a/runtime/dex_file_verifier_test.cc
+++ b/runtime/dex_file_verifier_test.cc
@@ -26,6 +26,7 @@
#include "base/macros.h"
#include "common_runtime_test.h"
#include "dex_file-inl.h"
+#include "dex_file_types.h"
#include "leb128.h"
#include "scoped_thread_state_change-inl.h"
#include "thread-inl.h"
@@ -155,7 +156,7 @@
"method_id_class_idx",
[](DexFile* dex_file) {
DexFile::MethodId* method_id = const_cast<DexFile::MethodId*>(&dex_file->GetMethodId(0));
- method_id->class_idx_ = 0xFF;
+ method_id->class_idx_ = dex::TypeIndex(0xFF);
},
"could not find declaring class for direct method index 0");
diff --git a/runtime/dex_instruction.cc b/runtime/dex_instruction.cc
index c766b54..751bd51 100644
--- a/runtime/dex_instruction.cc
+++ b/runtime/dex_instruction.cc
@@ -208,9 +208,9 @@
case CONST_CLASS:
case NEW_INSTANCE:
if (file != nullptr) {
- uint32_t type_idx = VRegB_21c();
- os << opcode << " v" << static_cast<int>(VRegA_21c()) << ", " << file->PrettyType(type_idx)
- << " // type@" << type_idx;
+ dex::TypeIndex type_idx(VRegB_21c());
+ os << opcode << " v" << static_cast<int>(VRegA_21c()) << ", "
+ << file->PrettyType(type_idx) << " // type@" << type_idx;
break;
}
FALLTHROUGH_INTENDED;
@@ -302,17 +302,19 @@
FALLTHROUGH_INTENDED;
case INSTANCE_OF:
if (file != nullptr) {
- uint32_t type_idx = VRegC_22c();
- os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
- << file->PrettyType(type_idx) << " // type@" << type_idx;
+ dex::TypeIndex type_idx(VRegC_22c());
+ os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v"
+ << static_cast<int>(VRegB_22c()) << ", " << file->PrettyType(type_idx)
+ << " // type@" << type_idx.index_;
break;
}
FALLTHROUGH_INTENDED;
case NEW_ARRAY:
if (file != nullptr) {
- uint32_t type_idx = VRegC_22c();
- os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
- << file->PrettyType(type_idx) << " // type@" << type_idx;
+ dex::TypeIndex type_idx(VRegC_22c());
+ os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v"
+ << static_cast<int>(VRegB_22c()) << ", " << file->PrettyType(type_idx)
+ << " // type@" << type_idx.index_;
break;
}
FALLTHROUGH_INTENDED;
diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h
index ed60f59..ac52f4e 100644
--- a/runtime/entrypoints/entrypoint_utils-inl.h
+++ b/runtime/entrypoints/entrypoint_utils-inl.h
@@ -129,7 +129,7 @@
template <const bool kAccessCheck>
ALWAYS_INLINE
-inline mirror::Class* CheckObjectAlloc(uint32_t type_idx,
+inline mirror::Class* CheckObjectAlloc(dex::TypeIndex type_idx,
ArtMethod* method,
Thread* self,
bool* slow_path) {
@@ -219,7 +219,7 @@
// check.
template <bool kAccessCheck, bool kInstrumented>
ALWAYS_INLINE
-inline mirror::Object* AllocObjectFromCode(uint32_t type_idx,
+inline mirror::Object* AllocObjectFromCode(dex::TypeIndex type_idx,
ArtMethod* method,
Thread* self,
gc::AllocatorType allocator_type) {
@@ -275,7 +275,7 @@
template <bool kAccessCheck>
ALWAYS_INLINE
-inline mirror::Class* CheckArrayAlloc(uint32_t type_idx,
+inline mirror::Class* CheckArrayAlloc(dex::TypeIndex type_idx,
int32_t component_count,
ArtMethod* method,
bool* slow_path) {
@@ -313,7 +313,7 @@
// check.
template <bool kAccessCheck, bool kInstrumented>
ALWAYS_INLINE
-inline mirror::Array* AllocArrayFromCode(uint32_t type_idx,
+inline mirror::Array* AllocArrayFromCode(dex::TypeIndex type_idx,
int32_t component_count,
ArtMethod* method,
Thread* self,
@@ -562,7 +562,7 @@
StackHandleScope<2> hs2(self);
HandleWrapperObjPtr<mirror::Object> h_this(hs2.NewHandleWrapper(this_object));
Handle<mirror::Class> h_referring_class(hs2.NewHandle(referrer->GetDeclaringClass()));
- const uint16_t method_type_idx =
+ const dex::TypeIndex method_type_idx =
h_referring_class->GetDexFile().GetMethodId(method_idx).class_idx_;
mirror::Class* method_reference_class = class_linker->ResolveType(method_type_idx, referrer);
if (UNLIKELY(method_reference_class == nullptr)) {
@@ -758,7 +758,8 @@
return resolved_method;
} else if (type == kSuper) {
// TODO This lookup is rather slow.
- uint16_t method_type_idx = referring_class->GetDexFile().GetMethodId(method_idx).class_idx_;
+ dex::TypeIndex method_type_idx =
+ referring_class->GetDexFile().GetMethodId(method_idx).class_idx_;
mirror::Class* method_reference_class =
referring_class->GetDexCache()->GetResolvedType(method_type_idx);
if (method_reference_class == nullptr) {
@@ -788,8 +789,11 @@
}
}
-inline mirror::Class* ResolveVerifyAndClinit(uint32_t type_idx, ArtMethod* referrer, Thread* self,
- bool can_run_clinit, bool verify_access) {
+inline mirror::Class* ResolveVerifyAndClinit(dex::TypeIndex type_idx,
+ ArtMethod* referrer,
+ Thread* self,
+ bool can_run_clinit,
+ bool verify_access) {
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
mirror::Class* klass = class_linker->ResolveType(type_idx, referrer);
if (UNLIKELY(klass == nullptr)) {
diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc
index 1ccb4b0..5390165 100644
--- a/runtime/entrypoints/entrypoint_utils.cc
+++ b/runtime/entrypoints/entrypoint_utils.cc
@@ -38,7 +38,7 @@
namespace art {
-static inline mirror::Class* CheckFilledNewArrayAlloc(uint32_t type_idx,
+static inline mirror::Class* CheckFilledNewArrayAlloc(dex::TypeIndex type_idx,
int32_t component_count,
ArtMethod* referrer,
Thread* self,
@@ -82,10 +82,12 @@
}
// Helper function to allocate array for FILLED_NEW_ARRAY.
-mirror::Array* CheckAndAllocArrayFromCode(uint32_t type_idx, int32_t component_count,
- ArtMethod* referrer, Thread* self,
+mirror::Array* CheckAndAllocArrayFromCode(dex::TypeIndex type_idx,
+ int32_t component_count,
+ ArtMethod* referrer,
+ Thread* self,
bool access_check,
- gc::AllocatorType /* allocator_type */) {
+ gc::AllocatorType allocator_type ATTRIBUTE_UNUSED) {
mirror::Class* klass = CheckFilledNewArrayAlloc(type_idx, component_count, referrer, self,
access_check);
if (UNLIKELY(klass == nullptr)) {
@@ -101,12 +103,13 @@
}
// Helper function to allocate array for FILLED_NEW_ARRAY.
-mirror::Array* CheckAndAllocArrayFromCodeInstrumented(uint32_t type_idx,
- int32_t component_count,
- ArtMethod* referrer,
- Thread* self,
- bool access_check,
- gc::AllocatorType /* allocator_type */) {
+mirror::Array* CheckAndAllocArrayFromCodeInstrumented(
+ dex::TypeIndex type_idx,
+ int32_t component_count,
+ ArtMethod* referrer,
+ Thread* self,
+ bool access_check,
+ gc::AllocatorType allocator_type ATTRIBUTE_UNUSED) {
mirror::Class* klass = CheckFilledNewArrayAlloc(type_idx, component_count, referrer, self,
access_check);
if (UNLIKELY(klass == nullptr)) {
diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h
index bcddfb0..d87dc67 100644
--- a/runtime/entrypoints/entrypoint_utils.h
+++ b/runtime/entrypoints/entrypoint_utils.h
@@ -23,6 +23,7 @@
#include "base/macros.h"
#include "base/mutex.h"
#include "dex_instruction.h"
+#include "dex_file_types.h"
#include "gc/allocator_type.h"
#include "handle.h"
#include "invoke_type.h"
@@ -45,7 +46,7 @@
class Thread;
template <const bool kAccessCheck>
-ALWAYS_INLINE inline mirror::Class* CheckObjectAlloc(uint32_t type_idx,
+ALWAYS_INLINE inline mirror::Class* CheckObjectAlloc(dex::TypeIndex type_idx,
ArtMethod* method,
Thread* self,
bool* slow_path)
@@ -63,7 +64,7 @@
// When verification/compiler hasn't been able to verify access, optionally perform an access
// check.
template <bool kAccessCheck, bool kInstrumented>
-ALWAYS_INLINE inline mirror::Object* AllocObjectFromCode(uint32_t type_idx,
+ALWAYS_INLINE inline mirror::Object* AllocObjectFromCode(dex::TypeIndex type_idx,
ArtMethod* method,
Thread* self,
gc::AllocatorType allocator_type)
@@ -89,7 +90,7 @@
template <bool kAccessCheck>
-ALWAYS_INLINE inline mirror::Class* CheckArrayAlloc(uint32_t type_idx,
+ALWAYS_INLINE inline mirror::Class* CheckArrayAlloc(dex::TypeIndex type_idx,
int32_t component_count,
ArtMethod* method,
bool* slow_path)
@@ -101,7 +102,7 @@
// When verification/compiler hasn't been able to verify access, optionally perform an access
// check.
template <bool kAccessCheck, bool kInstrumented>
-ALWAYS_INLINE inline mirror::Array* AllocArrayFromCode(uint32_t type_idx,
+ALWAYS_INLINE inline mirror::Array* AllocArrayFromCode(dex::TypeIndex type_idx,
int32_t component_count,
ArtMethod* method,
Thread* self,
@@ -118,19 +119,21 @@
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Roles::uninterruptible_);
-extern mirror::Array* CheckAndAllocArrayFromCode(uint32_t type_idx, int32_t component_count,
- ArtMethod* method, Thread* self,
- bool access_check,
- gc::AllocatorType allocator_type)
+mirror::Array* CheckAndAllocArrayFromCode(dex::TypeIndex type_idx,
+ int32_t component_count,
+ ArtMethod* method,
+ Thread* self,
+ bool access_check,
+ gc::AllocatorType allocator_type)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Roles::uninterruptible_);
-extern mirror::Array* CheckAndAllocArrayFromCodeInstrumented(uint32_t type_idx,
- int32_t component_count,
- ArtMethod* method,
- Thread* self,
- bool access_check,
- gc::AllocatorType allocator_type)
+mirror::Array* CheckAndAllocArrayFromCodeInstrumented(dex::TypeIndex type_idx,
+ int32_t component_count,
+ ArtMethod* method,
+ Thread* self,
+ bool access_check,
+ gc::AllocatorType allocator_type)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Roles::uninterruptible_);
@@ -177,7 +180,7 @@
InvokeType type)
REQUIRES_SHARED(Locks::mutator_lock_);
-inline mirror::Class* ResolveVerifyAndClinit(uint32_t type_idx,
+inline mirror::Class* ResolveVerifyAndClinit(dex::TypeIndex type_idx,
ArtMethod* referrer,
Thread* self,
bool can_run_clinit,
diff --git a/runtime/entrypoints/quick/quick_alloc_entrypoints.cc b/runtime/entrypoints/quick/quick_alloc_entrypoints.cc
index 515fcbf..397655a 100644
--- a/runtime/entrypoints/quick/quick_alloc_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_alloc_entrypoints.cc
@@ -19,6 +19,7 @@
#include "art_method-inl.h"
#include "base/enums.h"
#include "callee_save_frame.h"
+#include "dex_file_types.h"
#include "entrypoints/entrypoint_utils-inl.h"
#include "mirror/class-inl.h"
#include "mirror/object_array-inl.h"
@@ -34,7 +35,8 @@
REQUIRES_SHARED(Locks::mutator_lock_) { \
ScopedQuickEntrypointChecks sqec(self); \
if (kUseTlabFastPath && !(instrumented_bool) && (allocator_type) == gc::kAllocatorTypeTLAB) { \
- mirror::Class* klass = method->GetDexCacheResolvedType<false>(type_idx, kRuntimePointerSize); \
+ mirror::Class* klass = method->GetDexCacheResolvedType<false>(dex::TypeIndex(type_idx), \
+ kRuntimePointerSize); \
if (LIKELY(klass != nullptr && klass->IsInitialized() && !klass->IsFinalizable())) { \
size_t byte_count = klass->GetObjectSize(); \
byte_count = RoundUp(byte_count, gc::space::BumpPointerSpace::kAlignment); \
@@ -51,7 +53,10 @@
} \
} \
} \
- return AllocObjectFromCode<false, instrumented_bool>(type_idx, method, self, allocator_type); \
+ return AllocObjectFromCode<false, instrumented_bool>(dex::TypeIndex(type_idx), \
+ method, \
+ self, \
+ allocator_type); \
} \
extern "C" mirror::Object* artAllocObjectFromCodeResolved##suffix##suffix2( \
mirror::Class* klass, ArtMethod* method ATTRIBUTE_UNUSED, Thread* self) \
@@ -101,13 +106,19 @@
uint32_t type_idx, ArtMethod* method, Thread* self) \
REQUIRES_SHARED(Locks::mutator_lock_) { \
ScopedQuickEntrypointChecks sqec(self); \
- return AllocObjectFromCode<true, instrumented_bool>(type_idx, method, self, allocator_type); \
+ return AllocObjectFromCode<true, instrumented_bool>(dex::TypeIndex(type_idx), \
+ method, \
+ self, \
+ allocator_type); \
} \
extern "C" mirror::Array* artAllocArrayFromCode##suffix##suffix2( \
uint32_t type_idx, int32_t component_count, ArtMethod* method, Thread* self) \
REQUIRES_SHARED(Locks::mutator_lock_) { \
ScopedQuickEntrypointChecks sqec(self); \
- return AllocArrayFromCode<false, instrumented_bool>(type_idx, component_count, method, self, \
+ return AllocArrayFromCode<false, instrumented_bool>(dex::TypeIndex(type_idx), \
+ component_count, \
+ method, \
+ self, \
allocator_type); \
} \
extern "C" mirror::Array* artAllocArrayFromCodeResolved##suffix##suffix2( \
@@ -121,7 +132,10 @@
uint32_t type_idx, int32_t component_count, ArtMethod* method, Thread* self) \
REQUIRES_SHARED(Locks::mutator_lock_) { \
ScopedQuickEntrypointChecks sqec(self); \
- return AllocArrayFromCode<true, instrumented_bool>(type_idx, component_count, method, self, \
+ return AllocArrayFromCode<true, instrumented_bool>(dex::TypeIndex(type_idx), \
+ component_count, \
+ method, \
+ self, \
allocator_type); \
} \
extern "C" mirror::Array* artCheckAndAllocArrayFromCode##suffix##suffix2( \
@@ -129,9 +143,19 @@
REQUIRES_SHARED(Locks::mutator_lock_) { \
ScopedQuickEntrypointChecks sqec(self); \
if (!(instrumented_bool)) { \
- return CheckAndAllocArrayFromCode(type_idx, component_count, method, self, false, allocator_type); \
+ return CheckAndAllocArrayFromCode(dex::TypeIndex(type_idx), \
+ component_count, \
+ method, \
+ self, \
+ false, \
+ allocator_type); \
} else { \
- return CheckAndAllocArrayFromCodeInstrumented(type_idx, component_count, method, self, false, allocator_type); \
+ return CheckAndAllocArrayFromCodeInstrumented(dex::TypeIndex(type_idx), \
+ component_count, \
+ method, \
+ self, \
+ false, \
+ allocator_type); \
} \
} \
extern "C" mirror::Array* artCheckAndAllocArrayFromCodeWithAccessCheck##suffix##suffix2( \
@@ -139,9 +163,19 @@
REQUIRES_SHARED(Locks::mutator_lock_) { \
ScopedQuickEntrypointChecks sqec(self); \
if (!(instrumented_bool)) { \
- return CheckAndAllocArrayFromCode(type_idx, component_count, method, self, true, allocator_type); \
+ return CheckAndAllocArrayFromCode(dex::TypeIndex(type_idx), \
+ component_count, \
+ method, \
+ self, \
+ true, \
+ allocator_type); \
} else { \
- return CheckAndAllocArrayFromCodeInstrumented(type_idx, component_count, method, self, true, allocator_type); \
+ return CheckAndAllocArrayFromCodeInstrumented(dex::TypeIndex(type_idx), \
+ component_count, \
+ method, \
+ self, \
+ true, \
+ allocator_type); \
} \
} \
extern "C" mirror::String* artAllocStringFromBytesFromCode##suffix##suffix2( \
diff --git a/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
index d438418..b1259e1 100644
--- a/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
@@ -20,6 +20,7 @@
#include "class_linker-inl.h"
#include "class_table-inl.h"
#include "dex_file-inl.h"
+#include "dex_file_types.h"
#include "gc/heap.h"
#include "mirror/class-inl.h"
#include "mirror/class_loader.h"
@@ -37,7 +38,7 @@
// given by inheritance.
ScopedQuickEntrypointChecks sqec(self);
auto* caller = GetCalleeSaveMethodCaller(self, Runtime::kSaveRefsOnly);
- return ResolveVerifyAndClinit(type_idx, caller, self, true, false);
+ return ResolveVerifyAndClinit(dex::TypeIndex(type_idx), caller, self, true, false);
}
extern "C" mirror::Class* artInitializeTypeFromCode(uint32_t type_idx, Thread* self)
@@ -45,7 +46,7 @@
// Called when method->dex_cache_resolved_types_[] misses.
ScopedQuickEntrypointChecks sqec(self);
auto* caller = GetCalleeSaveMethodCaller(self, Runtime::kSaveRefsOnly);
- return ResolveVerifyAndClinit(type_idx, caller, self, false, false);
+ return ResolveVerifyAndClinit(dex::TypeIndex(type_idx), caller, self, false, false);
}
extern "C" mirror::Class* artInitializeTypeAndVerifyAccessFromCode(uint32_t type_idx, Thread* self)
@@ -54,7 +55,7 @@
// unpopulated.
ScopedQuickEntrypointChecks sqec(self);
auto* caller = GetCalleeSaveMethodCaller(self, Runtime::kSaveRefsOnly);
- return ResolveVerifyAndClinit(type_idx, caller, self, false, true);
+ return ResolveVerifyAndClinit(dex::TypeIndex(type_idx), caller, self, false, true);
}
extern "C" mirror::String* artResolveStringFromCode(int32_t string_idx, Thread* self)
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index a32c800..1b3d339 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -543,7 +543,7 @@
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
// This is a suspend point. But it's ok since value has been set into shadow_frame.
ObjPtr<mirror::Class> klass = class_linker->ResolveType(
- instr->VRegB_21c(), shadow_frame->GetMethod());
+ dex::TypeIndex(instr->VRegB_21c()), shadow_frame->GetMethod());
DCHECK(klass->IsStringClass());
}
} else {
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index 8c63a9e..05f74d6 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -1460,7 +1460,7 @@
ObjPtr<mirror::Object> o = shadow_frame.GetVRegReference(src_reg);
if (do_assignability_check && o != nullptr) {
PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
- const uint32_t type_idx = params->GetTypeItem(shorty_pos).type_idx_;
+ const dex::TypeIndex type_idx = params->GetTypeItem(shorty_pos).type_idx_;
ObjPtr<mirror::Class> arg_type = method->GetDexCacheResolvedType(type_idx,
pointer_size);
if (arg_type == nullptr) {
@@ -1568,7 +1568,7 @@
return false;
}
uint16_t type_idx = is_range ? inst->VRegB_3rc() : inst->VRegB_35c();
- ObjPtr<mirror::Class> array_class = ResolveVerifyAndClinit(type_idx,
+ ObjPtr<mirror::Class> array_class = ResolveVerifyAndClinit(dex::TypeIndex(type_idx),
shadow_frame.GetMethod(),
self,
false,
diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl.cc
index 435ac62..989b7da 100644
--- a/runtime/interpreter/interpreter_switch_impl.cc
+++ b/runtime/interpreter/interpreter_switch_impl.cc
@@ -395,7 +395,7 @@
}
case Instruction::CONST_CLASS: {
PREAMBLE();
- ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(inst->VRegB_21c(),
+ ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(dex::TypeIndex(inst->VRegB_21c()),
shadow_frame.GetMethod(),
self,
false,
@@ -434,7 +434,7 @@
}
case Instruction::CHECK_CAST: {
PREAMBLE();
- ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(inst->VRegB_21c(),
+ ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(dex::TypeIndex(inst->VRegB_21c()),
shadow_frame.GetMethod(),
self,
false,
@@ -454,7 +454,7 @@
}
case Instruction::INSTANCE_OF: {
PREAMBLE();
- ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(inst->VRegC_22c(),
+ ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(dex::TypeIndex(inst->VRegC_22c()),
shadow_frame.GetMethod(),
self,
false,
@@ -484,7 +484,7 @@
case Instruction::NEW_INSTANCE: {
PREAMBLE();
ObjPtr<mirror::Object> obj = nullptr;
- ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(inst->VRegB_21c(),
+ ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(dex::TypeIndex(inst->VRegB_21c()),
shadow_frame.GetMethod(),
self,
false,
@@ -495,8 +495,10 @@
obj = mirror::String::AllocEmptyString<true>(self, allocator_type);
} else {
obj = AllocObjectFromCode<do_access_check, true>(
- inst->VRegB_21c(), shadow_frame.GetMethod(), self,
- Runtime::Current()->GetHeap()->GetCurrentAllocator());
+ dex::TypeIndex(inst->VRegB_21c()),
+ shadow_frame.GetMethod(),
+ self,
+ Runtime::Current()->GetHeap()->GetCurrentAllocator());
}
}
if (UNLIKELY(obj == nullptr)) {
@@ -520,7 +522,10 @@
PREAMBLE();
int32_t length = shadow_frame.GetVReg(inst->VRegB_22c(inst_data));
ObjPtr<mirror::Object> obj = AllocArrayFromCode<do_access_check, true>(
- inst->VRegC_22c(), length, shadow_frame.GetMethod(), self,
+ dex::TypeIndex(inst->VRegC_22c()),
+ length,
+ shadow_frame.GetMethod(),
+ self,
Runtime::Current()->GetHeap()->GetCurrentAllocator());
if (UNLIKELY(obj == nullptr)) {
HANDLE_PENDING_EXCEPTION();
diff --git a/runtime/interpreter/mterp/mterp.cc b/runtime/interpreter/mterp/mterp.cc
index 2bd47bb..fbfed40 100644
--- a/runtime/interpreter/mterp/mterp.cc
+++ b/runtime/interpreter/mterp/mterp.cc
@@ -304,7 +304,11 @@
ShadowFrame* shadow_frame,
Thread* self)
REQUIRES_SHARED(Locks::mutator_lock_) {
- mirror::Class* c = ResolveVerifyAndClinit(index, shadow_frame->GetMethod(), self, false, false);
+ mirror::Class* c = ResolveVerifyAndClinit(dex::TypeIndex(index),
+ shadow_frame->GetMethod(),
+ self,
+ false,
+ false);
if (UNLIKELY(c == nullptr)) {
return true;
}
@@ -317,7 +321,11 @@
art::ArtMethod* method,
Thread* self)
REQUIRES_SHARED(Locks::mutator_lock_) {
- ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(index, method, self, false, false);
+ ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(dex::TypeIndex(index),
+ method,
+ self,
+ false,
+ false);
if (UNLIKELY(c == nullptr)) {
return true;
}
@@ -335,7 +343,11 @@
art::ArtMethod* method,
Thread* self)
REQUIRES_SHARED(Locks::mutator_lock_) {
- ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(index, method, self, false, false);
+ ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(dex::TypeIndex(index),
+ method,
+ self,
+ false,
+ false);
if (UNLIKELY(c == nullptr)) {
return false; // Caller will check for pending exception. Return value unimportant.
}
@@ -353,7 +365,7 @@
REQUIRES_SHARED(Locks::mutator_lock_) {
const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
mirror::Object* obj = nullptr;
- mirror::Class* c = ResolveVerifyAndClinit(inst->VRegB_21c(),
+ mirror::Class* c = ResolveVerifyAndClinit(dex::TypeIndex(inst->VRegB_21c()),
shadow_frame->GetMethod(),
self,
false,
@@ -363,9 +375,10 @@
gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
obj = mirror::String::AllocEmptyString<true>(self, allocator_type);
} else {
- obj = AllocObjectFromCode<false, true>(
- inst->VRegB_21c(), shadow_frame->GetMethod(), self,
- Runtime::Current()->GetHeap()->GetCurrentAllocator());
+ obj = AllocObjectFromCode<false, true>(dex::TypeIndex(inst->VRegB_21c()),
+ shadow_frame->GetMethod(),
+ self,
+ Runtime::Current()->GetHeap()->GetCurrentAllocator());
}
}
if (UNLIKELY(obj == nullptr)) {
@@ -446,7 +459,7 @@
const Instruction* inst = Instruction::At(dex_pc_ptr);
int32_t length = shadow_frame->GetVReg(inst->VRegB_22c(inst_data));
mirror::Object* obj = AllocArrayFromCode<false, true>(
- inst->VRegC_22c(), length, shadow_frame->GetMethod(), self,
+ dex::TypeIndex(inst->VRegC_22c()), length, shadow_frame->GetMethod(), self,
Runtime::Current()->GetHeap()->GetCurrentAllocator());
if (UNLIKELY(obj == nullptr)) {
return false;
diff --git a/runtime/jit/offline_profiling_info.cc b/runtime/jit/offline_profiling_info.cc
index b9f5981..6f2a8c6 100644
--- a/runtime/jit/offline_profiling_info.cc
+++ b/runtime/jit/offline_profiling_info.cc
@@ -235,7 +235,7 @@
AddUintToBuffer(&buffer, method_it);
}
for (auto class_id : dex_data.class_set) {
- AddUintToBuffer(&buffer, class_id);
+ AddUintToBuffer(&buffer, class_id.index_);
}
DCHECK_EQ(required_capacity, buffer.size())
<< "Failed to add the expected number of bytes in the buffer";
@@ -282,7 +282,7 @@
bool ProfileCompilationInfo::AddClassIndex(const std::string& dex_location,
uint32_t checksum,
- uint16_t type_idx) {
+ dex::TypeIndex type_idx) {
DexFileData* const data = GetOrAddDexFileData(dex_location, checksum);
if (data == nullptr) {
return false;
@@ -305,7 +305,7 @@
for (uint16_t i = 0; i < class_set_size; i++) {
uint16_t type_idx = line_buffer.ReadUintAndAdvance<uint16_t>();
- if (!AddClassIndex(dex_location, checksum, type_idx)) {
+ if (!AddClassIndex(dex_location, checksum, dex::TypeIndex(type_idx))) {
return false;
}
}
@@ -569,13 +569,13 @@
return false;
}
-bool ProfileCompilationInfo::ContainsClass(const DexFile& dex_file, uint16_t type_idx) const {
+bool ProfileCompilationInfo::ContainsClass(const DexFile& dex_file, dex::TypeIndex type_idx) const {
auto info_it = info_.find(GetProfileDexFileKey(dex_file.GetLocation()));
if (info_it != info_.end()) {
if (!ChecksumMatch(dex_file, info_it->second.checksum)) {
return false;
}
- const std::set<uint16_t>& classes = info_it->second.class_set;
+ const std::set<dex::TypeIndex>& classes = info_it->second.class_set;
return classes.find(type_idx) != classes.end();
}
return false;
@@ -706,7 +706,7 @@
if (c < (number_of_classes / kFavorSplit)) {
type_idx %= kFavorFirstN;
}
- info.AddClassIndex(profile_key, 0, type_idx);
+ info.AddClassIndex(profile_key, 0, dex::TypeIndex(type_idx));
}
}
return info.Save(fd);
diff --git a/runtime/jit/offline_profiling_info.h b/runtime/jit/offline_profiling_info.h
index f8ed573..4136488 100644
--- a/runtime/jit/offline_profiling_info.h
+++ b/runtime/jit/offline_profiling_info.h
@@ -23,6 +23,7 @@
#include "atomic.h"
#include "dex_cache_resolved_classes.h"
#include "dex_file.h"
+#include "dex_file_types.h"
#include "method_reference.h"
#include "safe_map.h"
@@ -66,7 +67,7 @@
bool ContainsMethod(const MethodReference& method_ref) const;
// Returns true if the class's type is present in the profiling info.
- bool ContainsClass(const DexFile& dex_file, uint16_t type_idx) const;
+ bool ContainsClass(const DexFile& dex_file, dex::TypeIndex type_idx) const;
// Dumps all the loaded profile info into a string and returns it.
// If dex_files is not null then the method indices will be resolved to their
@@ -104,7 +105,7 @@
explicit DexFileData(uint32_t location_checksum) : checksum(location_checksum) {}
uint32_t checksum;
std::set<uint16_t> method_set;
- std::set<uint16_t> class_set;
+ std::set<dex::TypeIndex> class_set;
bool operator==(const DexFileData& other) const {
return checksum == other.checksum && method_set == other.method_set;
@@ -115,7 +116,7 @@
DexFileData* GetOrAddDexFileData(const std::string& dex_location, uint32_t checksum);
bool AddMethodIndex(const std::string& dex_location, uint32_t checksum, uint16_t method_idx);
- bool AddClassIndex(const std::string& dex_location, uint32_t checksum, uint16_t type_idx);
+ bool AddClassIndex(const std::string& dex_location, uint32_t checksum, dex::TypeIndex type_idx);
bool AddResolvedClasses(const DexCacheResolvedClasses& classes);
// Parsing functionality.
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index 9a6d60e..aa5da2e 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -372,7 +372,7 @@
// to access the field if the FieldId specifies an accessible subclass of the declaring
// class rather than the declaring class itself.
ObjPtr<DexCache> referrer_dex_cache = use_referrers_cache ? this->GetDexCache() : dex_cache;
- uint32_t class_idx = referrer_dex_cache->GetDexFile()->GetFieldId(field_idx).class_idx_;
+ dex::TypeIndex class_idx = referrer_dex_cache->GetDexFile()->GetFieldId(field_idx).class_idx_;
// The referenced class has already been resolved with the field, but may not be in the dex
// cache. Use LookupResolveType here to search the class table if it is not in the dex cache.
// should be no thread suspension due to the class being resolved.
@@ -410,7 +410,7 @@
// to access the method if the MethodId specifies an accessible subclass of the declaring
// class rather than the declaring class itself.
ObjPtr<DexCache> referrer_dex_cache = use_referrers_cache ? this->GetDexCache() : dex_cache;
- uint32_t class_idx = referrer_dex_cache->GetDexFile()->GetMethodId(method_idx).class_idx_;
+ dex::TypeIndex class_idx = referrer_dex_cache->GetDexFile()->GetMethodId(method_idx).class_idx_;
// The referenced class has already been resolved with the method, but may not be in the dex
// cache.
ObjPtr<Class> dex_access_to = Runtime::Current()->GetClassLinker()->LookupResolvedType(
@@ -894,7 +894,8 @@
klass->SetClassSize(class_size_);
klass->SetPrimitiveType(Primitive::kPrimNot); // Default to not being primitive.
klass->SetDexClassDefIndex(DexFile::kDexNoIndex16); // Default to no valid class def index.
- klass->SetDexTypeIndex(DexFile::kDexNoIndex16); // Default to no valid type index.
+ klass->SetDexTypeIndex(dex::TypeIndex(DexFile::kDexNoIndex16)); // Default to no valid type
+ // index.
// Default to force slow path until initialized.
klass->SetObjectSizeAllocFastPath(std::numeric_limits<uint32_t>::max());
}
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index db46027..0cfe29b 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -923,7 +923,7 @@
return &GetDexFile().GetClassDef(class_def_idx);
}
-uint16_t Class::GetDirectInterfaceTypeIdx(uint32_t idx) {
+dex::TypeIndex Class::GetDirectInterfaceTypeIdx(uint32_t idx) {
DCHECK(!IsPrimitive());
DCHECK(!IsArrayClass());
return GetInterfaceTypeList()->GetTypeItem(idx).type_idx_;
@@ -947,10 +947,11 @@
DCHECK(interfaces != nullptr);
return interfaces->Get(idx);
} else {
- uint16_t type_idx = klass->GetDirectInterfaceTypeIdx(idx);
+ dex::TypeIndex type_idx = klass->GetDirectInterfaceTypeIdx(idx);
ObjPtr<Class> interface = klass->GetDexCache()->GetResolvedType(type_idx);
if (interface == nullptr) {
- interface = Runtime::Current()->GetClassLinker()->ResolveType(klass->GetDexFile(), type_idx,
+ interface = Runtime::Current()->GetClassLinker()->ResolveType(klass->GetDexFile(),
+ type_idx,
klass.Get());
CHECK(interface != nullptr || self->IsExceptionPending());
}
@@ -1130,10 +1131,12 @@
return depth;
}
-uint32_t Class::FindTypeIndexInOtherDexFile(const DexFile& dex_file) {
+dex::TypeIndex Class::FindTypeIndexInOtherDexFile(const DexFile& dex_file) {
std::string temp;
const DexFile::TypeId* type_id = dex_file.FindTypeId(GetDescriptor(&temp));
- return (type_id == nullptr) ? DexFile::kDexNoIndex : dex_file.GetIndexForTypeId(*type_id);
+ return (type_id == nullptr)
+ ? dex::TypeIndex(DexFile::kDexNoIndex)
+ : dex_file.GetIndexForTypeId(*type_id);
}
template <PointerSize kPointerSize, bool kTransactionActive>
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index 711914d..792f626 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -20,6 +20,7 @@
#include "base/enums.h"
#include "base/iteration_range.h"
#include "dex_file.h"
+#include "dex_file_types.h"
#include "class_flags.h"
#include "gc_root.h"
#include "gc/allocator_type.h"
@@ -1148,16 +1149,17 @@
SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, dex_class_def_idx_), class_def_idx);
}
- uint16_t GetDexTypeIndex() REQUIRES_SHARED(Locks::mutator_lock_) {
- return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, dex_type_idx_));
+ dex::TypeIndex GetDexTypeIndex() REQUIRES_SHARED(Locks::mutator_lock_) {
+ return dex::TypeIndex(
+ static_cast<uint16_t>(GetField32(OFFSET_OF_OBJECT_MEMBER(Class, dex_type_idx_))));
}
- void SetDexTypeIndex(uint16_t type_idx) REQUIRES_SHARED(Locks::mutator_lock_) {
+ void SetDexTypeIndex(dex::TypeIndex type_idx) REQUIRES_SHARED(Locks::mutator_lock_) {
// Not called within a transaction.
- SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, dex_type_idx_), type_idx);
+ SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, dex_type_idx_), type_idx.index_);
}
- uint32_t FindTypeIndexInOtherDexFile(const DexFile& dex_file)
+ dex::TypeIndex FindTypeIndexInOtherDexFile(const DexFile& dex_file)
REQUIRES_SHARED(Locks::mutator_lock_);
static Class* GetJavaLangClass() REQUIRES_SHARED(Locks::mutator_lock_) {
@@ -1198,7 +1200,7 @@
ALWAYS_INLINE uint32_t NumDirectInterfaces() REQUIRES_SHARED(Locks::mutator_lock_);
- uint16_t GetDirectInterfaceTypeIdx(uint32_t idx) REQUIRES_SHARED(Locks::mutator_lock_);
+ dex::TypeIndex GetDirectInterfaceTypeIdx(uint32_t idx) REQUIRES_SHARED(Locks::mutator_lock_);
static ObjPtr<Class> GetDirectInterface(Thread* self,
Handle<Class> klass,
diff --git a/runtime/mirror/dex_cache-inl.h b/runtime/mirror/dex_cache-inl.h
index c7a123b..d903f71 100644
--- a/runtime/mirror/dex_cache-inl.h
+++ b/runtime/mirror/dex_cache-inl.h
@@ -69,15 +69,15 @@
}
}
-inline Class* DexCache::GetResolvedType(uint32_t type_idx) {
- DCHECK_LT(type_idx, NumResolvedTypes());
- return GetResolvedTypes()[type_idx].Read();
+inline Class* DexCache::GetResolvedType(dex::TypeIndex type_idx) {
+ DCHECK_LT(type_idx.index_, NumResolvedTypes());
+ return GetResolvedTypes()[type_idx.index_].Read();
}
-inline void DexCache::SetResolvedType(uint32_t type_idx, ObjPtr<Class> resolved) {
- DCHECK_LT(type_idx, NumResolvedTypes()); // NOTE: Unchecked, i.e. not throwing AIOOB.
+inline void DexCache::SetResolvedType(dex::TypeIndex type_idx, ObjPtr<Class> resolved) {
+ DCHECK_LT(type_idx.index_, NumResolvedTypes()); // NOTE: Unchecked, i.e. not throwing AIOOB.
// TODO default transaction support.
- GetResolvedTypes()[type_idx] = GcRoot<Class>(resolved);
+ GetResolvedTypes()[type_idx.index_] = GcRoot<Class>(resolved);
// TODO: Fine-grained marking, so that we don't need to go through all arrays in full.
Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(this);
}
diff --git a/runtime/mirror/dex_cache.h b/runtime/mirror/dex_cache.h
index 1ae694d..7d82d3a 100644
--- a/runtime/mirror/dex_cache.h
+++ b/runtime/mirror/dex_cache.h
@@ -21,6 +21,7 @@
#include "art_field.h"
#include "art_method.h"
#include "class.h"
+#include "dex_file_types.h"
#include "object.h"
#include "object_array.h"
@@ -223,9 +224,9 @@
// the string isn't kept live.
void ClearString(uint32_t string_idx) REQUIRES_SHARED(Locks::mutator_lock_);
- Class* GetResolvedType(uint32_t type_idx) REQUIRES_SHARED(Locks::mutator_lock_);
+ Class* GetResolvedType(dex::TypeIndex type_idx) REQUIRES_SHARED(Locks::mutator_lock_);
- void SetResolvedType(uint32_t type_idx, ObjPtr<Class> resolved)
+ void SetResolvedType(dex::TypeIndex type_idx, ObjPtr<Class> resolved)
REQUIRES_SHARED(Locks::mutator_lock_);
ALWAYS_INLINE ArtMethod* GetResolvedMethod(uint32_t method_idx, PointerSize ptr_size)
diff --git a/runtime/mirror/object_test.cc b/runtime/mirror/object_test.cc
index 5bf254d..4b47f7f 100644
--- a/runtime/mirror/object_test.cc
+++ b/runtime/mirror/object_test.cc
@@ -313,7 +313,7 @@
ArtMethod* sort = java_util_Arrays->FindDirectMethod("sort", "([I)V", kRuntimePointerSize);
const DexFile::TypeId* type_id = java_lang_dex_file_->FindTypeId("[I");
ASSERT_TRUE(type_id != nullptr);
- uint32_t type_idx = java_lang_dex_file_->GetIndexForTypeId(*type_id);
+ dex::TypeIndex type_idx = java_lang_dex_file_->GetIndexForTypeId(*type_id);
Object* array = CheckAndAllocArrayFromCodeInstrumented(
type_idx, 3, sort, Thread::Current(), false,
Runtime::Current()->GetHeap()->GetCurrentAllocator());
diff --git a/runtime/mirror/throwable.cc b/runtime/mirror/throwable.cc
index b866a63..ade4e87 100644
--- a/runtime/mirror/throwable.cc
+++ b/runtime/mirror/throwable.cc
@@ -104,7 +104,7 @@
CHECK_EQ(array_len % 2, 0);
const auto depth = array_len / 2;
if (depth == 0) {
- result += "(Throwable with empty stack trace)";
+ result += "(Throwable with empty stack trace)\n";
} else {
const PointerSize ptr_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
for (int32_t i = 0; i < depth; ++i) {
@@ -124,7 +124,7 @@
ObjPtr<ObjectArray<StackTraceElement>> ste_array =
ObjPtr<ObjectArray<StackTraceElement>>::DownCast(stack_trace);
if (ste_array->GetLength() == 0) {
- result += "(Throwable with empty stack trace)";
+ result += "(Throwable with empty stack trace)\n";
} else {
for (int32_t i = 0; i < ste_array->GetLength(); ++i) {
StackTraceElement* ste = ste_array->Get(i);
@@ -139,7 +139,7 @@
}
}
} else {
- result += "(Throwable with no stack trace)";
+ result += "(Throwable with no stack trace)\n";
}
}
ObjPtr<Throwable> cause = GetFieldObject<Throwable>(OFFSET_OF_OBJECT_MEMBER(Throwable, cause_));
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index 866dc7f..48feb11 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -34,6 +34,7 @@
#include "common_throws.h"
#include "debugger.h"
#include "dex_file-inl.h"
+#include "dex_file_types.h"
#include "gc/accounting/card_table-inl.h"
#include "gc/allocator/dlmalloc.h"
#include "gc/heap.h"
@@ -305,7 +306,7 @@
// Based on ClassLinker::ResolveType.
static void PreloadDexCachesResolveType(Thread* self,
ObjPtr<mirror::DexCache> dex_cache,
- uint32_t type_idx)
+ dex::TypeIndex type_idx)
REQUIRES_SHARED(Locks::mutator_lock_) {
ObjPtr<mirror::Class> klass = dex_cache->GetResolvedType(type_idx);
if (klass != nullptr) {
@@ -455,7 +456,7 @@
}
}
for (size_t j = 0; j < dex_cache->NumResolvedTypes(); j++) {
- ObjPtr<mirror::Class> klass = dex_cache->GetResolvedType(j);
+ ObjPtr<mirror::Class> klass = dex_cache->GetResolvedType(dex::TypeIndex(j));
if (klass != nullptr) {
filled->num_types++;
}
@@ -519,7 +520,7 @@
if (kPreloadDexCachesTypes) {
for (size_t j = 0; j < dex_cache->NumResolvedTypes(); j++) {
- PreloadDexCachesResolveType(soa.Self(), dex_cache.Get(), j);
+ PreloadDexCachesResolveType(soa.Self(), dex_cache.Get(), dex::TypeIndex(j));
}
}
diff --git a/runtime/native/java_lang_DexCache.cc b/runtime/native/java_lang_DexCache.cc
index 71379a5..f6de593 100644
--- a/runtime/native/java_lang_DexCache.cc
+++ b/runtime/native/java_lang_DexCache.cc
@@ -17,6 +17,7 @@
#include "java_lang_DexCache.h"
#include "dex_file.h"
+#include "dex_file_types.h"
#include "jni_internal.h"
#include "mirror/class-inl.h"
#include "mirror/dex_cache-inl.h"
@@ -53,7 +54,7 @@
ScopedFastNativeObjectAccess soa(env);
ObjPtr<mirror::DexCache> dex_cache = soa.Decode<mirror::DexCache>(javaDexCache);
CHECK_LT(static_cast<size_t>(type_index), dex_cache->NumResolvedTypes());
- return soa.AddLocalReference<jobject>(dex_cache->GetResolvedType(type_index));
+ return soa.AddLocalReference<jobject>(dex_cache->GetResolvedType(dex::TypeIndex(type_index)));
}
static jobject DexCache_getResolvedString(JNIEnv* env, jobject javaDexCache, jint string_index) {
@@ -68,7 +69,7 @@
ScopedFastNativeObjectAccess soa(env);
ObjPtr<mirror::DexCache> dex_cache = soa.Decode<mirror::DexCache>(javaDexCache);
CHECK_LT(static_cast<size_t>(type_index), dex_cache->NumResolvedTypes());
- dex_cache->SetResolvedType(type_index, soa.Decode<mirror::Class>(type));
+ dex_cache->SetResolvedType(dex::TypeIndex(type_index), soa.Decode<mirror::Class>(type));
}
static void DexCache_setResolvedString(JNIEnv* env, jobject javaDexCache, jint string_index,
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index c14b616..404e5ce 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -38,6 +38,7 @@
#include "base/stl_util.h"
#include "base/systrace.h"
#include "base/unix_file/fd_file.h"
+#include "dex_file_types.h"
#include "elf_file.h"
#include "elf_utils.h"
#include "gc_root.h"
@@ -1252,13 +1253,14 @@
if (lookup_table_data_ + TypeLookupTable::RawDataLength(num_class_defs) > GetOatFile()->End()) {
LOG(WARNING) << "found truncated lookup table in " << dex_file_location_;
} else {
- lookup_table_.reset(TypeLookupTable::Open(dex_file_pointer_,
- lookup_table_data_,
- num_class_defs));
+ lookup_table_ = TypeLookupTable::Open(dex_file_pointer_, lookup_table_data_, num_class_defs);
}
}
}
+OatFile::OatDexFile::OatDexFile(std::unique_ptr<TypeLookupTable>&& lookup_table)
+ : lookup_table_(std::move(lookup_table)) {}
+
OatFile::OatDexFile::~OatDexFile() {}
size_t OatFile::OatDexFile::FileSize() const {
@@ -1342,7 +1344,7 @@
}
const DexFile::TypeId* type_id = dex_file.FindTypeId(descriptor);
if (type_id != nullptr) {
- uint16_t type_idx = dex_file.GetIndexForTypeId(*type_id);
+ dex::TypeIndex type_idx = dex_file.GetIndexForTypeId(*type_id);
return dex_file.FindClassDef(type_idx);
}
return nullptr;
@@ -1540,7 +1542,7 @@
bool* found) {
DCHECK_NE(class_def_idx, DexFile::kDexNoIndex16);
const OatFile::OatDexFile* oat_dex_file = dex_file.GetOatDexFile();
- if (oat_dex_file == nullptr) {
+ if (oat_dex_file == nullptr || oat_dex_file->GetOatFile() == nullptr) {
*found = false;
return OatFile::OatClass::Invalid();
}
@@ -1548,4 +1550,8 @@
return oat_dex_file->GetOatClass(class_def_idx);
}
+void OatFile::OatDexFile::AssertAotCompiler() {
+ CHECK(Runtime::Current()->IsAotCompiler());
+}
+
} // namespace art
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index 63a0e14..29add5b 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -384,7 +384,13 @@
// Opens the DexFile referred to by this OatDexFile from within the containing OatFile.
std::unique_ptr<const DexFile> OpenDexFile(std::string* error_msg) const;
+ // May return null if the OatDexFile only contains a type lookup table. This case only happens
+ // for the compiler to speed up compilation.
const OatFile* GetOatFile() const {
+ // Avoid pulling in runtime.h in the header file.
+ if (kIsDebugBuild && oat_file_ == nullptr) {
+ AssertAotCompiler();
+ }
return oat_file_;
}
@@ -436,6 +442,9 @@
~OatDexFile();
+ // Create only with a type lookup table, used by the compiler to speed up compilation.
+ explicit OatDexFile(std::unique_ptr<TypeLookupTable>&& lookup_table);
+
private:
OatDexFile(const OatFile* oat_file,
const std::string& dex_file_location,
@@ -446,14 +455,16 @@
const uint32_t* oat_class_offsets_pointer,
uint8_t* dex_cache_arrays);
- const OatFile* const oat_file_;
+ static void AssertAotCompiler();
+
+ const OatFile* const oat_file_ = nullptr;
const std::string dex_file_location_;
const std::string canonical_dex_file_location_;
- const uint32_t dex_file_location_checksum_;
- const uint8_t* const dex_file_pointer_;
- const uint8_t* lookup_table_data_;
- const uint32_t* const oat_class_offsets_pointer_;
- uint8_t* const dex_cache_arrays_;
+ const uint32_t dex_file_location_checksum_ = 0u;
+ const uint8_t* const dex_file_pointer_ = nullptr;
+ const uint8_t* lookup_table_data_ = nullptr;
+ const uint32_t* const oat_class_offsets_pointer_ = 0u;
+ uint8_t* const dex_cache_arrays_ = nullptr;
mutable std::unique_ptr<TypeLookupTable> lookup_table_;
friend class OatFile;
diff --git a/runtime/openjdkjvmti/ti_heap.cc b/runtime/openjdkjvmti/ti_heap.cc
index 0eff469..5e588a8 100644
--- a/runtime/openjdkjvmti/ti_heap.cc
+++ b/runtime/openjdkjvmti/ti_heap.cc
@@ -269,6 +269,12 @@
ReportRoot(root_obj, info);
}
+ // Remove NO_THREAD_SAFETY_ANALYSIS once ASSERT_CAPABILITY works correctly.
+ art::Thread* FindThread(const art::RootInfo& info) NO_THREAD_SAFETY_ANALYSIS {
+ art::Locks::thread_list_lock_->AssertExclusiveHeld(art::Thread::Current());
+ return art::Runtime::Current()->GetThreadList()->FindThreadByThreadId(info.GetThreadId());
+ }
+
jvmtiHeapReferenceKind GetReferenceKind(const art::RootInfo& info,
jvmtiHeapReferenceInfo* ref_info)
REQUIRES_SHARED(art::Locks::mutator_lock_) {
@@ -280,7 +286,34 @@
return JVMTI_HEAP_REFERENCE_JNI_GLOBAL;
case art::RootType::kRootJNILocal:
+ {
+ uint32_t thread_id = info.GetThreadId();
+ ref_info->jni_local.thread_id = thread_id;
+
+ art::Thread* thread = FindThread(info);
+ if (thread != nullptr) {
+ art::mirror::Object* thread_obj = thread->GetPeer();
+ if (thread->IsStillStarting()) {
+ thread_obj = nullptr;
+ } else {
+ thread_obj = thread->GetPeer();
+ }
+ if (thread_obj != nullptr) {
+ ref_info->jni_local.thread_tag = tag_table_->GetTagOrZero(thread_obj);
+ }
+ }
+
+ // TODO: We don't have this info.
+ if (thread != nullptr) {
+ ref_info->jni_local.depth = 0;
+ art::ArtMethod* method = thread->GetCurrentMethod(nullptr, false /* abort_on_error */);
+ if (method != nullptr) {
+ ref_info->jni_local.method = art::jni::EncodeArtMethod(method);
+ }
+ }
+
return JVMTI_HEAP_REFERENCE_JNI_LOCAL;
+ }
case art::RootType::kRootJavaFrame:
return JVMTI_HEAP_REFERENCE_STACK_LOCAL;
diff --git a/runtime/openjdkjvmti/ti_method.cc b/runtime/openjdkjvmti/ti_method.cc
index e391a9d..ffa5ac7 100644
--- a/runtime/openjdkjvmti/ti_method.cc
+++ b/runtime/openjdkjvmti/ti_method.cc
@@ -78,7 +78,9 @@
}
// TODO: Support generic signature.
- *generic_ptr = nullptr;
+ if (generic_ptr != nullptr) {
+ *generic_ptr = nullptr;
+ }
// Everything is fine, release the buffers.
name_copy.release();
diff --git a/runtime/openjdkjvmti/transform.cc b/runtime/openjdkjvmti/transform.cc
index fa2983c..7bb5205 100644
--- a/runtime/openjdkjvmti/transform.cc
+++ b/runtime/openjdkjvmti/transform.cc
@@ -33,6 +33,7 @@
#include "class_linker.h"
#include "dex_file.h"
+#include "dex_file_types.h"
#include "gc_root-inl.h"
#include "globals.h"
#include "jni_env_ext-inl.h"
@@ -108,10 +109,10 @@
// Find the code_item for the method then find the dex_method_index and dex_code_item_offset to
// set.
const art::DexFile::StringId* new_name_id = dex_file->FindStringId(method.GetName());
- uint16_t method_return_idx =
+ art::dex::TypeIndex method_return_idx =
dex_file->GetIndexForTypeId(*dex_file->FindTypeId(method.GetReturnTypeDescriptor()));
const auto* old_type_list = method.GetParameterTypeList();
- std::vector<uint16_t> new_type_list;
+ std::vector<art::dex::TypeIndex> new_type_list;
for (uint32_t i = 0; old_type_list != nullptr && i < old_type_list->Size(); i++) {
new_type_list.push_back(
dex_file->GetIndexForTypeId(
diff --git a/runtime/reflection.cc b/runtime/reflection.cc
index 3128380..8446b52 100644
--- a/runtime/reflection.cc
+++ b/runtime/reflection.cc
@@ -363,7 +363,7 @@
Thread* const self = Thread::Current();
PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
for (uint32_t i = 0; i < num_params; i++) {
- uint16_t type_idx = params->GetTypeItem(i).type_idx_;
+ dex::TypeIndex type_idx = params->GetTypeItem(i).type_idx_;
ObjPtr<mirror::Class> param_type(m->GetClassFromTypeIndex(type_idx,
true /* resolve*/,
pointer_size));
diff --git a/runtime/type_lookup_table.cc b/runtime/type_lookup_table.cc
index 56e9262..16cd722 100644
--- a/runtime/type_lookup_table.cc
+++ b/runtime/type_lookup_table.cc
@@ -50,17 +50,19 @@
return num_class_defs != 0u && num_class_defs <= std::numeric_limits<uint16_t>::max();
}
-TypeLookupTable* TypeLookupTable::Create(const DexFile& dex_file, uint8_t* storage) {
+std::unique_ptr<TypeLookupTable> TypeLookupTable::Create(const DexFile& dex_file,
+ uint8_t* storage) {
const uint32_t num_class_defs = dex_file.NumClassDefs();
- return SupportedSize(num_class_defs)
+ return std::unique_ptr<TypeLookupTable>(SupportedSize(num_class_defs)
? new TypeLookupTable(dex_file, storage)
- : nullptr;
+ : nullptr);
}
-TypeLookupTable* TypeLookupTable::Open(const uint8_t* dex_file_pointer,
- const uint8_t* raw_data,
- uint32_t num_class_defs) {
- return new TypeLookupTable(dex_file_pointer, raw_data, num_class_defs);
+std::unique_ptr<TypeLookupTable> TypeLookupTable::Open(const uint8_t* dex_file_pointer,
+ const uint8_t* raw_data,
+ uint32_t num_class_defs) {
+ return std::unique_ptr<TypeLookupTable>(
+ new TypeLookupTable(dex_file_pointer, raw_data, num_class_defs));
}
TypeLookupTable::TypeLookupTable(const DexFile& dex_file, uint8_t* storage)
diff --git a/runtime/type_lookup_table.h b/runtime/type_lookup_table.h
index 9595743..3f6f76f 100644
--- a/runtime/type_lookup_table.h
+++ b/runtime/type_lookup_table.h
@@ -60,13 +60,14 @@
}
// Method creates lookup table for dex file
- static TypeLookupTable* Create(const DexFile& dex_file, uint8_t* storage = nullptr);
+ static std::unique_ptr<TypeLookupTable> Create(const DexFile& dex_file,
+ uint8_t* storage = nullptr);
// Method opens lookup table from binary data. Lookups will traverse strings and other
// data contained in dex_file as well. Lookup table does not own raw_data or dex_file.
- static TypeLookupTable* Open(const uint8_t* dex_file_pointer,
- const uint8_t* raw_data,
- uint32_t num_class_defs);
+ static std::unique_ptr<TypeLookupTable> Open(const uint8_t* dex_file_pointer,
+ const uint8_t* raw_data,
+ uint32_t num_class_defs);
// Method returns pointer to binary data of lookup table. Used by the oat writer.
const uint8_t* RawData() const {
diff --git a/runtime/utils/dex_cache_arrays_layout-inl.h b/runtime/utils/dex_cache_arrays_layout-inl.h
index c7875b5..bd1b044 100644
--- a/runtime/utils/dex_cache_arrays_layout-inl.h
+++ b/runtime/utils/dex_cache_arrays_layout-inl.h
@@ -65,8 +65,8 @@
return PointerSize::k32;
}
-inline size_t DexCacheArraysLayout::TypeOffset(uint32_t type_idx) const {
- return types_offset_ + ElementOffset(GcRootAsPointerSize<mirror::Class>(), type_idx);
+inline size_t DexCacheArraysLayout::TypeOffset(dex::TypeIndex type_idx) const {
+ return types_offset_ + ElementOffset(GcRootAsPointerSize<mirror::Class>(), type_idx.index_);
}
inline size_t DexCacheArraysLayout::TypesSize(size_t num_elements) const {
diff --git a/runtime/utils/dex_cache_arrays_layout.h b/runtime/utils/dex_cache_arrays_layout.h
index ae3bfab..7d4b23a 100644
--- a/runtime/utils/dex_cache_arrays_layout.h
+++ b/runtime/utils/dex_cache_arrays_layout.h
@@ -18,6 +18,7 @@
#define ART_RUNTIME_UTILS_DEX_CACHE_ARRAYS_LAYOUT_H_
#include "dex_file.h"
+#include "dex_file_types.h"
namespace art {
@@ -59,7 +60,7 @@
return types_offset_;
}
- size_t TypeOffset(uint32_t type_idx) const;
+ size_t TypeOffset(dex::TypeIndex type_idx) const;
size_t TypesSize(size_t num_elements) const;
diff --git a/runtime/verifier/method_verifier-inl.h b/runtime/verifier/method_verifier-inl.h
index def61db..363bd8f 100644
--- a/runtime/verifier/method_verifier-inl.h
+++ b/runtime/verifier/method_verifier-inl.h
@@ -74,7 +74,7 @@
return !failure_messages_.empty();
}
-inline const RegType& MethodVerifier::ResolveCheckedClass(uint32_t class_idx) {
+inline const RegType& MethodVerifier::ResolveCheckedClass(dex::TypeIndex class_idx) {
DCHECK(!HasFailures());
const RegType& result = ResolveClassAndCheckAccess(class_idx);
DCHECK(!HasFailures());
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index ed24611..7137db8 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -1072,7 +1072,7 @@
GetInstructionFlags(dex_pc).SetBranchTarget();
// Ensure exception types are resolved so that they don't need resolution to be delivered,
// unresolved exception types will be ignored by exception delivery
- if (iterator.GetHandlerTypeIndex() != DexFile::kDexNoIndex16) {
+ if (iterator.GetHandlerTypeIndex().IsValid()) {
mirror::Class* exception_type = linker->ResolveType(*dex_file_,
iterator.GetHandlerTypeIndex(),
dex_cache_, class_loader_);
@@ -1155,13 +1155,13 @@
result = result && CheckMethodIndex(inst->VRegB());
break;
case Instruction::kVerifyRegBNewInstance:
- result = result && CheckNewInstance(inst->VRegB());
+ result = result && CheckNewInstance(dex::TypeIndex(inst->VRegB()));
break;
case Instruction::kVerifyRegBString:
result = result && CheckStringIndex(inst->VRegB());
break;
case Instruction::kVerifyRegBType:
- result = result && CheckTypeIndex(inst->VRegB());
+ result = result && CheckTypeIndex(dex::TypeIndex(inst->VRegB()));
break;
case Instruction::kVerifyRegBWide:
result = result && CheckWideRegisterIndex(inst->VRegB());
@@ -1175,10 +1175,10 @@
result = result && CheckFieldIndex(inst->VRegC());
break;
case Instruction::kVerifyRegCNewArray:
- result = result && CheckNewArray(inst->VRegC());
+ result = result && CheckNewArray(dex::TypeIndex(inst->VRegC()));
break;
case Instruction::kVerifyRegCType:
- result = result && CheckTypeIndex(inst->VRegC());
+ result = result && CheckTypeIndex(dex::TypeIndex(inst->VRegC()));
break;
case Instruction::kVerifyRegCWide:
result = result && CheckWideRegisterIndex(inst->VRegC());
@@ -1270,9 +1270,9 @@
return true;
}
-inline bool MethodVerifier::CheckNewInstance(uint32_t idx) {
- if (idx >= dex_file_->GetHeader().type_ids_size_) {
- Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "bad type index " << idx << " (max "
+inline bool MethodVerifier::CheckNewInstance(dex::TypeIndex idx) {
+ if (idx.index_ >= dex_file_->GetHeader().type_ids_size_) {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "bad type index " << idx.index_ << " (max "
<< dex_file_->GetHeader().type_ids_size_ << ")";
return false;
}
@@ -1298,18 +1298,18 @@
return true;
}
-inline bool MethodVerifier::CheckTypeIndex(uint32_t idx) {
- if (idx >= dex_file_->GetHeader().type_ids_size_) {
- Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "bad type index " << idx << " (max "
+inline bool MethodVerifier::CheckTypeIndex(dex::TypeIndex idx) {
+ if (idx.index_ >= dex_file_->GetHeader().type_ids_size_) {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "bad type index " << idx.index_ << " (max "
<< dex_file_->GetHeader().type_ids_size_ << ")";
return false;
}
return true;
}
-bool MethodVerifier::CheckNewArray(uint32_t idx) {
- if (idx >= dex_file_->GetHeader().type_ids_size_) {
- Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "bad type index " << idx << " (max "
+bool MethodVerifier::CheckNewArray(dex::TypeIndex idx) {
+ if (idx.index_ >= dex_file_->GetHeader().type_ids_size_) {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "bad type index " << idx.index_ << " (max "
<< dex_file_->GetHeader().type_ids_size_ << ")";
return false;
}
@@ -1945,7 +1945,7 @@
// Returns the index of the first final instance field of the given class, or kDexNoIndex if there
// is no such field.
-static uint32_t GetFirstFinalInstanceFieldIndex(const DexFile& dex_file, uint16_t type_idx) {
+static uint32_t GetFirstFinalInstanceFieldIndex(const DexFile& dex_file, dex::TypeIndex type_idx) {
const DexFile::ClassDef* class_def = dex_file.FindClassDef(type_idx);
DCHECK(class_def != nullptr);
const uint8_t* class_data = dex_file.GetClassData(*class_def);
@@ -2293,7 +2293,7 @@
case Instruction::CONST_CLASS: {
// Get type from instruction if unresolved then we need an access check
// TODO: check Compiler::CanAccessTypeWithoutChecks returns false when res_type is unresolved
- const RegType& res_type = ResolveClassAndCheckAccess(inst->VRegB_21c());
+ const RegType& res_type = ResolveClassAndCheckAccess(dex::TypeIndex(inst->VRegB_21c()));
// Register holds class, ie its type is class, on error it will hold Conflict.
work_line_->SetRegisterType<LockOp::kClear>(
this, inst->VRegA_21c(), res_type.IsConflict() ? res_type
@@ -2363,7 +2363,7 @@
* dec_insn.vA when branching to a handler.
*/
const bool is_checkcast = (inst->Opcode() == Instruction::CHECK_CAST);
- const uint32_t type_idx = (is_checkcast) ? inst->VRegB_21c() : inst->VRegC_22c();
+ const dex::TypeIndex type_idx((is_checkcast) ? inst->VRegB_21c() : inst->VRegC_22c());
const RegType& res_type = ResolveClassAndCheckAccess(type_idx);
if (res_type.IsConflict()) {
// If this is a primitive type, fail HARD.
@@ -2433,7 +2433,7 @@
break;
}
case Instruction::NEW_INSTANCE: {
- const RegType& res_type = ResolveClassAndCheckAccess(inst->VRegB_21c());
+ const RegType& res_type = ResolveClassAndCheckAccess(dex::TypeIndex(inst->VRegB_21c()));
if (res_type.IsConflict()) {
DCHECK_NE(failures_.size(), 0U);
break; // bad class
@@ -2645,7 +2645,8 @@
// ensure that subsequent merges don't lose type information - such as becoming an
// interface from a class that would lose information relevant to field checks.
const RegType& orig_type = work_line_->GetRegisterType(this, instance_of_inst->VRegB_22c());
- const RegType& cast_type = ResolveClassAndCheckAccess(instance_of_inst->VRegC_22c());
+ const RegType& cast_type = ResolveClassAndCheckAccess(
+ dex::TypeIndex(instance_of_inst->VRegC_22c()));
if (!orig_type.Equals(cast_type) &&
!cast_type.IsUnresolvedTypes() && !orig_type.IsUnresolvedTypes() &&
@@ -2883,7 +2884,8 @@
if (return_type == nullptr) {
uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx);
- uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
+ dex::TypeIndex return_type_idx =
+ dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
const char* descriptor = dex_file_->StringByTypeIdx(return_type_idx);
return_type = ®_types_.FromDescriptor(GetClassLoader(), descriptor, false);
}
@@ -2906,7 +2908,8 @@
uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx);
is_constructor = strcmp("<init>", dex_file_->StringDataByIdx(method_id.name_idx_)) == 0;
- uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
+ dex::TypeIndex return_type_idx =
+ dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
return_type_descriptor = dex_file_->StringByTypeIdx(return_type_idx);
} else {
is_constructor = called_method->IsConstructor();
@@ -2982,7 +2985,8 @@
if (called_method == nullptr) {
uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx);
- uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
+ dex::TypeIndex return_type_idx =
+ dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
descriptor = dex_file_->StringByTypeIdx(return_type_idx);
} else {
descriptor = called_method->GetReturnTypeDescriptor();
@@ -3036,7 +3040,8 @@
if (abs_method == nullptr) {
uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx);
- uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
+ dex::TypeIndex return_type_idx =
+ dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
descriptor = dex_file_->StringByTypeIdx(return_type_idx);
} else {
descriptor = abs_method->GetReturnTypeDescriptor();
@@ -3500,8 +3505,8 @@
ClassLinker* linker = Runtime::Current()->GetClassLinker();
for (; iterator.HasNext(); iterator.Next()) {
- uint16_t handler_type_idx = iterator.GetHandlerTypeIndex();
- if (handler_type_idx == DexFile::kDexNoIndex16) {
+ dex::TypeIndex handler_type_idx = iterator.GetHandlerTypeIndex();
+ if (!handler_type_idx.IsValid()) {
has_catch_all_handler = true;
} else {
// It is also a catch-all if it is java.lang.Throwable.
@@ -3628,7 +3633,7 @@
return klass->IsInstantiable() || klass->IsPrimitive();
}
-const RegType& MethodVerifier::ResolveClassAndCheckAccess(uint32_t class_idx) {
+const RegType& MethodVerifier::ResolveClassAndCheckAccess(dex::TypeIndex class_idx) {
mirror::Class* klass = dex_cache_->GetResolvedType(class_idx);
const RegType* result = nullptr;
if (klass != nullptr) {
@@ -3684,7 +3689,7 @@
CatchHandlerIterator iterator(handlers_ptr);
for (; iterator.HasNext(); iterator.Next()) {
if (iterator.GetHandlerAddress() == (uint32_t) work_insn_idx_) {
- if (iterator.GetHandlerTypeIndex() == DexFile::kDexNoIndex16) {
+ if (!iterator.GetHandlerTypeIndex().IsValid()) {
common_super = ®_types_.JavaLangThrowable(false);
} else {
const RegType& exception = ResolveClassAndCheckAccess(iterator.GetHandlerTypeIndex());
@@ -3941,7 +3946,7 @@
klass->CannotBeAssignedFromOtherTypes());
} else {
const uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
- const uint16_t class_idx = dex_file_->GetMethodId(method_idx).class_idx_;
+ const dex::TypeIndex class_idx = dex_file_->GetMethodId(method_idx).class_idx_;
res_method_class = ®_types_.FromDescriptor(
GetClassLoader(),
dex_file_->StringByTypeIdx(class_idx),
@@ -4078,7 +4083,7 @@
// If we're using invoke-super(method), make sure that the executing method's class' superclass
// has a vtable entry for the target method. Or the target is on a interface.
if (method_type == METHOD_SUPER) {
- uint16_t class_idx = dex_file_->GetMethodId(method_idx).class_idx_;
+ dex::TypeIndex class_idx = dex_file_->GetMethodId(method_idx).class_idx_;
const RegType& reference_type = reg_types_.FromDescriptor(
GetClassLoader(),
dex_file_->StringByTypeIdx(class_idx),
@@ -4287,16 +4292,16 @@
}
void MethodVerifier::VerifyNewArray(const Instruction* inst, bool is_filled, bool is_range) {
- uint32_t type_idx;
+ dex::TypeIndex type_idx;
if (!is_filled) {
DCHECK_EQ(inst->Opcode(), Instruction::NEW_ARRAY);
- type_idx = inst->VRegC_22c();
+ type_idx = dex::TypeIndex(inst->VRegC_22c());
} else if (!is_range) {
DCHECK_EQ(inst->Opcode(), Instruction::FILLED_NEW_ARRAY);
- type_idx = inst->VRegB_35c();
+ type_idx = dex::TypeIndex(inst->VRegB_35c());
} else {
DCHECK_EQ(inst->Opcode(), Instruction::FILLED_NEW_ARRAY_RANGE);
- type_idx = inst->VRegB_3rc();
+ type_idx = dex::TypeIndex(inst->VRegB_3rc());
}
const RegType& res_type = ResolveClassAndCheckAccess(type_idx);
if (res_type.IsConflict()) { // bad class
@@ -5011,7 +5016,7 @@
if (return_type_ == nullptr) {
const DexFile::MethodId& method_id = dex_file_->GetMethodId(dex_method_idx_);
const DexFile::ProtoId& proto_id = dex_file_->GetMethodPrototype(method_id);
- uint16_t return_type_idx = proto_id.return_type_idx_;
+ dex::TypeIndex return_type_idx = proto_id.return_type_idx_;
const char* descriptor = dex_file_->GetTypeDescriptor(dex_file_->GetTypeId(return_type_idx));
return_type_ = ®_types_.FromDescriptor(GetClassLoader(), descriptor, false);
}
diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h
index c6ce583..f3faecd 100644
--- a/runtime/verifier/method_verifier.h
+++ b/runtime/verifier/method_verifier.h
@@ -27,6 +27,7 @@
#include "base/stl_util.h"
#include "base/value_object.h"
#include "dex_file.h"
+#include "dex_file_types.h"
#include "handle.h"
#include "instruction_flags.h"
#include "method_reference.h"
@@ -261,7 +262,7 @@
return have_any_pending_runtime_throw_failure_;
}
- const RegType& ResolveCheckedClass(uint32_t class_idx)
+ const RegType& ResolveCheckedClass(dex::TypeIndex class_idx)
REQUIRES_SHARED(Locks::mutator_lock_);
// Returns the method of a quick invoke or null if it cannot be found.
ArtMethod* GetQuickInvokedMethod(const Instruction* inst, RegisterLine* reg_line,
@@ -471,18 +472,18 @@
// Perform static checks on a "new-instance" instruction. Specifically, make sure the class
// reference isn't for an array class.
- bool CheckNewInstance(uint32_t idx);
+ bool CheckNewInstance(dex::TypeIndex idx);
/* Ensure that the string index is in the valid range. */
bool CheckStringIndex(uint32_t idx);
// Perform static checks on an instruction that takes a class constant. Ensure that the class
// index is in the valid range.
- bool CheckTypeIndex(uint32_t idx);
+ bool CheckTypeIndex(dex::TypeIndex idx);
// Perform static checks on a "new-array" instruction. Specifically, make sure they aren't
// creating an array of arrays that causes the number of dimensions to exceed 255.
- bool CheckNewArray(uint32_t idx);
+ bool CheckNewArray(dex::TypeIndex idx);
// Verify an array data table. "cur_offset" is the offset of the fill-array-data instruction.
bool CheckArrayData(uint32_t cur_offset);
@@ -625,7 +626,7 @@
// Resolves a class based on an index and performs access checks to ensure the referrer can
// access the resolved class.
- const RegType& ResolveClassAndCheckAccess(uint32_t class_idx)
+ const RegType& ResolveClassAndCheckAccess(dex::TypeIndex class_idx)
REQUIRES_SHARED(Locks::mutator_lock_);
/*
diff --git a/runtime/verifier/verifier_deps.cc b/runtime/verifier/verifier_deps.cc
index c395612d7..a65e82b 100644
--- a/runtime/verifier/verifier_deps.cc
+++ b/runtime/verifier/verifier_deps.cc
@@ -16,6 +16,8 @@
#include "verifier_deps.h"
+#include <cstring>
+
#include "compiler_callbacks.h"
#include "leb128.h"
#include "mirror/class-inl.h"
@@ -56,17 +58,80 @@
}
}
-template <typename T>
-uint32_t VerifierDeps::GetDeclaringClassStringId(const DexFile& dex_file, T* element) {
+uint32_t VerifierDeps::GetClassDescriptorStringId(const DexFile& dex_file,
+ ObjPtr<mirror::Class> klass) {
+ DCHECK(klass != nullptr);
+ ObjPtr<mirror::DexCache> dex_cache = klass->GetDexCache();
+ // Array classes do not have a dex cache.
+ if (!klass->IsArrayClass() && !klass->IsProxyClass()) {
+ DCHECK(dex_cache != nullptr) << klass->PrettyClass();
+ if (dex_cache->GetDexFile() == &dex_file) {
+ // FindStringId is slow, try to go through the class def if we have one.
+ const DexFile::ClassDef* class_def = klass->GetClassDef();
+ DCHECK(class_def != nullptr) << klass->PrettyClass();
+ std::string temp;
+ const DexFile::TypeId& type_id = dex_file.GetTypeId(class_def->class_idx_);
+ DCHECK_EQ(GetIdFromString(dex_file, klass->GetDescriptor(&temp)), type_id.descriptor_idx_);
+ return type_id.descriptor_idx_;
+ }
+ }
+ std::string temp;
+ return GetIdFromString(dex_file, klass->GetDescriptor(&temp));
+}
+
+// Try to find the string descriptor of the class. type_idx is a best guess of a matching string id.
+static uint32_t TryGetClassDescriptorStringId(const DexFile& dex_file,
+ dex::TypeIndex type_idx,
+ ObjPtr<mirror::Class> klass)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (!klass->IsArrayClass()) {
+ const DexFile::TypeId& type_id = dex_file.GetTypeId(type_idx);
+ const DexFile& klass_dex = klass->GetDexFile();
+ const DexFile::TypeId& klass_type_id = klass_dex.GetTypeId(klass->GetClassDef()->class_idx_);
+ if (strcmp(dex_file.GetTypeDescriptor(type_id),
+ klass_dex.GetTypeDescriptor(klass_type_id)) == 0) {
+ return type_id.descriptor_idx_;
+ }
+ }
+ return DexFile::kDexNoIndex;
+}
+
+uint32_t VerifierDeps::GetMethodDeclaringClassStringId(const DexFile& dex_file,
+ uint32_t dex_method_index,
+ ArtMethod* method) {
static_assert(kAccJavaFlagsMask == 0xFFFF, "Unexpected value of a constant");
- if (element == nullptr) {
+ if (method == nullptr) {
return VerifierDeps::kUnresolvedMarker;
- } else {
- std::string temp;
- uint32_t string_id = GetIdFromString(
- dex_file, element->GetDeclaringClass()->GetDescriptor(&temp));
+ }
+ const uint32_t string_id = TryGetClassDescriptorStringId(
+ dex_file,
+ dex_file.GetMethodId(dex_method_index).class_idx_,
+ method->GetDeclaringClass());
+ if (string_id != DexFile::kDexNoIndex) {
+ // Got lucky using the original dex file, return based on the input dex file.
+ DCHECK_EQ(GetClassDescriptorStringId(dex_file, method->GetDeclaringClass()), string_id);
return string_id;
}
+ return GetClassDescriptorStringId(dex_file, method->GetDeclaringClass());
+}
+
+uint32_t VerifierDeps::GetFieldDeclaringClassStringId(const DexFile& dex_file,
+ uint32_t dex_field_idx,
+ ArtField* field) {
+ static_assert(kAccJavaFlagsMask == 0xFFFF, "Unexpected value of a constant");
+ if (field == nullptr) {
+ return VerifierDeps::kUnresolvedMarker;
+ }
+ const uint32_t string_id = TryGetClassDescriptorStringId(
+ dex_file,
+ dex_file.GetFieldId(dex_field_idx).class_idx_,
+ field->GetDeclaringClass());
+ if (string_id != DexFile::kDexNoIndex) {
+ // Got lucky using the original dex file, return based on the input dex file.
+ DCHECK_EQ(GetClassDescriptorStringId(dex_file, field->GetDeclaringClass()), string_id);
+ return string_id;
+ }
+ return GetClassDescriptorStringId(dex_file, field->GetDeclaringClass());
}
uint32_t VerifierDeps::GetIdFromString(const DexFile& dex_file, const std::string& str) {
@@ -137,7 +202,7 @@
}
void VerifierDeps::AddClassResolution(const DexFile& dex_file,
- uint16_t type_idx,
+ dex::TypeIndex type_idx,
mirror::Class* klass) {
DexFileDeps* dex_deps = GetDexFileDeps(dex_file);
if (dex_deps == nullptr) {
@@ -171,8 +236,11 @@
}
MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
- dex_deps->fields_.emplace(FieldResolution(
- field_idx, GetAccessFlags(field), GetDeclaringClassStringId(dex_file, field)));
+ dex_deps->fields_.emplace(FieldResolution(field_idx,
+ GetAccessFlags(field),
+ GetFieldDeclaringClassStringId(dex_file,
+ field_idx,
+ field)));
}
void VerifierDeps::AddMethodResolution(const DexFile& dex_file,
@@ -194,7 +262,7 @@
MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
MethodResolution method_tuple(method_idx,
GetAccessFlags(method),
- GetDeclaringClassStringId(dex_file, method));
+ GetMethodDeclaringClassStringId(dex_file, method_idx, method));
if (resolution_kind == kDirectMethodResolution) {
dex_deps->direct_methods_.emplace(method_tuple);
} else if (resolution_kind == kVirtualMethodResolution) {
@@ -263,12 +331,8 @@
MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
// Get string IDs for both descriptors and store in the appropriate set.
-
- std::string temp1, temp2;
- std::string destination_desc(destination->GetDescriptor(&temp1));
- std::string source_desc(source->GetDescriptor(&temp2));
- uint32_t destination_id = GetIdFromString(dex_file, destination_desc);
- uint32_t source_id = GetIdFromString(dex_file, source_desc);
+ uint32_t destination_id = GetClassDescriptorStringId(dex_file, destination);
+ uint32_t source_id = GetClassDescriptorStringId(dex_file, source);
if (is_assignable) {
dex_deps->assignable_types_.emplace(TypeAssignability(destination_id, source_id));
@@ -286,7 +350,7 @@
}
void VerifierDeps::MaybeRecordVerificationStatus(const DexFile& dex_file,
- uint16_t type_idx,
+ dex::TypeIndex type_idx,
MethodVerifier::FailureKind failure_kind) {
if (failure_kind == MethodVerifier::kNoFailure) {
// We only record classes that did not fully verify at compile time.
@@ -302,7 +366,7 @@
}
void VerifierDeps::MaybeRecordClassResolution(const DexFile& dex_file,
- uint16_t type_idx,
+ dex::TypeIndex type_idx,
mirror::Class* klass) {
VerifierDeps* singleton = GetVerifierDepsSingleton();
if (singleton != nullptr) {
@@ -340,36 +404,62 @@
}
}
+namespace {
+
static inline uint32_t DecodeUint32WithOverflowCheck(const uint8_t** in, const uint8_t* end) {
CHECK_LT(*in, end);
return DecodeUnsignedLeb128(in);
}
+template<typename T> inline uint32_t Encode(T in);
+
+template<> inline uint32_t Encode<uint16_t>(uint16_t in) {
+ return in;
+}
+template<> inline uint32_t Encode<uint32_t>(uint32_t in) {
+ return in;
+}
+template<> inline uint32_t Encode<dex::TypeIndex>(dex::TypeIndex in) {
+ return in.index_;
+}
+
+template<typename T> inline T Decode(uint32_t in);
+
+template<> inline uint16_t Decode<uint16_t>(uint32_t in) {
+ return dchecked_integral_cast<uint16_t>(in);
+}
+template<> inline uint32_t Decode<uint32_t>(uint32_t in) {
+ return in;
+}
+template<> inline dex::TypeIndex Decode<dex::TypeIndex>(uint32_t in) {
+ return dex::TypeIndex(in);
+}
+
template<typename T1, typename T2>
static inline void EncodeTuple(std::vector<uint8_t>* out, const std::tuple<T1, T2>& t) {
- EncodeUnsignedLeb128(out, std::get<0>(t));
- EncodeUnsignedLeb128(out, std::get<1>(t));
+ EncodeUnsignedLeb128(out, Encode(std::get<0>(t)));
+ EncodeUnsignedLeb128(out, Encode(std::get<1>(t)));
}
template<typename T1, typename T2>
static inline void DecodeTuple(const uint8_t** in, const uint8_t* end, std::tuple<T1, T2>* t) {
- T1 v1 = static_cast<T1>(DecodeUint32WithOverflowCheck(in, end));
- T2 v2 = static_cast<T2>(DecodeUint32WithOverflowCheck(in, end));
+ T1 v1 = Decode<T1>(DecodeUint32WithOverflowCheck(in, end));
+ T2 v2 = Decode<T2>(DecodeUint32WithOverflowCheck(in, end));
*t = std::make_tuple(v1, v2);
}
template<typename T1, typename T2, typename T3>
static inline void EncodeTuple(std::vector<uint8_t>* out, const std::tuple<T1, T2, T3>& t) {
- EncodeUnsignedLeb128(out, std::get<0>(t));
- EncodeUnsignedLeb128(out, std::get<1>(t));
- EncodeUnsignedLeb128(out, std::get<2>(t));
+ EncodeUnsignedLeb128(out, Encode(std::get<0>(t)));
+ EncodeUnsignedLeb128(out, Encode(std::get<1>(t)));
+ EncodeUnsignedLeb128(out, Encode(std::get<2>(t)));
}
template<typename T1, typename T2, typename T3>
static inline void DecodeTuple(const uint8_t** in, const uint8_t* end, std::tuple<T1, T2, T3>* t) {
- T1 v1 = static_cast<T1>(DecodeUint32WithOverflowCheck(in, end));
- T2 v2 = static_cast<T2>(DecodeUint32WithOverflowCheck(in, end));
- T3 v3 = static_cast<T2>(DecodeUint32WithOverflowCheck(in, end));
+ T1 v1 = Decode<T1>(DecodeUint32WithOverflowCheck(in, end));
+ T2 v2 = Decode<T2>(DecodeUint32WithOverflowCheck(in, end));
+ T3 v3 = Decode<T2>(DecodeUint32WithOverflowCheck(in, end));
*t = std::make_tuple(v1, v2, v3);
}
@@ -381,11 +471,12 @@
}
}
+template <typename T>
static inline void EncodeUint16Vector(std::vector<uint8_t>* out,
- const std::vector<uint16_t>& vector) {
+ const std::vector<T>& vector) {
EncodeUnsignedLeb128(out, vector.size());
- for (uint16_t entry : vector) {
- EncodeUnsignedLeb128(out, entry);
+ for (const T& entry : vector) {
+ EncodeUnsignedLeb128(out, Encode(entry));
}
}
@@ -400,14 +491,16 @@
}
}
+template<typename T>
static inline void DecodeUint16Vector(const uint8_t** in,
const uint8_t* end,
- std::vector<uint16_t>* vector) {
+ std::vector<T>* vector) {
DCHECK(vector->empty());
size_t num_entries = DecodeUint32WithOverflowCheck(in, end);
vector->reserve(num_entries);
for (size_t i = 0; i < num_entries; ++i) {
- vector->push_back(dchecked_integral_cast<uint16_t>(DecodeUint32WithOverflowCheck(in, end)));
+ vector->push_back(
+ Decode<T>(dchecked_integral_cast<uint16_t>(DecodeUint32WithOverflowCheck(in, end))));
}
}
@@ -436,6 +529,8 @@
}
}
+} // namespace
+
void VerifierDeps::Encode(const std::vector<const DexFile*>& dex_files,
std::vector<uint8_t>* buffer) const {
MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
@@ -599,7 +694,7 @@
}
}
- for (uint16_t type_index : dep.second->unverified_classes_) {
+ for (dex::TypeIndex type_index : dep.second->unverified_classes_) {
vios->Stream()
<< dex_file.StringByTypeIdx(type_index)
<< " is expected to be verified at runtime\n";
diff --git a/runtime/verifier/verifier_deps.h b/runtime/verifier/verifier_deps.h
index 7b419d4..e35af41 100644
--- a/runtime/verifier/verifier_deps.h
+++ b/runtime/verifier/verifier_deps.h
@@ -57,14 +57,14 @@
// Record the verification status of the class at `type_idx`.
static void MaybeRecordVerificationStatus(const DexFile& dex_file,
- uint16_t type_idx,
+ dex::TypeIndex type_idx,
MethodVerifier::FailureKind failure_kind)
REQUIRES(!Locks::verifier_deps_lock_);
// Record the outcome `klass` of resolving type `type_idx` from `dex_file`.
// If `klass` is null, the class is assumed unresolved.
static void MaybeRecordClassResolution(const DexFile& dex_file,
- uint16_t type_idx,
+ dex::TypeIndex type_idx,
mirror::Class* klass)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Locks::verifier_deps_lock_);
@@ -116,7 +116,7 @@
// NO_THREAD_SAFETY_ANALSYS, as this is queried when the VerifierDeps are
// fully created.
- const std::vector<uint16_t>& GetUnverifiedClasses(const DexFile& dex_file) const
+ const std::vector<dex::TypeIndex>& GetUnverifiedClasses(const DexFile& dex_file) const
NO_THREAD_SAFETY_ANALYSIS {
return GetDexFileDeps(dex_file)->unverified_classes_;
}
@@ -124,15 +124,15 @@
private:
static constexpr uint16_t kUnresolvedMarker = static_cast<uint16_t>(-1);
- using ClassResolutionBase = std::tuple<uint32_t, uint16_t>;
+ using ClassResolutionBase = std::tuple<dex::TypeIndex, uint16_t>;
struct ClassResolution : public ClassResolutionBase {
ClassResolution() = default;
ClassResolution(const ClassResolution&) = default;
- ClassResolution(uint32_t type_idx, uint16_t access_flags)
+ ClassResolution(dex::TypeIndex type_idx, uint16_t access_flags)
: ClassResolutionBase(type_idx, access_flags) {}
bool IsResolved() const { return GetAccessFlags() != kUnresolvedMarker; }
- uint32_t GetDexTypeIndex() const { return std::get<0>(*this); }
+ dex::TypeIndex GetDexTypeIndex() const { return std::get<0>(*this); }
uint16_t GetAccessFlags() const { return std::get<1>(*this); }
};
@@ -193,7 +193,7 @@
std::set<MethodResolution> interface_methods_;
// List of classes that were not fully verified in that dex file.
- std::vector<uint16_t> unverified_classes_;
+ std::vector<dex::TypeIndex> unverified_classes_;
bool Equals(const DexFileDeps& rhs) const;
};
@@ -232,13 +232,24 @@
// Returns a string ID of the descriptor of the declaring class of `element`,
// or `kUnresolvedMarker` if `element` is null.
- template <typename T>
- uint32_t GetDeclaringClassStringId(const DexFile& dex_file, T* element)
+ uint32_t GetMethodDeclaringClassStringId(const DexFile& dex_file,
+ uint32_t dex_method_idx,
+ ArtMethod* method)
+ REQUIRES_SHARED(Locks::mutator_lock_)
+ REQUIRES(Locks::verifier_deps_lock_);
+ uint32_t GetFieldDeclaringClassStringId(const DexFile& dex_file,
+ uint32_t dex_field_idx,
+ ArtField* field)
+ REQUIRES_SHARED(Locks::mutator_lock_)
+ REQUIRES(Locks::verifier_deps_lock_);
+
+ // Returns a string ID of the descriptor of the class.
+ uint32_t GetClassDescriptorStringId(const DexFile& dex_file, ObjPtr<mirror::Class> klass)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(Locks::verifier_deps_lock_);
void AddClassResolution(const DexFile& dex_file,
- uint16_t type_idx,
+ dex::TypeIndex type_idx,
mirror::Class* klass)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Locks::verifier_deps_lock_);
diff --git a/test/626-const-class-linking/clear_dex_cache_types.cc b/test/626-const-class-linking/clear_dex_cache_types.cc
new file mode 100644
index 0000000..ff33709
--- /dev/null
+++ b/test/626-const-class-linking/clear_dex_cache_types.cc
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "jni.h"
+#include "scoped_thread_state_change-inl.h"
+
+namespace art {
+
+namespace {
+
+extern "C" JNIEXPORT void JNICALL Java_Main_clearResolvedTypes(JNIEnv*, jclass, jclass cls) {
+ ScopedObjectAccess soa(Thread::Current());
+ mirror::DexCache* dex_cache = soa.Decode<mirror::Class>(cls)->GetDexCache();
+ for (size_t i = 0, num_types = dex_cache->NumResolvedTypes(); i != num_types; ++i) {
+ dex_cache->SetResolvedType(dex::TypeIndex(i), ObjPtr<mirror::Class>(nullptr));
+ }
+}
+
+} // namespace
+
+} // namespace art
diff --git a/test/626-const-class-linking/expected.txt b/test/626-const-class-linking/expected.txt
new file mode 100644
index 0000000..e83aa78
--- /dev/null
+++ b/test/626-const-class-linking/expected.txt
@@ -0,0 +1,62 @@
+JNI_OnLoad called
+first: Helper1 class loader: DelegatingLoader
+second: Test class loader: DefiningLoader
+first: Helper1 class loader: DelegatingLoader
+second: Test class loader: DefiningLoader
+testClearDexCache done
+first: Helper1 class loader: DelegatingLoader
+second: Test class loader: DefiningLoader
+first: Helper2 class loader: DelegatingLoader
+second: Test class loader: DefiningLoader
+testMultiDex done
+first: Helper1 class loader: RacyLoader
+second: Test class loader: DefiningLoader
+first: Helper1 class loader: RacyLoader
+second: Test class loader: DefiningLoader
+first: Helper1 class loader: RacyLoader
+second: Test class loader: DefiningLoader
+first: Helper1 class loader: RacyLoader
+second: Test class loader: DefiningLoader
+total: 4
+ throwables: 0
+ class_weaks: 4 (1 unique)
+testRacyLoader done
+first: Helper1 class loader: RacyLoader
+second: Test class loader: DefiningLoader
+first: Helper1 class loader: RacyLoader
+second: Test class loader: DefiningLoader
+first: Helper3 class loader: RacyLoader
+second: Test3 class loader: DefiningLoader
+first: Helper3 class loader: RacyLoader
+second: Test3 class loader: DefiningLoader
+total: 4
+ throwables: 0
+ class_weaks: 4 (2 unique)
+testRacyLoader2 done
+MisbehavingLoader loading Helper2 instead of Test
+java.lang.NoClassDefFoundError: Initiating class loader of type MisbehavingLoader returned class Helper2 instead of Test.
+testMisbehavingLoader done
+first: Helper1 class loader: RacyMisbehavingLoader
+second: Test class loader: DefiningLoader
+first: Helper1 class loader: RacyMisbehavingLoader
+second: Test class loader: DefiningLoader
+first: Helper1 class loader: RacyMisbehavingLoader
+second: Test class loader: DefiningLoader
+first: Helper1 class loader: RacyMisbehavingLoader
+second: Test class loader: DefiningLoader
+total: 4
+ throwables: 0
+ class_weaks: 4 (1 unique)
+testRacyMisbehavingLoader done
+first: Helper1 class loader: RacyMisbehavingLoader
+second: Test class loader: DefiningLoader
+first: Helper1 class loader: RacyMisbehavingLoader
+second: Test class loader: DefiningLoader
+first: Helper1 class loader: RacyMisbehavingLoader
+second: Test class loader: DefiningLoader
+first: Helper1 class loader: RacyMisbehavingLoader
+second: Test class loader: DefiningLoader
+total: 4
+ throwables: 0
+ class_weaks: 4 (1 unique)
+testRacyMisbehavingLoader2 done
diff --git a/test/626-const-class-linking/info.txt b/test/626-const-class-linking/info.txt
new file mode 100644
index 0000000..9c19a46
--- /dev/null
+++ b/test/626-const-class-linking/info.txt
@@ -0,0 +1,3 @@
+Test that once a const-class instruction is linked, it will keep referring
+to the same class even in the presence of custom class loaders even after
+clearing the dex cache type array.
diff --git a/test/626-const-class-linking/multidex.jpp b/test/626-const-class-linking/multidex.jpp
new file mode 100644
index 0000000..c7a6648
--- /dev/null
+++ b/test/626-const-class-linking/multidex.jpp
@@ -0,0 +1,27 @@
+ClassPair:
+ @@com.android.jack.annotations.ForceInMainDex
+ class ClassPair
+DefiningLoader:
+ @@com.android.jack.annotations.ForceInMainDex
+ class DefiningLoader
+DelegatingLoader:
+ @@com.android.jack.annotations.ForceInMainDex
+ class DelegatingLoader
+Helper1:
+ @@com.android.jack.annotations.ForceInMainDex
+ class Helper1
+Main:
+ @@com.android.jack.annotations.ForceInMainDex
+ class Main
+MisbehavingLoader:
+ @@com.android.jack.annotations.ForceInMainDex
+ class MisbehavingLoader
+RacyLoader:
+ @@com.android.jack.annotations.ForceInMainDex
+ class RacyLoader
+RacyMisbehavingHelper:
+ @@com.android.jack.annotations.ForceInMainDex
+ class RacyMisbehavingHelper
+RacyMisbehavingLoader:
+ @@com.android.jack.annotations.ForceInMainDex
+ class RacyMisbehavingLoader
diff --git a/test/626-const-class-linking/src-multidex/Helper2.java b/test/626-const-class-linking/src-multidex/Helper2.java
new file mode 100644
index 0000000..5bb31ee
--- /dev/null
+++ b/test/626-const-class-linking/src-multidex/Helper2.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Helper2 {
+ public static ClassPair get() {
+ Class<?> helper2_class = Helper2.class;
+ Class<?> test_class = Test.class;
+ return new ClassPair(helper2_class, test_class);
+ }
+}
diff --git a/test/626-const-class-linking/src-multidex/Helper3.java b/test/626-const-class-linking/src-multidex/Helper3.java
new file mode 100644
index 0000000..af996de
--- /dev/null
+++ b/test/626-const-class-linking/src-multidex/Helper3.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Helper3 {
+ public static ClassPair get() {
+ Class<?> helper3_class = Helper3.class;
+ Class<?> test3_class = Test3.class;
+ return new ClassPair(helper3_class, test3_class);
+ }
+}
diff --git a/test/626-const-class-linking/src-multidex/Test.java b/test/626-const-class-linking/src-multidex/Test.java
new file mode 100644
index 0000000..1b0cc2a
--- /dev/null
+++ b/test/626-const-class-linking/src-multidex/Test.java
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Test {
+}
diff --git a/test/626-const-class-linking/src-multidex/Test3.java b/test/626-const-class-linking/src-multidex/Test3.java
new file mode 100644
index 0000000..c4b134d
--- /dev/null
+++ b/test/626-const-class-linking/src-multidex/Test3.java
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Test3 {
+}
diff --git a/test/626-const-class-linking/src/ClassPair.java b/test/626-const-class-linking/src/ClassPair.java
new file mode 100644
index 0000000..b07036c
--- /dev/null
+++ b/test/626-const-class-linking/src/ClassPair.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class ClassPair {
+ public Class<?> first;
+ public Class<?> second;
+
+ public ClassPair(Class<?> first, Class<?> second) {
+ this.first = first;
+ this.second = second;
+ }
+
+ public void print() {
+ String first_loader_name = first.getClassLoader().getClass().getName();
+ System.out.println("first: " + first.getName() + " class loader: " + first_loader_name);
+ String second_loader_name = second.getClassLoader().getClass().getName();
+ System.out.println("second: " + second.getName() + " class loader: " + second_loader_name);
+ }
+}
diff --git a/test/626-const-class-linking/src/DefiningLoader.java b/test/626-const-class-linking/src/DefiningLoader.java
new file mode 100644
index 0000000..b17ab77
--- /dev/null
+++ b/test/626-const-class-linking/src/DefiningLoader.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.lang.reflect.InvocationTargetException;
+
+/**
+ * A class loader with atypical behavior: we try to load a private
+ * class implementation before asking the system or boot loader. This
+ * is used to create multiple classes with identical names in a single VM.
+ *
+ * If DexFile is available, we use that; if not, we assume we're not in
+ * Dalvik and instantiate the class with defineClass().
+ *
+ * The location of the DEX files and class data is dependent upon the
+ * test framework.
+ */
+public class DefiningLoader extends ClassLoader {
+ static {
+ // For JVM, register as parallel capable.
+ // Android treats all class loaders as parallel capable and makes this a no-op.
+ registerAsParallelCapable();
+ }
+
+ /* this is where the .class files live */
+ static final String CLASS_PATH1 = "classes/";
+ static final String CLASS_PATH2 = "classes2/";
+
+ /* this is the DEX/Jar file */
+ static final String DEX_FILE = System.getenv("DEX_LOCATION") + "/626-const-class-linking.jar";
+
+ /* on Dalvik, this is a DexFile; otherwise, it's null */
+ private Class<?> mDexClass;
+
+ private Object mDexFile;
+
+ /**
+ * Construct DefiningLoader, grabbing a reference to the DexFile class
+ * if we're running under Dalvik.
+ */
+ public DefiningLoader(ClassLoader parent) {
+ super(parent);
+
+ try {
+ mDexClass = parent.loadClass("dalvik.system.DexFile");
+ } catch (ClassNotFoundException cnfe) {
+ // ignore -- not running Dalvik
+ }
+ }
+
+ /**
+ * Finds the class with the specified binary name.
+ *
+ * We search for a file in CLASS_PATH or pull an entry from DEX_FILE.
+ * If we don't find a match, we throw an exception.
+ */
+ protected Class<?> findClass(String name) throws ClassNotFoundException
+ {
+ if (mDexClass != null) {
+ return findClassDalvik(name);
+ } else {
+ return findClassNonDalvik(name);
+ }
+ }
+
+ /**
+ * Finds the class with the specified binary name, from a DEX file.
+ */
+ private Class<?> findClassDalvik(String name)
+ throws ClassNotFoundException {
+
+ if (mDexFile == null) {
+ synchronized (DefiningLoader.class) {
+ Constructor<?> ctor;
+ /*
+ * Construct a DexFile object through reflection.
+ */
+ try {
+ ctor = mDexClass.getConstructor(String.class);
+ } catch (NoSuchMethodException nsme) {
+ throw new ClassNotFoundException("getConstructor failed",
+ nsme);
+ }
+
+ try {
+ mDexFile = ctor.newInstance(DEX_FILE);
+ } catch (InstantiationException ie) {
+ throw new ClassNotFoundException("newInstance failed", ie);
+ } catch (IllegalAccessException iae) {
+ throw new ClassNotFoundException("newInstance failed", iae);
+ } catch (InvocationTargetException ite) {
+ throw new ClassNotFoundException("newInstance failed", ite);
+ }
+ }
+ }
+
+ /*
+ * Call DexFile.loadClass(String, ClassLoader).
+ */
+ Method meth;
+
+ try {
+ meth = mDexClass.getMethod("loadClass", String.class, ClassLoader.class);
+ } catch (NoSuchMethodException nsme) {
+ throw new ClassNotFoundException("getMethod failed", nsme);
+ }
+
+ try {
+ meth.invoke(mDexFile, name, this);
+ } catch (IllegalAccessException iae) {
+ throw new ClassNotFoundException("loadClass failed", iae);
+ } catch (InvocationTargetException ite) {
+ throw new ClassNotFoundException("loadClass failed",
+ ite.getCause());
+ }
+
+ return null;
+ }
+
+ /**
+ * Finds the class with the specified binary name, from .class files.
+ */
+ private Class<?> findClassNonDalvik(String name)
+ throws ClassNotFoundException {
+
+ String[] pathNames = { CLASS_PATH1 + name + ".class", CLASS_PATH2 + name + ".class" };
+
+ String pathName = null;
+ RandomAccessFile raf = null;
+
+ for (String pn : pathNames) {
+ pathName = pn;
+ try {
+ //System.out.println("--- Defining: looking for " + pathName);
+ raf = new RandomAccessFile(new File(pathName), "r");
+ break;
+ } catch (FileNotFoundException fnfe) {
+ }
+ }
+ if (raf == null) {
+ throw new ClassNotFoundException("Not found: " + pathNames[0] + ":" + pathNames[1]);
+ }
+
+ /* read the entire file in */
+ byte[] fileData;
+ try {
+ fileData = new byte[(int) raf.length()];
+ raf.readFully(fileData);
+ } catch (IOException ioe) {
+ throw new ClassNotFoundException("Read error: " + pathName);
+ } finally {
+ try {
+ raf.close();
+ } catch (IOException ioe) {
+ // drop
+ }
+ }
+
+ /* create the class */
+ //System.out.println("--- Defining: defining " + name);
+ try {
+ return defineClass(name, fileData, 0, fileData.length);
+ } catch (Throwable th) {
+ throw new ClassNotFoundException("defineClass failed", th);
+ }
+ }
+
+ /**
+ * Load a class.
+ *
+ * Normally a class loader wouldn't override this, but we want our
+ * version of the class to take precedence over an already-loaded
+ * version.
+ *
+ * We still want the system classes (e.g. java.lang.Object) from the
+ * bootstrap class loader.
+ */
+ synchronized protected Class<?> loadClass(String name, boolean resolve)
+ throws ClassNotFoundException
+ {
+ Class<?> res;
+
+ /*
+ * 1. Invoke findLoadedClass(String) to check if the class has
+ * already been loaded.
+ *
+ * This doesn't change.
+ */
+ res = findLoadedClass(name);
+ if (res != null) {
+ // System.out.println("FancyLoader.loadClass: " + name + " already loaded");
+ if (resolve)
+ resolveClass(res);
+ return res;
+ }
+
+ /*
+ * 3. Invoke the findClass(String) method to find the class.
+ */
+ try {
+ res = findClass(name);
+ if (resolve)
+ resolveClass(res);
+ }
+ catch (ClassNotFoundException e) {
+ // we couldn't find it, so eat the exception and keep going
+ }
+
+ /*
+ * 2. Invoke the loadClass method on the parent class loader. If
+ * the parent loader is null the class loader built-in to the
+ * virtual machine is used, instead.
+ *
+ * (Since we're not in java.lang, we can't actually invoke the
+ * parent's loadClass() method, but we passed our parent to the
+ * super-class which can take care of it for us.)
+ */
+ res = super.loadClass(name, resolve); // returns class or throws
+ return res;
+ }
+}
diff --git a/test/626-const-class-linking/src/DelegatingLoader.java b/test/626-const-class-linking/src/DelegatingLoader.java
new file mode 100644
index 0000000..49955d4
--- /dev/null
+++ b/test/626-const-class-linking/src/DelegatingLoader.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class DelegatingLoader extends DefiningLoader {
+ private DefiningLoader defining_loader;
+
+ public DelegatingLoader(ClassLoader parent, DefiningLoader defining_loader) {
+ super(parent);
+ this.defining_loader = defining_loader;
+ }
+
+ public void resetDefiningLoader(DefiningLoader defining_loader) {
+ this.defining_loader = defining_loader;
+ }
+
+ protected Class<?> findClass(String name) throws ClassNotFoundException
+ {
+ if (name.equals("Test")) {
+ throw new Error("Unexpected DelegatingLoader.findClass(\"Test\")");
+ }
+ return super.findClass(name);
+ }
+
+ protected Class<?> loadClass(String name, boolean resolve)
+ throws ClassNotFoundException
+ {
+ if (name.equals("Test")) {
+ return defining_loader.loadClass(name, resolve);
+ }
+ return super.loadClass(name, resolve);
+ }
+}
diff --git a/test/626-const-class-linking/src/Helper1.java b/test/626-const-class-linking/src/Helper1.java
new file mode 100644
index 0000000..ff9cd1a
--- /dev/null
+++ b/test/626-const-class-linking/src/Helper1.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Helper1 {
+ public static ClassPair get() {
+ Class<?> helper1_class = Helper1.class;
+ Class<?> test_class = Test.class;
+ return new ClassPair(helper1_class, test_class);
+ }
+}
diff --git a/test/626-const-class-linking/src/Main.java b/test/626-const-class-linking/src/Main.java
new file mode 100644
index 0000000..44ea1c1
--- /dev/null
+++ b/test/626-const-class-linking/src/Main.java
@@ -0,0 +1,343 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+public class Main {
+ public static void main(String[] args) throws Exception {
+ try {
+ System.loadLibrary(args[0]);
+ } catch (UnsatisfiedLinkError ule) {
+ usingRI = true;
+ // Add expected JNI_OnLoad log line to match expected.txt.
+ System.out.println("JNI_OnLoad called");
+ }
+
+ testClearDexCache();
+ testMultiDex();
+ testRacyLoader();
+ testRacyLoader2();
+ testMisbehavingLoader();
+ testRacyMisbehavingLoader();
+ testRacyMisbehavingLoader2();
+ }
+
+ private static void testClearDexCache() throws Exception {
+ DelegatingLoader delegating_loader = createDelegatingLoader();
+ Class<?> helper = delegating_loader.loadClass("Helper1");
+
+ WeakReference<Class<?>> weak_test1 = wrapHelperGet(helper);
+ changeInner(delegating_loader);
+ if (!usingRI) {
+ clearResolvedTypes(helper);
+ }
+ Runtime.getRuntime().gc();
+ WeakReference<Class<?>> weak_test2 = wrapHelperGet(helper);
+
+ Class<?> test1 = weak_test1.get();
+ if (test1 == null) {
+ System.out.println("test1 disappeared");
+ }
+ Class<?> test2 = weak_test2.get();
+ if (test2 == null) {
+ System.out.println("test2 disappeared");
+ }
+ if (test1 != test2) {
+ System.out.println("test1 != test2");
+ }
+
+ test1 = null;
+ test2 = null;
+ if (!usingRI) {
+ clearResolvedTypes(helper);
+ }
+ helper = null;
+ delegating_loader = null;
+ Runtime.getRuntime().gc();
+ if (weak_test1.get() != null) {
+ System.out.println("weak_test1 still not null");
+ }
+ if (weak_test2.get() != null) {
+ System.out.println("weak_test2 still not null");
+ }
+ System.out.println("testClearDexCache done");
+ }
+
+ private static void testMultiDex() throws Exception {
+ DelegatingLoader delegating_loader = createDelegatingLoader();
+
+ Class<?> helper1 = delegating_loader.loadClass("Helper1");
+ WeakReference<Class<?>> weak_test1 = wrapHelperGet(helper1);
+
+ changeInner(delegating_loader);
+
+ Class<?> helper2 = delegating_loader.loadClass("Helper2");
+ WeakReference<Class<?>> weak_test2 = wrapHelperGet(helper2);
+
+ Class<?> test1 = weak_test1.get();
+ if (test1 == null) {
+ System.out.println("test1 disappeared");
+ }
+ Class<?> test2 = weak_test2.get();
+ if (test2 == null) {
+ System.out.println("test2 disappeared");
+ }
+ if (test1 != test2) {
+ System.out.println("test1 != test2");
+ }
+
+ test1 = null;
+ test2 = null;
+ delegating_loader = null;
+ helper1 = null;
+ helper2 = null;
+ Runtime.getRuntime().gc();
+ if (weak_test1.get() != null) {
+ System.out.println("weak_test1 still not null");
+ }
+ if (weak_test2.get() != null) {
+ System.out.println("weak_test2 still not null");
+ }
+ System.out.println("testMultiDex done");
+ }
+
+ private static void testMisbehavingLoader() throws Exception {
+ ClassLoader system_loader = ClassLoader.getSystemClassLoader();
+ DefiningLoader defining_loader = new DefiningLoader(system_loader);
+ MisbehavingLoader misbehaving_loader =
+ new MisbehavingLoader(system_loader, defining_loader);
+ Class<?> helper = misbehaving_loader.loadClass("Helper1");
+
+ try {
+ WeakReference<Class<?>> weak_test = wrapHelperGet(helper);
+ } catch (InvocationTargetException ite) {
+ String message = ite.getCause().getMessage();
+ if (usingRI && "Test".equals(message)) {
+ // Replace RI message with dalvik message to match expected.txt.
+ message = "Initiating class loader of type " +
+ misbehaving_loader.getClass().getName() +
+ " returned class Helper2 instead of Test.";
+ }
+ System.out.println(ite.getCause().getClass().getName() + ": " + message);
+ }
+ System.out.println("testMisbehavingLoader done");
+ }
+
+ private static void testRacyLoader() throws Exception {
+ final ClassLoader system_loader = ClassLoader.getSystemClassLoader();
+
+ final Thread[] threads = new Thread[4];
+ final Object[] results = new Object[threads.length];
+
+ final RacyLoader racy_loader = new RacyLoader(system_loader, threads.length);
+ final Class<?> helper1 = racy_loader.loadClass("Helper1");
+
+ for (int i = 0; i != threads.length; ++i) {
+ final int my_index = i;
+ Thread t = new Thread() {
+ public void run() {
+ try {
+ Method get = helper1.getDeclaredMethod("get");
+ results[my_index] = get.invoke(null);
+ } catch (InvocationTargetException ite) {
+ results[my_index] = ite.getCause();
+ } catch (Throwable t) {
+ results[my_index] = t;
+ }
+ }
+ };
+ t.start();
+ threads[i] = t;
+ }
+ for (Thread t : threads) {
+ t.join();
+ }
+ dumpResultStats(results);
+ System.out.println("testRacyLoader done");
+ }
+
+ private static void testRacyLoader2() throws Exception {
+ final ClassLoader system_loader = ClassLoader.getSystemClassLoader();
+
+ final Thread[] threads = new Thread[4];
+ final Object[] results = new Object[threads.length];
+
+ final RacyLoader racy_loader = new RacyLoader(system_loader, threads.length);
+ final Class<?> helper1 = racy_loader.loadClass("Helper1");
+ final Class<?> helper3 = racy_loader.loadClass("Helper3");
+
+ for (int i = 0; i != threads.length; ++i) {
+ final int my_index = i;
+ Thread t = new Thread() {
+ public void run() {
+ try {
+ Class<?> helper = (my_index < threads.length / 2) ? helper1 : helper3;
+ Method get = helper.getDeclaredMethod("get");
+ results[my_index] = get.invoke(null);
+ } catch (InvocationTargetException ite) {
+ results[my_index] = ite.getCause();
+ } catch (Throwable t) {
+ results[my_index] = t;
+ }
+ }
+ };
+ t.start();
+ threads[i] = t;
+ }
+ for (Thread t : threads) {
+ t.join();
+ }
+ dumpResultStats(results);
+ System.out.println("testRacyLoader2 done");
+ }
+
+ private static void dumpResultStats(Object[] results) throws Exception {
+ int throwables = 0;
+ int class_weaks = 0;
+ int unique_class_weaks = 0;
+ for (int i = 0; i != results.length; ++i) {
+ Object r = results[i];
+ if (r instanceof Throwable) {
+ ++throwables;
+ System.out.println(((Throwable) r).getMessage());
+ } else if (isClassPair(r)) {
+ printPair(r);
+ Object ref = getSecond(r);
+ ++class_weaks;
+ ++unique_class_weaks;
+ for (int j = 0; j != i; ++j) {
+ Object rj = results[j];
+ if (isClassPair(results[j]) && getSecond(results[j]) == ref) {
+ --unique_class_weaks;
+ break;
+ }
+ }
+ }
+ }
+ System.out.println("total: " + results.length);
+ System.out.println(" throwables: " + throwables);
+ System.out.println(" class_weaks: " + class_weaks
+ + " (" + unique_class_weaks + " unique)");
+ }
+
+ private static void testRacyMisbehavingLoader() throws Exception {
+ final ClassLoader system_loader = ClassLoader.getSystemClassLoader();
+
+ final Thread[] threads = new Thread[4];
+ final Object[] results = new Object[threads.length];
+
+ final RacyMisbehavingLoader racy_loader =
+ new RacyMisbehavingLoader(system_loader, threads.length, false);
+ final Class<?> helper1 = racy_loader.loadClass("RacyMisbehavingHelper");
+
+ for (int i = 0; i != threads.length; ++i) {
+ final int my_index = i;
+ Thread t = new Thread() {
+ public void run() {
+ try {
+ Method get = helper1.getDeclaredMethod("get");
+ results[my_index] = get.invoke(null);
+ } catch (InvocationTargetException ite) {
+ results[my_index] = ite.getCause();
+ } catch (Throwable t) {
+ results[my_index] = t;
+ }
+ }
+ };
+ t.start();
+ threads[i] = t;
+ }
+ for (Thread t : threads) {
+ t.join();
+ }
+ dumpResultStats(results);
+ System.out.println("testRacyMisbehavingLoader done");
+ }
+
+ private static void testRacyMisbehavingLoader2() throws Exception {
+ final ClassLoader system_loader = ClassLoader.getSystemClassLoader();
+
+ final Thread[] threads = new Thread[4];
+ final Object[] results = new Object[threads.length];
+
+ final RacyMisbehavingLoader racy_loader =
+ new RacyMisbehavingLoader(system_loader, threads.length, true);
+ final Class<?> helper1 = racy_loader.loadClass("RacyMisbehavingHelper");
+
+ for (int i = 0; i != threads.length; ++i) {
+ final int my_index = i;
+ Thread t = new Thread() {
+ public void run() {
+ try {
+ Method get = helper1.getDeclaredMethod("get");
+ results[my_index] = get.invoke(null);
+ } catch (InvocationTargetException ite) {
+ results[my_index] = ite.getCause();
+ } catch (Throwable t) {
+ results[my_index] = t;
+ }
+ }
+ };
+ t.start();
+ threads[i] = t;
+ }
+ for (Thread t : threads) {
+ t.join();
+ }
+ dumpResultStats(results);
+ System.out.println("testRacyMisbehavingLoader2 done");
+ }
+
+ private static DelegatingLoader createDelegatingLoader() {
+ ClassLoader system_loader = ClassLoader.getSystemClassLoader();
+ DefiningLoader defining_loader = new DefiningLoader(system_loader);
+ return new DelegatingLoader(system_loader, defining_loader);
+ }
+
+ private static void changeInner(DelegatingLoader delegating_loader) {
+ ClassLoader system_loader = ClassLoader.getSystemClassLoader();
+ DefiningLoader defining_loader = new DefiningLoader(system_loader);
+ delegating_loader.resetDefiningLoader(defining_loader);
+ }
+
+ private static WeakReference<Class<?>> wrapHelperGet(Class<?> helper) throws Exception {
+ Method get = helper.getDeclaredMethod("get");
+ Object pair = get.invoke(null);
+ printPair(pair);
+ return new WeakReference<Class<?>>(getSecond(pair));
+ }
+
+ private static void printPair(Object pair) throws Exception {
+ Method print = pair.getClass().getDeclaredMethod("print");
+ print.invoke(pair);
+ }
+
+ private static Class<?> getSecond(Object pair) throws Exception {
+ Field second = pair.getClass().getDeclaredField("second");
+ return (Class<?>) second.get(pair);
+ }
+
+ private static boolean isClassPair(Object r) {
+ return r != null && r.getClass().getName().equals("ClassPair");
+ }
+
+ public static native void clearResolvedTypes(Class<?> c);
+
+ static boolean usingRI = false;
+}
diff --git a/test/626-const-class-linking/src/MisbehavingLoader.java b/test/626-const-class-linking/src/MisbehavingLoader.java
new file mode 100644
index 0000000..61639ba
--- /dev/null
+++ b/test/626-const-class-linking/src/MisbehavingLoader.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Class loader that returns Helper2.class when asked to load "Test".
+public class MisbehavingLoader extends DefiningLoader {
+ private DefiningLoader defining_loader;
+
+ public MisbehavingLoader(ClassLoader parent, DefiningLoader defining_loader) {
+ super(parent);
+ this.defining_loader = defining_loader;
+ }
+
+ protected Class<?> findClass(String name) throws ClassNotFoundException
+ {
+ if (name.equals("Helper1") || name.equals("Helper2")) {
+ return super.findClass(name);
+ } else if (name.equals("Test")) {
+ throw new Error("Unexpected MisbehavingLoader.findClass(\"Test\")");
+ }
+ return super.findClass(name);
+ }
+
+ protected Class<?> loadClass(String name, boolean resolve)
+ throws ClassNotFoundException
+ {
+ if (name.equals("Helper1") || name.equals("Helper2")) {
+ return super.loadClass(name, resolve);
+ } else if (name.equals("Test")) {
+ // Ask for a different class.
+ System.out.println("MisbehavingLoader loading Helper2 instead of Test");
+ return defining_loader.loadClass("Helper2", resolve);
+ }
+ return super.loadClass(name, resolve);
+ }
+}
diff --git a/test/626-const-class-linking/src/RacyLoader.java b/test/626-const-class-linking/src/RacyLoader.java
new file mode 100644
index 0000000..abfc8ed
--- /dev/null
+++ b/test/626-const-class-linking/src/RacyLoader.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class RacyLoader extends DefiningLoader {
+ static {
+ // For JVM, register as parallel capable.
+ // Android treats all class loaders as parallel capable and makes this a no-op.
+ registerAsParallelCapable();
+ }
+
+ private Object lock = new Object();
+ private int index = 0;
+ private int count;
+
+ private DefiningLoader[] defining_loaders;
+
+ public RacyLoader(ClassLoader parent, int count) {
+ super(parent);
+ this.count = count;
+ defining_loaders = new DefiningLoader[2];
+ for (int i = 0; i != defining_loaders.length; ++i) {
+ defining_loaders[i] = new DefiningLoader(parent);
+ }
+ }
+
+ protected Class<?> findClass(String name) throws ClassNotFoundException
+ {
+ if (name.equals("Test") || name.equals("Test3")) {
+ throw new Error("Unexpected RacyLoader.findClass(\"" + name + "\")");
+ }
+ return super.findClass(name);
+ }
+
+ protected Class<?> loadClass(String name, boolean resolve)
+ throws ClassNotFoundException
+ {
+ if (name.equals("Test") || name.equals("Test3")) {
+ int my_index = syncWithOtherInstances(count);
+ Class<?> result = defining_loaders[my_index & 1].loadClass(name, resolve);
+ syncWithOtherInstances(2 * count);
+ return result;
+ }
+ return super.loadClass(name, resolve);
+ }
+
+ private int syncWithOtherInstances(int limit) {
+ int my_index;
+ synchronized (lock) {
+ my_index = index;
+ ++index;
+ if (index != limit) {
+ try {
+ lock.wait(2000);
+ if (index < limit) {
+ throw new Error("Timed out; my_index=" + my_index + ", index=" + index);
+ }
+ } catch (InterruptedException ie) {
+ throw new Error(ie);
+ }
+ } else {
+ lock.notifyAll();
+ }
+ }
+ return my_index;
+ }
+}
diff --git a/test/626-const-class-linking/src/RacyMisbehavingHelper.java b/test/626-const-class-linking/src/RacyMisbehavingHelper.java
new file mode 100644
index 0000000..4525278
--- /dev/null
+++ b/test/626-const-class-linking/src/RacyMisbehavingHelper.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.lang.reflect.Method;
+
+public class RacyMisbehavingHelper {
+ public static ClassPair get() {
+ Class<?> helper1_class = Helper1.class;
+ Class<?> test_class = Test.class;
+ try {
+ // After loading the correct class, allow loading the incorrect class.
+ ClassLoader loader = helper1_class.getClassLoader();
+ Method reportAfterLoading = loader.getClass().getDeclaredMethod("reportAfterLoading");
+ reportAfterLoading.invoke(loader);
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+ return new ClassPair(helper1_class, test_class);
+ }
+}
diff --git a/test/626-const-class-linking/src/RacyMisbehavingLoader.java b/test/626-const-class-linking/src/RacyMisbehavingLoader.java
new file mode 100644
index 0000000..d09888e
--- /dev/null
+++ b/test/626-const-class-linking/src/RacyMisbehavingLoader.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class RacyMisbehavingLoader extends DefiningLoader {
+ static {
+ // For JVM, register as parallel capable.
+ // Android treats all class loaders as parallel capable and makes this a no-op.
+ registerAsParallelCapable();
+ }
+
+ private Object lock = new Object();
+ private int index = 0;
+ private int count;
+ private boolean throw_error;
+
+ private DefiningLoader[] defining_loaders;
+
+ public RacyMisbehavingLoader(ClassLoader parent, int count, boolean throw_error) {
+ super(parent);
+ this.count = count;
+ this.throw_error = throw_error;
+ defining_loaders = new DefiningLoader[2];
+ for (int i = 0; i != defining_loaders.length; ++i) {
+ defining_loaders[i] = new DefiningLoader(parent);
+ }
+ }
+
+ public void reportAfterLoading() {
+ synchronized (lock) {
+ ++index;
+ if (index == 2 * count) {
+ lock.notifyAll();
+ }
+ }
+ }
+
+ protected Class<?> findClass(String name) throws ClassNotFoundException
+ {
+ if (name.equals("Test")) {
+ throw new Error("Unexpected RacyLoader.findClass(\"" + name + "\")");
+ }
+ return super.findClass(name);
+ }
+
+ protected Class<?> loadClass(String name, boolean resolve)
+ throws ClassNotFoundException
+ {
+ if (name.equals("Test")) {
+ int my_index = syncWithOtherInstances(count);
+ Class<?> result;
+ if ((my_index & 1) == 0) {
+ // Do not delay loading the correct class.
+ result = defining_loaders[my_index & 1].loadClass(name, resolve);
+ } else {
+ // Delay loading the wrong class.
+ syncWithOtherInstances(2 * count);
+ if (throw_error) {
+ throw new Error("RacyMisbehavingLoader throw_error=true");
+ }
+ result = defining_loaders[my_index & 1].loadClass("Test3", resolve);
+ }
+ return result;
+ }
+ return super.loadClass(name, resolve);
+ }
+
+ private int syncWithOtherInstances(int limit) {
+ int my_index;
+ synchronized (lock) {
+ my_index = index;
+ ++index;
+ if (index != limit) {
+ try {
+ lock.wait(2000);
+ if (index < limit) {
+ throw new Error("Timed out; my_index=" + my_index + ", index=" + index);
+ }
+ } catch (InterruptedException ie) {
+ throw new Error(ie);
+ }
+ } else {
+ lock.notifyAll();
+ }
+ }
+ return my_index;
+ }
+}
diff --git a/test/910-methods/methods.cc b/test/910-methods/methods.cc
index 8f0850b..3ed91d7 100644
--- a/test/910-methods/methods.cc
+++ b/test/910-methods/methods.cc
@@ -66,6 +66,15 @@
jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(gen));
}
+ // Also run GetMethodName with all parameter pointers null to check for segfaults.
+ jvmtiError result2 = jvmti_env->GetMethodName(id, nullptr, nullptr, nullptr);
+ if (result2 != JVMTI_ERROR_NONE) {
+ char* err;
+ jvmti_env->GetErrorName(result2, &err);
+ printf("Failure running GetMethodName(null, null, null): %s\n", err);
+ return nullptr;
+ }
+
return ret;
}
diff --git a/test/913-heaps/expected.txt b/test/913-heaps/expected.txt
index d1ddbae..8002cfa 100644
--- a/test/913-heaps/expected.txt
+++ b/test/913-heaps/expected.txt
@@ -45,7 +45,7 @@
6@1000 --(class)--> 1000@0 [size=123, length=-1]
---
root@root --(jni-global)--> 1@1000 [size=16, length=-1]
-root@root --(jni-local)--> 1@1000 [size=16, length=-1]
+root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 1@1000 [size=16, length=-1]
root@root --(stack-local)--> 1@1000 [size=16, length=-1]
root@root --(thread)--> 1@1000 [size=16, length=-1]
root@root --(thread)--> 3000@0 [size=132, length=-1]
@@ -67,7 +67,7 @@
6@1000 --(class)--> 1000@0 [size=123, length=-1]
---
root@root --(jni-global)--> 1@1000 [size=16, length=-1]
-root@root --(jni-local)--> 1@1000 [size=16, length=-1]
+root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 1@1000 [size=16, length=-1]
root@root --(stack-local)--> 1@1000 [size=16, length=-1]
root@root --(stack-local)--> 2@1000 [size=16, length=-1]
root@root --(thread)--> 1@1000 [size=16, length=-1]
diff --git a/test/913-heaps/heaps.cc b/test/913-heaps/heaps.cc
index 871902e..340671d 100644
--- a/test/913-heaps/heaps.cc
+++ b/test/913-heaps/heaps.cc
@@ -234,6 +234,41 @@
jint length_;
};
+ class JNILocalElement : public Elem {
+ public:
+ JNILocalElement(const std::string& referrer,
+ const std::string& referree,
+ jlong size,
+ jint length,
+ const jvmtiHeapReferenceInfo* reference_info)
+ : Elem(referrer, referree, size, length) {
+ memcpy(&info_, reference_info, sizeof(jvmtiHeapReferenceInfo));
+ }
+
+ protected:
+ std::string PrintArrowType() const OVERRIDE {
+ char* name = nullptr;
+ if (info_.jni_local.method != nullptr) {
+ jvmti_env->GetMethodName(info_.jni_local.method, &name, nullptr, nullptr);
+ }
+ std::string ret = StringPrintf("jni-local[id=%" PRId64 ",tag=%" PRId64 ",depth=%d,"
+ "method=%s]",
+ info_.jni_local.thread_id,
+ info_.jni_local.thread_tag,
+ info_.jni_local.depth,
+ name == nullptr ? "<null>" : name);
+ if (name != nullptr) {
+ jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(name));
+ }
+
+ return ret;
+ }
+
+ private:
+ const std::string string_;
+ jvmtiHeapReferenceInfo info_;
+ };
+
// For simple or unimplemented cases.
class StringElement : public Elem {
public:
@@ -351,11 +386,11 @@
length,
"stack-local"));
case JVMTI_HEAP_REFERENCE_JNI_LOCAL:
- return std::unique_ptr<Elem>(new StringElement(referrer,
- referree,
- size,
- length,
- "jni-local"));
+ return std::unique_ptr<Elem>(new JNILocalElement(referrer,
+ referree,
+ size,
+ length,
+ reference_info));
case JVMTI_HEAP_REFERENCE_THREAD:
return std::unique_ptr<Elem>(new StringElement(referrer,
referree,
diff --git a/test/Android.bp b/test/Android.bp
index fe20f29..39a4059 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -314,6 +314,7 @@
"595-profile-saving/profile-saving.cc",
"596-app-images/app_images.cc",
"597-deopt-new-string/deopt.cc",
+ "626-const-class-linking/clear_dex_cache_types.cc",
],
shared_libs: [
"libbacktrace",
diff --git a/test/etc/default-build b/test/etc/default-build
index e663496..408dcfd 100755
--- a/test/etc/default-build
+++ b/test/etc/default-build
@@ -273,8 +273,10 @@
fi
# Create a single jar with two dex files for multidex.
-if [ ${HAS_SRC_MULTIDEX} = "true" ] || [ ${HAS_SMALI_MULTIDEX} = "true" ]; then
- zip $TEST_NAME.jar classes.dex classes2.dex
-elif [ ${NEED_DEX} = "true" ]; then
- zip $TEST_NAME.jar classes.dex
+if [ ${NEED_DEX} = "true" ]; then
+ if [ ${HAS_SRC_MULTIDEX} = "true" ] || [ ${HAS_SMALI_MULTIDEX} = "true" ]; then
+ zip $TEST_NAME.jar classes.dex classes2.dex
+ else
+ zip $TEST_NAME.jar classes.dex
+ fi
fi
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index 06e4219..368c663 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -312,7 +312,8 @@
if [ "$USE_JVM" = "y" ]; then
export LD_LIBRARY_PATH=${ANDROID_HOST_OUT}/lib64
# Xmx is necessary since we don't pass down the ART flags to JVM.
- cmdline="${JAVA} ${DEBUGGER_OPTS} ${JVM_VERIFY_ARG} -Xmx256m -classpath classes ${FLAGS} $MAIN $@ ${ARGS}"
+ # We pass the classes2 path whether it's used (src-multidex) or not.
+ cmdline="${JAVA} ${DEBUGGER_OPTS} ${JVM_VERIFY_ARG} -Xmx256m -classpath classes:classes2 ${FLAGS} $MAIN $@ ${ARGS}"
if [ "$DEV_MODE" = "y" ]; then
echo $cmdline
fi