summaryrefslogtreecommitdiff
path: root/runtime/class_linker.cc
diff options
context:
space:
mode:
author Nicolas Geoffray <ngeoffray@google.com> 2016-01-23 14:16:58 +0000
committer Gerrit Code Review <noreply-gerritcodereview@google.com> 2016-01-23 14:16:58 +0000
commit5d5dbeb0344fa57f34cee40f01f96829eae4b514 (patch)
tree5e4a1f49fe8e59c105397b53da3a5a963a22a9ff /runtime/class_linker.cc
parent01ebf4a0197ab221cb5af348607696458c5b927a (diff)
parent1bc977cf2f8199311a97f2ba9431a184540e3e9c (diff)
Merge "Revert "Load app images""
Diffstat (limited to 'runtime/class_linker.cc')
-rw-r--r--runtime/class_linker.cc757
1 files changed, 149 insertions, 608 deletions
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index be9310abd8..ed833c4335 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -336,10 +336,6 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b
// Use the pointer size from the runtime since we are probably creating the image.
image_pointer_size_ = InstructionSetPointerSize(runtime->GetInstructionSet());
- if (!ValidPointerSize(image_pointer_size_)) {
- *error_msg = StringPrintf("Invalid image pointer size: %zu", image_pointer_size_);
- return false;
- }
// java_lang_Class comes first, it's needed for AllocClass
// The GC can't handle an object with a null class since we can't get the size of this object.
@@ -493,7 +489,7 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b
return false;
}
AppendToBootClassPath(self, *dex_file);
- boot_dex_files_.push_back(std::move(dex_file));
+ opened_dex_files_.push_back(std::move(dex_file));
}
// now we can use FindSystemClass
@@ -882,7 +878,6 @@ struct TrampolineCheckData {
ArtMethod* m;
bool error;
};
-
static void CheckTrampolines(mirror::Object* obj, void* arg) NO_THREAD_SAFETY_ANALYSIS {
if (obj->IsClass()) {
mirror::Class* klass = obj->AsClass();
@@ -901,8 +896,8 @@ static void CheckTrampolines(mirror::Object* obj, void* arg) NO_THREAD_SAFETY_AN
}
}
-bool ClassLinker::InitFromBootImage(std::string* error_msg) {
- VLOG(startup) << __FUNCTION__ << " entering";
+bool ClassLinker::InitFromImage(std::string* error_msg) {
+ VLOG(startup) << "ClassLinker::InitFromImage entering";
CHECK(!init_done_);
Runtime* const runtime = Runtime::Current();
@@ -911,21 +906,6 @@ bool ClassLinker::InitFromBootImage(std::string* error_msg) {
std::vector<gc::space::ImageSpace*> spaces = heap->GetBootImageSpaces();
CHECK(!spaces.empty());
image_pointer_size_ = spaces[0]->GetImageHeader().GetPointerSize();
- if (!ValidPointerSize(image_pointer_size_)) {
- *error_msg = StringPrintf("Invalid image pointer size: %zu", image_pointer_size_);
- return false;
- }
- if (!runtime->IsAotCompiler()) {
- // Only the Aot compiler supports having an image with a different pointer size than the
- // runtime. This happens on the host for compiling 32 bit tests since we use a 64 bit libart
- // compiler. We may also use 32 bit dex2oat on a system with 64 bit apps.
- if (image_pointer_size_ != sizeof(void*)) {
- *error_msg = StringPrintf("Runtime must use current image pointer size: %zu vs %zu",
- image_pointer_size_,
- sizeof(void*));
- return false;
- }
- }
dex_cache_boot_image_class_lookup_required_ = true;
std::vector<const OatFile*> oat_files =
runtime->GetOatFileManager().RegisterImageOatFiles(spaces);
@@ -977,10 +957,19 @@ bool ClassLinker::InitFromBootImage(std::string* error_msg) {
}
}
- class_roots_ = GcRoot<mirror::ObjectArray<mirror::Class>>(
- down_cast<mirror::ObjectArray<mirror::Class>*>(
- spaces[0]->GetImageHeader().GetImageRoot(ImageHeader::kClassRoots)));
- mirror::Class::SetClassClass(class_roots_.Read()->Get(kJavaLangClass));
+ StackHandleScopeCollection handles(self);
+ std::vector<Handle<mirror::ObjectArray<mirror::DexCache>>> dex_caches_vector;
+ for (gc::space::ImageSpace* space : spaces) {
+ Handle<mirror::ObjectArray<mirror::DexCache>> dex_caches(handles.NewHandle(
+ space->GetImageHeader().GetImageRoot(ImageHeader::kDexCaches)->
+ AsObjectArray<mirror::DexCache>()));
+ dex_caches_vector.push_back(dex_caches);
+ }
+
+ Handle<mirror::ObjectArray<mirror::Class>> class_roots(handles.NewHandle(
+ spaces[0]->GetImageHeader().GetImageRoot(ImageHeader::kClassRoots)->
+ AsObjectArray<mirror::Class>()));
+ class_roots_ = GcRoot<mirror::ObjectArray<mirror::Class>>(class_roots.Get());
// Special case of setting up the String class early so that we can test arbitrary objects
// as being Strings or not
@@ -993,595 +982,162 @@ bool ClassLinker::InitFromBootImage(std::string* error_msg) {
runtime->SetSentinel(heap->AllocNonMovableObject<true>(
self, java_lang_Object, java_lang_Object->GetObjectSize(), VoidFunctor()));
- // reinit array_iftable_ from any array class instance, they should be ==
- array_iftable_ = GcRoot<mirror::IfTable>(GetClassRoot(kObjectArrayClass)->GetIfTable());
- DCHECK_EQ(array_iftable_.Read(), GetClassRoot(kBooleanArrayClass)->GetIfTable());
- // String class root was set above
- mirror::Field::SetClass(GetClassRoot(kJavaLangReflectField));
- mirror::Field::SetArrayClass(GetClassRoot(kJavaLangReflectFieldArrayClass));
- mirror::Constructor::SetClass(GetClassRoot(kJavaLangReflectConstructor));
- mirror::Constructor::SetArrayClass(GetClassRoot(kJavaLangReflectConstructorArrayClass));
- mirror::Method::SetClass(GetClassRoot(kJavaLangReflectMethod));
- mirror::Method::SetArrayClass(GetClassRoot(kJavaLangReflectMethodArrayClass));
- mirror::Reference::SetClass(GetClassRoot(kJavaLangRefReference));
- mirror::BooleanArray::SetArrayClass(GetClassRoot(kBooleanArrayClass));
- mirror::ByteArray::SetArrayClass(GetClassRoot(kByteArrayClass));
- mirror::CharArray::SetArrayClass(GetClassRoot(kCharArrayClass));
- mirror::DoubleArray::SetArrayClass(GetClassRoot(kDoubleArrayClass));
- mirror::FloatArray::SetArrayClass(GetClassRoot(kFloatArrayClass));
- mirror::IntArray::SetArrayClass(GetClassRoot(kIntArrayClass));
- mirror::LongArray::SetArrayClass(GetClassRoot(kLongArrayClass));
- mirror::ShortArray::SetArrayClass(GetClassRoot(kShortArrayClass));
- mirror::Throwable::SetClass(GetClassRoot(kJavaLangThrowable));
- mirror::StackTraceElement::SetClass(GetClassRoot(kJavaLangStackTraceElement));
-
- for (gc::space::ImageSpace* image_space : spaces) {
- // Boot class loader, use a null handle.
- std::vector<std::unique_ptr<const DexFile>> dex_files;
- if (!AddImageSpace(image_space,
- ScopedNullHandle<mirror::ClassLoader>(),
- /*dex_elements*/nullptr,
- /*dex_location*/nullptr,
- /*out*/&dex_files,
- error_msg)) {
- return false;
- }
- // Append opened dex files at the end.
- boot_dex_files_.insert(boot_dex_files_.end(),
- std::make_move_iterator(dex_files.begin()),
- std::make_move_iterator(dex_files.end()));
+ uint32_t dex_file_count = 0;
+ for (const OatFile* oat_file : oat_files) {
+ dex_file_count += oat_file->GetOatHeader().GetDexFileCount();
}
- FinishInit(self);
-
- VLOG(startup) << __FUNCTION__ << " exiting";
- return true;
-}
-
-static bool IsBootClassLoader(ScopedObjectAccessAlreadyRunnable& soa,
- mirror::ClassLoader* class_loader)
- SHARED_REQUIRES(Locks::mutator_lock_) {
- return class_loader == nullptr ||
- class_loader->GetClass() ==
- soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_BootClassLoader);
-}
-
-static mirror::String* GetDexPathListElementName(ScopedObjectAccessUnchecked& soa,
- mirror::Object* element)
- SHARED_REQUIRES(Locks::mutator_lock_) {
- ArtField* const dex_file_field =
- soa.DecodeField(WellKnownClasses::dalvik_system_DexPathList__Element_dexFile);
- ArtField* const dex_file_name_field =
- soa.DecodeField(WellKnownClasses::dalvik_system_DexFile_fileName);
- DCHECK(dex_file_field != nullptr);
- DCHECK(dex_file_name_field != nullptr);
- DCHECK(element != nullptr);
- CHECK_EQ(dex_file_field->GetDeclaringClass(), element->GetClass()) << PrettyTypeOf(element);
- mirror::Object* dex_file = dex_file_field->GetObject(element);
- if (dex_file == nullptr) {
- return nullptr;
+ uint32_t dex_caches_count = 0;
+ for (auto dex_caches : dex_caches_vector) {
+ dex_caches_count += dex_caches->GetLength();
}
- mirror::Object* const name_object = dex_file_name_field->GetObject(dex_file);
- if (name_object != nullptr) {
- return name_object->AsString();
+ if (dex_file_count != dex_caches_count) {
+ *error_msg = "Dex cache count and dex file count mismatch while trying to initialize from "
+ "image";
+ return false;
}
- return nullptr;
-}
-
-static bool FlattenPathClassLoader(mirror::ClassLoader* class_loader,
- std::list<mirror::String*>* out_dex_file_names,
- std::string* error_msg)
- SHARED_REQUIRES(Locks::mutator_lock_) {
- DCHECK(out_dex_file_names != nullptr);
- DCHECK(error_msg != nullptr);
- ScopedObjectAccessUnchecked soa(Thread::Current());
- ArtField* const dex_path_list_field =
- soa.DecodeField(WellKnownClasses::dalvik_system_PathClassLoader_pathList);
- ArtField* const dex_elements_field =
- soa.DecodeField(WellKnownClasses::dalvik_system_DexPathList_dexElements);
- CHECK(dex_path_list_field != nullptr);
- CHECK(dex_elements_field != nullptr);
- while (!IsBootClassLoader(soa, class_loader)) {
- if (class_loader->GetClass() !=
- soa.Decode<mirror::Class*>(WellKnownClasses::dalvik_system_PathClassLoader)) {
- *error_msg = StringPrintf("Unknown class loader type %s", PrettyTypeOf(class_loader).c_str());
- // Unsupported class loader.
- return false;
- }
- mirror::Object* dex_path_list = dex_path_list_field->GetObject(class_loader);
- if (dex_path_list != nullptr) {
- // DexPathList has an array dexElements of Elements[] which each contain a dex file.
- mirror::Object* dex_elements_obj = dex_elements_field->GetObject(dex_path_list);
- // Loop through each dalvik.system.DexPathList$Element's dalvik.system.DexFile and look
- // at the mCookie which is a DexFile vector.
- if (dex_elements_obj != nullptr) {
- mirror::ObjectArray<mirror::Object>* dex_elements =
- dex_elements_obj->AsObjectArray<mirror::Object>();
- // Reverse order since we insert the parent at the front.
- for (int32_t i = dex_elements->GetLength() - 1; i >= 0; --i) {
- mirror::Object* const element = dex_elements->GetWithoutChecks(i);
- if (element == nullptr) {
- *error_msg = StringPrintf("Null dex element at index %d", i);
- return false;
- }
- mirror::String* const name = GetDexPathListElementName(soa, element);
- if (name == nullptr) {
- *error_msg = StringPrintf("Null name for dex element at index %d", i);
- return false;
- }
- out_dex_file_names->push_front(name);
+ for (auto dex_caches : dex_caches_vector) {
+ for (int32_t i = 0; i < dex_caches->GetLength(); i++) {
+ StackHandleScope<1> hs2(self);
+ Handle<mirror::DexCache> dex_cache(hs2.NewHandle(dex_caches->Get(i)));
+ const std::string& dex_file_location(dex_cache->GetLocation()->ToModifiedUtf8());
+ const OatFile::OatDexFile* oat_dex_file = nullptr;
+ for (const OatFile* oat_file : oat_files) {
+ const OatFile::OatDexFile* oat_dex =
+ oat_file->GetOatDexFile(dex_file_location.c_str(), nullptr, false);
+ if (oat_dex != nullptr) {
+ DCHECK(oat_dex_file == nullptr);
+ oat_dex_file = oat_dex;
}
}
- }
- class_loader = class_loader->GetParent();
- }
- return true;
-}
-class FixupArtMethodArrayVisitor : public ArtMethodVisitor {
- public:
- explicit FixupArtMethodArrayVisitor(const ImageHeader& header) : header_(header) {}
-
- virtual void Visit(ArtMethod* method) SHARED_REQUIRES(Locks::mutator_lock_) {
- GcRoot<mirror::Class>* resolved_types = method->GetDexCacheResolvedTypes(sizeof(void*));
- const bool is_miranda = method->IsMiranda();
- if (resolved_types != nullptr) {
- bool in_image_space = false;
- if (kIsDebugBuild || is_miranda) {
- in_image_space = header_.GetImageSection(ImageHeader::kSectionDexCacheArrays).Contains(
- reinterpret_cast<const uint8_t*>(resolved_types) - header_.GetImageBegin());
- }
- // Must be in image space for non-miranda method.
- DCHECK(is_miranda || in_image_space)
- << resolved_types << " is not in image starting at "
- << reinterpret_cast<void*>(header_.GetImageBegin());
- if (!is_miranda || in_image_space) {
- // Go through the array so that we don't need to do a slow map lookup.
- method->SetDexCacheResolvedTypes(*reinterpret_cast<GcRoot<mirror::Class>**>(resolved_types),
- sizeof(void*));
- }
- }
- ArtMethod** resolved_methods = method->GetDexCacheResolvedMethods(sizeof(void*));
- if (resolved_methods != nullptr) {
- bool in_image_space = false;
- if (kIsDebugBuild || is_miranda) {
- in_image_space = header_.GetImageSection(ImageHeader::kSectionDexCacheArrays).Contains(
- reinterpret_cast<const uint8_t*>(resolved_methods) - header_.GetImageBegin());
+ if (oat_dex_file == nullptr) {
+ *error_msg = StringPrintf("Failed finding oat dex file for %s",
+ dex_file_location.c_str());
+ return false;
}
- // Must be in image space for non-miranda method.
- DCHECK(is_miranda || in_image_space)
- << resolved_methods << " is not in image starting at "
- << reinterpret_cast<void*>(header_.GetImageBegin());
- if (!is_miranda || in_image_space) {
- // Go through the array so that we don't need to do a slow map lookup.
- method->SetDexCacheResolvedMethods(*reinterpret_cast<ArtMethod***>(resolved_methods),
- sizeof(void*));
+ std::string inner_error_msg;
+ std::unique_ptr<const DexFile> dex_file = oat_dex_file->OpenDexFile(&inner_error_msg);
+ if (dex_file == nullptr) {
+ *error_msg = StringPrintf("Failed to open dex file %s error '%s'",
+ dex_file_location.c_str(),
+ inner_error_msg.c_str());
+ return false;
}
- }
- }
- private:
- const ImageHeader& header_;
-};
-
-class VerifyClassInTableArtMethodVisitor : public ArtMethodVisitor {
- public:
- explicit VerifyClassInTableArtMethodVisitor(ClassTable* table) : table_(table) {}
-
- virtual void Visit(ArtMethod* method)
- SHARED_REQUIRES(Locks::mutator_lock_, Locks::classlinker_classes_lock_) {
- mirror::Class* klass = method->GetDeclaringClass();
- if (klass != nullptr && !Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(klass)) {
- CHECK_EQ(table_->LookupByDescriptor(klass), klass) << PrettyClass(klass);
- }
- }
-
- private:
- ClassTable* const table_;
-};
-
-void ClassLinker::UpdateAppImageClassLoadersAndDexCaches(
- gc::space::ImageSpace* space,
- Handle<mirror::ClassLoader> class_loader,
- Handle<mirror::ObjectArray<mirror::DexCache>> dex_caches,
- bool added_class_table) {
- Thread* const self = Thread::Current();
- gc::Heap* const heap = Runtime::Current()->GetHeap();
- const ImageHeader& header = space->GetImageHeader();
- // Add image classes into the class table for the class loader, and fixup the dex caches and
- // class loader fields.
- WriterMutexLock mu(self, *Locks::classlinker_classes_lock_);
- ClassTable* table = InsertClassTableForClassLoader(class_loader.Get());
- // TODO: Store class table in the image to avoid manually adding the classes.
- for (int32_t i = 0, num_dex_caches = dex_caches->GetLength(); i < num_dex_caches; i++) {
- mirror::DexCache* const dex_cache = dex_caches->Get(i);
- const DexFile* const dex_file = dex_cache->GetDexFile();
- // If the oat file expects the dex cache arrays to be in the BSS, then allocate there and
- // copy over the arrays.
- DCHECK(dex_file != nullptr);
- const size_t num_strings = dex_file->NumStringIds();
- const size_t num_types = dex_file->NumTypeIds();
- const size_t num_methods = dex_file->NumMethodIds();
- const size_t num_fields = dex_file->NumFieldIds();
- CHECK_EQ(num_strings, dex_cache->NumStrings());
- CHECK_EQ(num_types, dex_cache->NumResolvedTypes());
- CHECK_EQ(num_methods, dex_cache->NumResolvedMethods());
- CHECK_EQ(num_fields, dex_cache->NumResolvedFields());
- if (dex_file->GetOatDexFile() != nullptr &&
- dex_file->GetOatDexFile()->GetDexCacheArrays() != nullptr) {
- DexCacheArraysLayout layout(image_pointer_size_, dex_file);
- uint8_t* const raw_arrays = dex_file->GetOatDexFile()->GetDexCacheArrays();
- // The space is not yet visible to the GC, we can avoid the read barriers and use
- // std::copy_n.
- if (num_strings != 0u) {
- GcRoot<mirror::String>* const strings =
- reinterpret_cast<GcRoot<mirror::String>*>(raw_arrays + layout.StringsOffset());
- for (size_t j = 0; kIsDebugBuild && j < num_strings; ++j) {
- DCHECK(strings[j].IsNull());
- }
- std::copy_n(dex_cache->GetStrings(), num_strings, strings);
- dex_cache->SetStrings(strings);
+ if (kSanityCheckObjects) {
+ SanityCheckArtMethodPointerArray(dex_cache->GetResolvedMethods(),
+ dex_cache->NumResolvedMethods(),
+ image_pointer_size_,
+ spaces);
}
- if (num_types != 0u) {
- GcRoot<mirror::Class>* const image_resolved_types = dex_cache->GetResolvedTypes();
- GcRoot<mirror::Class>* const types =
- reinterpret_cast<GcRoot<mirror::Class>*>(raw_arrays + layout.TypesOffset());
- for (size_t j = 0; kIsDebugBuild && j < num_types; ++j) {
- DCHECK(types[j].IsNull());
- }
- std::copy_n(image_resolved_types, num_types, types);
- // Store a pointer to the new location for fast ArtMethod patching without requiring map.
- // This leaves random garbage at the start of the dex cache array, but nobody should ever
- // read from it again.
- *reinterpret_cast<GcRoot<mirror::Class>**>(image_resolved_types) = types;
- dex_cache->SetResolvedTypes(types);
- }
- if (num_methods != 0u) {
- ArtMethod** const methods = reinterpret_cast<ArtMethod**>(
- raw_arrays + layout.MethodsOffset());
- ArtMethod** const image_resolved_methods = dex_cache->GetResolvedMethods();
- for (size_t j = 0; kIsDebugBuild && j < num_methods; ++j) {
- DCHECK(methods[j] == nullptr);
- }
- std::copy_n(image_resolved_methods, num_methods, methods);
- // Store a pointer to the new location for fast ArtMethod patching without requiring map.
- *reinterpret_cast<ArtMethod***>(image_resolved_methods) = methods;
- dex_cache->SetResolvedMethods(methods);
- }
- if (num_fields != 0u) {
- ArtField** const fields = reinterpret_cast<ArtField**>(raw_arrays + layout.FieldsOffset());
- for (size_t j = 0; kIsDebugBuild && j < num_fields; ++j) {
- DCHECK(fields[j] == nullptr);
- }
- std::copy_n(dex_cache->GetResolvedFields(), num_fields, fields);
- dex_cache->SetResolvedFields(fields);
- }
- }
- {
- WriterMutexLock mu2(self, dex_lock_);
- // Make sure to do this after we update the arrays since we store the resolved types array
- // in DexCacheData in RegisterDexFileLocked. We need the array pointer to be the one in the
- // BSS.
- mirror::DexCache* existing_dex_cache = FindDexCacheLocked(self,
- *dex_file,
- /*allow_failure*/true);
- CHECK(existing_dex_cache == nullptr);
- StackHandleScope<1> hs3(self);
- RegisterDexFileLocked(*dex_file, hs3.NewHandle(dex_cache));
- }
- GcRoot<mirror::Class>* const types = dex_cache->GetResolvedTypes();
- if (!added_class_table) {
- for (int32_t j = 0; j < static_cast<int32_t>(num_types); j++) {
- // The image space is not yet added to the heap, avoid read barriers.
- mirror::Class* klass = types[j].Read<kWithoutReadBarrier>();
- if (klass != nullptr) {
- DCHECK_NE(klass->GetStatus(), mirror::Class::kStatusError);
- // Update the class loader from the one in the image class loader to the one that loaded
- // the app image.
- klass->SetClassLoader(class_loader.Get());
- // If there are multiple dex caches, there may be the same class multiple times
- // in different dex caches. Check for this since inserting will add duplicates
- // otherwise.
- if (num_dex_caches > 1) {
- mirror::Class* existing = table->LookupByDescriptor(klass);
- if (existing != nullptr) {
- DCHECK_EQ(existing, klass) << PrettyClass(klass);
- } else {
- table->Insert(klass);
- }
- } else {
- table->Insert(klass);
- }
- // Double checked VLOG to avoid overhead.
- if (VLOG_IS_ON(image)) {
- VLOG(image) << PrettyClass(klass) << " " << klass->GetStatus();
- if (!klass->IsArrayClass()) {
- VLOG(image) << "From " << klass->GetDexCache()->GetDexFile()->GetBaseLocation();
- }
- VLOG(image) << "Direct methods";
- for (ArtMethod& m : klass->GetDirectMethods(sizeof(void*))) {
- VLOG(image) << PrettyMethod(&m);
- }
- VLOG(image) << "Virtual methods";
- for (ArtMethod& m : klass->GetVirtualMethods(sizeof(void*))) {
- VLOG(image) << PrettyMethod(&m);
- }
- }
- }
- }
- }
- if (kIsDebugBuild) {
- for (int32_t j = 0; j < static_cast<int32_t>(num_types); j++) {
- // The image space is not yet added to the heap, avoid read barriers.
- mirror::Class* klass = types[j].Read<kWithoutReadBarrier>();
- if (klass != nullptr) {
- DCHECK_NE(klass->GetStatus(), mirror::Class::kStatusError);
- if (kIsDebugBuild) {
- DCHECK_EQ(table->LookupByDescriptor(klass), klass);
- mirror::Class* super_class = klass->GetSuperClass();
- if (super_class != nullptr && !heap->ObjectIsInBootImageSpace(super_class)) {
- CHECK_EQ(table->LookupByDescriptor(super_class), super_class);
- }
- }
- DCHECK_EQ(klass->GetClassLoader(), class_loader.Get());
- if (kIsDebugBuild) {
- for (ArtMethod& m : klass->GetDirectMethods(sizeof(void*))) {
- const void* code = m.GetEntryPointFromQuickCompiledCode();
- const void* oat_code = m.IsInvokable() ? GetQuickOatCodeFor(&m) : code;
- if (!IsQuickResolutionStub(code) &&
- !IsQuickGenericJniStub(code) &&
- !IsQuickToInterpreterBridge(code) &&
- !m.IsNative()) {
- DCHECK_EQ(code, oat_code) << PrettyMethod(&m);
- }
- }
- VLOG(image) << "Virtual methods";
- for (ArtMethod& m : klass->GetVirtualMethods(sizeof(void*))) {
- const void* code = m.GetEntryPointFromQuickCompiledCode();
- const void* oat_code = m.IsInvokable() ? GetQuickOatCodeFor(&m) : code;
- if (!IsQuickResolutionStub(code) &&
- !IsQuickGenericJniStub(code) &&
- !IsQuickToInterpreterBridge(code) &&
- !m.IsNative()) {
- DCHECK_EQ(code, oat_code) << PrettyMethod(&m);
- }
- }
- }
- }
+ if (dex_file->GetLocationChecksum() != oat_dex_file->GetDexFileLocationChecksum()) {
+ *error_msg = StringPrintf("Checksums do not match for %s: %x vs %x",
+ dex_file_location.c_str(),
+ dex_file->GetLocationChecksum(),
+ oat_dex_file->GetDexFileLocationChecksum());
+ return false;
}
- }
- }
- {
- FixupArtMethodArrayVisitor visitor(header);
- header.GetImageSection(ImageHeader::kSectionArtMethods).VisitPackedArtMethods(
- &visitor, space->Begin(), sizeof(void*));
- Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(class_loader.Get());
- }
- if (kIsDebugBuild) {
- ClassTable* const class_table = class_loader.Get()->GetClassTable();
- VerifyClassInTableArtMethodVisitor visitor2(class_table);
- header.GetImageSection(ImageHeader::kSectionArtMethods).VisitPackedArtMethods(
- &visitor2, space->Begin(), sizeof(void*));
- }
-}
-bool ClassLinker::AddImageSpace(
- gc::space::ImageSpace* space,
- Handle<mirror::ClassLoader> class_loader,
- jobjectArray dex_elements,
- const char* dex_location,
- std::vector<std::unique_ptr<const DexFile>>* out_dex_files,
- std::string* error_msg) {
- DCHECK(out_dex_files != nullptr);
- DCHECK(error_msg != nullptr);
- const uint64_t start_time = NanoTime();
- const bool app_image = class_loader.Get() != nullptr;
- const ImageHeader& header = space->GetImageHeader();
- mirror::Object* dex_caches_object = header.GetImageRoot(ImageHeader::kDexCaches);
- DCHECK(dex_caches_object != nullptr);
- Runtime* const runtime = Runtime::Current();
- gc::Heap* const heap = runtime->GetHeap();
- Thread* const self = Thread::Current();
- StackHandleScope<2> hs(self);
- Handle<mirror::ObjectArray<mirror::DexCache>> dex_caches(
- hs.NewHandle(dex_caches_object->AsObjectArray<mirror::DexCache>()));
- Handle<mirror::ObjectArray<mirror::Class>> class_roots(hs.NewHandle(
- header.GetImageRoot(ImageHeader::kClassRoots)->AsObjectArray<mirror::Class>()));
- const OatFile* oat_file = space->GetOatFile();
- std::unordered_set<mirror::ClassLoader*> image_class_loaders;
- // Check that the image is what we are expecting.
- if (image_pointer_size_ != space->GetImageHeader().GetPointerSize()) {
- *error_msg = StringPrintf("Application image pointer size does not match runtime: %zu vs %zu",
- static_cast<size_t>(space->GetImageHeader().GetPointerSize()),
- image_pointer_size_);
- return false;
- }
- DCHECK(class_roots.Get() != nullptr);
- if (class_roots->GetLength() != static_cast<int32_t>(kClassRootsMax)) {
- *error_msg = StringPrintf("Expected %d class roots but got %d",
- class_roots->GetLength(),
- static_cast<int32_t>(kClassRootsMax));
- return false;
- }
- // Check against existing class roots to make sure they match the ones in the boot image.
- for (size_t i = 0; i < kClassRootsMax; i++) {
- if (class_roots->Get(i) != GetClassRoot(static_cast<ClassRoot>(i))) {
- *error_msg = "App image class roots must have pointer equality with runtime ones.";
- return false;
+ AppendToBootClassPath(*dex_file.get(), dex_cache);
+ opened_dex_files_.push_back(std::move(dex_file));
}
}
- if (oat_file->GetOatHeader().GetDexFileCount() !=
- static_cast<uint32_t>(dex_caches->GetLength())) {
- *error_msg = "Dex cache count and dex file count mismatch while trying to initialize from "
- "image";
+
+ if (!ValidPointerSize(image_pointer_size_)) {
+ *error_msg = StringPrintf("Invalid image pointer size: %zu", image_pointer_size_);
return false;
}
- StackHandleScope<1> hs2(self);
- MutableHandle<mirror::DexCache> h_dex_cache(hs2.NewHandle<mirror::DexCache>(nullptr));
- for (int32_t i = 0; i < dex_caches->GetLength(); i++) {
- h_dex_cache.Assign(dex_caches->Get(i));
- std::string dex_file_location(h_dex_cache->GetLocation()->ToModifiedUtf8());
- // TODO: Only store qualified paths.
- // If non qualified, qualify it.
- if (dex_file_location.find('/') == std::string::npos) {
- std::string dex_location_path = dex_location;
- const size_t pos = dex_location_path.find_last_of('/');
- CHECK_NE(pos, std::string::npos);
- dex_location_path = dex_location_path.substr(0, pos + 1); // Keep trailing '/'
- dex_file_location = dex_location_path + dex_file_location;
- }
- const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file_location.c_str(),
- nullptr);
- if (oat_dex_file == nullptr) {
- *error_msg = StringPrintf("Failed finding oat dex file for %s %s",
- oat_file->GetLocation().c_str(),
- dex_file_location.c_str());
- return false;
- }
- std::string inner_error_msg;
- std::unique_ptr<const DexFile> dex_file = oat_dex_file->OpenDexFile(&inner_error_msg);
- if (dex_file == nullptr) {
- *error_msg = StringPrintf("Failed to open dex file %s from within oat file %s error '%s'",
- dex_file_location.c_str(),
- oat_file->GetLocation().c_str(),
- inner_error_msg.c_str());
- return false;
- }
-
- if (dex_file->GetLocationChecksum() != oat_dex_file->GetDexFileLocationChecksum()) {
- *error_msg = StringPrintf("Checksums do not match for %s: %x vs %x",
- dex_file_location.c_str(),
- dex_file->GetLocationChecksum(),
- oat_dex_file->GetDexFileLocationChecksum());
+ // Set classes on AbstractMethod early so that IsMethod tests can be performed during the live
+ // bitmap walk.
+ if (!runtime->IsAotCompiler()) {
+ // Only the Aot compiler supports having an image with a different pointer size than the
+ // runtime. This happens on the host for compile 32 bit tests since we use a 64 bit libart
+ // compiler. We may also use 32 bit dex2oat on a system with 64 bit apps.
+ if (image_pointer_size_ != sizeof(void*)) {
+ *error_msg = StringPrintf("Runtime must use current image pointer size: %zu vs %zu",
+ image_pointer_size_ ,
+ sizeof(void*));
return false;
}
-
- if (app_image) {
- // The current dex file field is bogus, overwrite it so that we can get the dex file in the
- // loop below.
- h_dex_cache->SetDexFile(dex_file.get());
- // Check that each class loader resolved the same way.
- // TODO: Store image class loaders as image roots.
- GcRoot<mirror::Class>* const types = h_dex_cache->GetResolvedTypes();
- for (int32_t j = 0, num_types = h_dex_cache->NumResolvedTypes(); j < num_types; j++) {
- mirror::Class* klass = types[j].Read();
- if (klass != nullptr) {
- DCHECK_NE(klass->GetStatus(), mirror::Class::kStatusError);
- mirror::ClassLoader* image_class_loader = klass->GetClassLoader();
- image_class_loaders.insert(image_class_loader);
- }
- }
- } else {
- if (kSanityCheckObjects) {
- SanityCheckArtMethodPointerArray(h_dex_cache->GetResolvedMethods(),
- h_dex_cache->NumResolvedMethods(),
- image_pointer_size_,
- heap->GetBootImageSpaces());
- }
- // Register dex files, keep track of existing ones that are conflicts.
- AppendToBootClassPath(*dex_file.get(), h_dex_cache);
- }
- out_dex_files->push_back(std::move(dex_file));
- }
-
- if (app_image) {
- ScopedObjectAccessUnchecked soa(Thread::Current());
- // Check that the class loader resolves the same way as the ones in the image.
- // Image class loader [A][B][C][image dex files]
- // Class loader = [???][dex_elements][image dex files]
- // Need to ensure that [???][dex_elements] == [A][B][C].
- // For each class loader, PathClassLoader, the laoder checks the parent first. Also the logic
- // for PathClassLoader does this by looping through the array of dex files. To ensure they
- // resolve the same way, simply flatten the hierarchy in the way the resolution order would be,
- // and check that the dex file names are the same.
- for (mirror::ClassLoader* image_class_loader : image_class_loaders) {
- std::list<mirror::String*> image_dex_file_names;
- std::string temp_error_msg;
- if (!FlattenPathClassLoader(image_class_loader, &image_dex_file_names, &temp_error_msg)) {
- *error_msg = StringPrintf("Failed to flatten image class loader hierarchy '%s'",
- temp_error_msg.c_str());
- return false;
- }
- std::list<mirror::String*> loader_dex_file_names;
- if (!FlattenPathClassLoader(class_loader.Get(), &loader_dex_file_names, &temp_error_msg)) {
- *error_msg = StringPrintf("Failed to flatten class loader hierarchy '%s'",
- temp_error_msg.c_str());
- return false;
- }
- // Add the temporary dex path list elements at the end.
- auto* elements = soa.Decode<mirror::ObjectArray<mirror::Object>*>(dex_elements);
- for (size_t i = 0, num_elems = elements->GetLength(); i < num_elems; ++i) {
- mirror::Object* element = elements->GetWithoutChecks(i);
- if (element != nullptr) {
- // If we are somewhere in the middle of the array, there may be nulls at the end.
- loader_dex_file_names.push_back(GetDexPathListElementName(soa, element));
- }
- }
- // Ignore the number of image dex files since we are adding those to the class loader anyways.
- CHECK_GE(static_cast<size_t>(image_dex_file_names.size()),
- static_cast<size_t>(dex_caches->GetLength()));
- size_t image_count = image_dex_file_names.size() - dex_caches->GetLength();
- // Check that the dex file names match.
- bool equal = image_count == loader_dex_file_names.size();
- if (equal) {
- auto it1 = image_dex_file_names.begin();
- auto it2 = loader_dex_file_names.begin();
- for (size_t i = 0; equal && i < image_count; ++i, ++it1, ++it2) {
- equal = equal && (*it1)->Equals(*it2);
- }
- }
- if (!equal) {
- *error_msg = "Rejecting application image due to class loader mismatch";
- return false;
- }
- }
}
if (kSanityCheckObjects) {
- for (int32_t i = 0; i < dex_caches->GetLength(); i++) {
- auto* dex_cache = dex_caches->Get(i);
- for (size_t j = 0; j < dex_cache->NumResolvedFields(); ++j) {
- auto* field = dex_cache->GetResolvedField(j, image_pointer_size_);
- if (field != nullptr) {
- CHECK(field->GetDeclaringClass()->GetClass() != nullptr);
+ for (auto dex_caches : dex_caches_vector) {
+ for (int32_t i = 0; i < dex_caches->GetLength(); i++) {
+ auto* dex_cache = dex_caches->Get(i);
+ for (size_t j = 0; j < dex_cache->NumResolvedFields(); ++j) {
+ auto* field = dex_cache->GetResolvedField(j, image_pointer_size_);
+ if (field != nullptr) {
+ CHECK(field->GetDeclaringClass()->GetClass() != nullptr);
+ }
}
}
}
- if (!app_image) {
- heap->VisitObjects(SanityCheckObjectsCallback, nullptr);
- }
+ heap->VisitObjects(SanityCheckObjectsCallback, nullptr);
}
// Set entry point to interpreter if in InterpretOnly mode.
if (!runtime->IsAotCompiler() && runtime->GetInstrumentation()->InterpretOnly()) {
- const ImageSection& methods = header.GetMethodsSection();
- SetInterpreterEntrypointArtMethodVisitor visitor(image_pointer_size_);
- methods.VisitPackedArtMethods(&visitor, space->Begin(), image_pointer_size_);
- }
-
- const ImageSection& class_table_section = header.GetImageSection(ImageHeader::kSectionClassTable);
- bool added_class_table = false;
- if (app_image) {
- GetOrCreateAllocatorForClassLoader(class_loader.Get()); // Make sure we have a linear alloc.
- }
- if (class_table_section.Size() > 0u) {
- const uint64_t start_time2 = NanoTime();
- WriterMutexLock mu(self, *Locks::classlinker_classes_lock_);
- ClassTable* const class_table = InsertClassTableForClassLoader(class_loader.Get());
- class_table->ReadFromMemory(space->Begin() + class_table_section.Offset());
- if (app_image) {
- class_table->SetClassLoader(class_loader.Get());
- } else {
- dex_cache_boot_image_class_lookup_required_ = false;
+ for (gc::space::ImageSpace* space : spaces) {
+ const ImageHeader& header = space->GetImageHeader();
+ const ImageSection& methods = header.GetMethodsSection();
+ SetInterpreterEntrypointArtMethodVisitor visitor(image_pointer_size_);
+ methods.VisitPackedArtMethods(&visitor, space->Begin(), image_pointer_size_);
}
- VLOG(image) << "Adding class table classes took " << PrettyDuration(NanoTime() - start_time2);
- added_class_table = true;
}
- if (app_image) {
- UpdateAppImageClassLoadersAndDexCaches(space, class_loader, dex_caches, added_class_table);
+
+ // reinit class_roots_
+ mirror::Class::SetClassClass(class_roots->Get(kJavaLangClass));
+ class_roots_ = GcRoot<mirror::ObjectArray<mirror::Class>>(class_roots.Get());
+
+ // reinit array_iftable_ from any array class instance, they should be ==
+ array_iftable_ = GcRoot<mirror::IfTable>(GetClassRoot(kObjectArrayClass)->GetIfTable());
+ DCHECK_EQ(array_iftable_.Read(), GetClassRoot(kBooleanArrayClass)->GetIfTable());
+ // String class root was set above
+ mirror::Field::SetClass(GetClassRoot(kJavaLangReflectField));
+ mirror::Field::SetArrayClass(GetClassRoot(kJavaLangReflectFieldArrayClass));
+ mirror::Constructor::SetClass(GetClassRoot(kJavaLangReflectConstructor));
+ mirror::Constructor::SetArrayClass(GetClassRoot(kJavaLangReflectConstructorArrayClass));
+ mirror::Method::SetClass(GetClassRoot(kJavaLangReflectMethod));
+ mirror::Method::SetArrayClass(GetClassRoot(kJavaLangReflectMethodArrayClass));
+ mirror::Reference::SetClass(GetClassRoot(kJavaLangRefReference));
+ mirror::BooleanArray::SetArrayClass(GetClassRoot(kBooleanArrayClass));
+ mirror::ByteArray::SetArrayClass(GetClassRoot(kByteArrayClass));
+ mirror::CharArray::SetArrayClass(GetClassRoot(kCharArrayClass));
+ mirror::DoubleArray::SetArrayClass(GetClassRoot(kDoubleArrayClass));
+ mirror::FloatArray::SetArrayClass(GetClassRoot(kFloatArrayClass));
+ mirror::IntArray::SetArrayClass(GetClassRoot(kIntArrayClass));
+ mirror::LongArray::SetArrayClass(GetClassRoot(kLongArrayClass));
+ mirror::ShortArray::SetArrayClass(GetClassRoot(kShortArrayClass));
+ mirror::Throwable::SetClass(GetClassRoot(kJavaLangThrowable));
+ mirror::StackTraceElement::SetClass(GetClassRoot(kJavaLangStackTraceElement));
+
+ size_t class_tables_added = 0;
+ for (gc::space::ImageSpace* space : spaces) {
+ const ImageHeader& header = space->GetImageHeader();
+ const ImageSection& section = header.GetImageSection(ImageHeader::kSectionClassTable);
+ if (section.Size() > 0u) {
+ WriterMutexLock mu(self, *Locks::classlinker_classes_lock_);
+ ClassTable* const class_table = InsertClassTableForClassLoader(nullptr);
+ class_table->ReadFromMemory(space->Begin() + section.Offset());
+ ++class_tables_added;
+ }
}
- VLOG(class_linker) << "Adding image space took " << PrettyDuration(NanoTime() - start_time);
+ if (class_tables_added != 0) {
+ // Either all of the image spaces have an empty class section or none do. In the case where
+ // an image space has no classes, it will still have a non-empty class section that contains
+ // metadata.
+ CHECK_EQ(spaces.size(), class_tables_added)
+ << "Expected non-empty class section for each image space.";
+ dex_cache_boot_image_class_lookup_required_ = false;
+ }
+
+ FinishInit(self);
+
+ VLOG(startup) << "ClassLinker::InitFromImage exiting";
+
return true;
}
@@ -1971,6 +1527,14 @@ ClassPathEntry FindInClassPath(const char* descriptor,
return ClassPathEntry(nullptr, nullptr);
}
+static bool IsBootClassLoader(ScopedObjectAccessAlreadyRunnable& soa,
+ mirror::ClassLoader* class_loader)
+ SHARED_REQUIRES(Locks::mutator_lock_) {
+ return class_loader == nullptr ||
+ class_loader->GetClass() ==
+ soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_BootClassLoader);
+}
+
bool ClassLinker::FindClassInPathClassLoader(ScopedObjectAccessAlreadyRunnable& soa,
Thread* self,
const char* descriptor,
@@ -2256,7 +1820,6 @@ mirror::Class* ClassLinker::DefineClass(Thread* self,
// inserted before we allocate / fill in these fields.
LoadClass(self, dex_file, dex_class_def, klass);
if (self->IsExceptionPending()) {
- VLOG(class_linker) << self->GetException()->Dump();
// An exception occured during load, set status to erroneous while holding klass' lock in case
// notification is necessary.
if (!klass->IsErroneous()) {
@@ -2924,20 +2487,7 @@ void ClassLinker::RegisterDexFileLocked(const DexFile& dex_file,
Thread* const self = Thread::Current();
dex_lock_.AssertExclusiveHeld(self);
CHECK(dex_cache.Get() != nullptr) << dex_file.GetLocation();
- // For app images, the dex cache location may be a suffix of the dex file location since the
- // dex file location is an absolute path.
- const size_t dex_cache_length = dex_cache->GetLocation()->GetLength();
- CHECK_GT(dex_cache_length, 0u) << dex_file.GetLocation();
- std::string dex_file_location = dex_file.GetLocation();
- CHECK_GE(dex_file_location.length(), dex_cache_length)
- << dex_cache->GetLocation()->ToModifiedUtf8() << " " << dex_file.GetLocation();
- // Take suffix.
- const std::string dex_file_suffix = dex_file_location.substr(
- dex_file_location.length() - dex_cache_length,
- dex_cache_length);
- // Example dex_cache location is SettingsProvider.apk and
- // dex file location is /system/priv-app/SettingsProvider/SettingsProvider.apk
- CHECK(dex_cache->GetLocation()->Equals(dex_file_suffix))
+ CHECK(dex_cache->GetLocation()->Equals(dex_file.GetLocation()))
<< dex_cache->GetLocation()->ToModifiedUtf8() << " " << dex_file.GetLocation();
// Clean up pass to remove null dex caches.
// Null dex caches can occur due to class unloading and we are lazily removing null entries.
@@ -7381,13 +6931,10 @@ jobject ClassLinker::CreatePathClassLoader(Thread* self, std::vector<const DexFi
ArtField* cookie_field = soa.DecodeField(WellKnownClasses::dalvik_system_DexFile_cookie);
DCHECK_EQ(cookie_field->GetDeclaringClass(), element_file_field->GetType<false>());
- ArtField* file_name_field = soa.DecodeField(WellKnownClasses::dalvik_system_DexFile_fileName);
- DCHECK_EQ(file_name_field->GetDeclaringClass(), element_file_field->GetType<false>());
-
// Fill the elements array.
int32_t index = 0;
for (const DexFile* dex_file : dex_files) {
- StackHandleScope<4> hs2(self);
+ StackHandleScope<3> hs2(self);
// CreatePathClassLoader is only used by gtests. Index 0 of h_long_array is supposed to be the
// oat file but we can leave it null.
@@ -7402,11 +6949,6 @@ jobject ClassLinker::CreatePathClassLoader(Thread* self, std::vector<const DexFi
DCHECK(h_dex_file.Get() != nullptr);
cookie_field->SetObject<false>(h_dex_file.Get(), h_long_array.Get());
- Handle<mirror::String> h_file_name = hs2.NewHandle(
- mirror::String::AllocFromModifiedUtf8(self, dex_file->GetLocation().c_str()));
- DCHECK(h_file_name.Get() != nullptr);
- file_name_field->SetObject<false>(h_dex_file.Get(), h_file_name.Get());
-
Handle<mirror::Object> h_element = hs2.NewHandle(h_dex_element_class->AllocObject(self));
DCHECK(h_element.Get() != nullptr);
element_file_field->SetObject<false>(h_element.Get(), h_dex_file.Get());
@@ -7506,7 +7048,6 @@ void ClassLinker::CleanupClassLoaders() {
if (class_loader != nullptr) {
++it;
} else {
- VLOG(class_linker) << "Freeing class loader";
DeleteClassLoader(self, data);
it = class_loaders_.erase(it);
}