diff options
-rw-r--r-- | compiler/optimizing/intrinsic_objects.cc | 67 | ||||
-rw-r--r-- | compiler/optimizing/intrinsic_objects.h | 6 | ||||
-rw-r--r-- | dex2oat/linker/image_writer.cc | 60 | ||||
-rw-r--r-- | oatdump/oatdump.cc | 4 | ||||
-rw-r--r-- | runtime/class_linker.cc | 18 | ||||
-rw-r--r-- | runtime/image.cc | 2 | ||||
-rw-r--r-- | runtime/image.h | 13 | ||||
-rw-r--r-- | runtime/runtime.cc | 13 | ||||
-rw-r--r-- | runtime/runtime.h | 2 |
9 files changed, 103 insertions, 82 deletions
diff --git a/compiler/optimizing/intrinsic_objects.cc b/compiler/optimizing/intrinsic_objects.cc index c345624a7a..5f6f562161 100644 --- a/compiler/optimizing/intrinsic_objects.cc +++ b/compiler/optimizing/intrinsic_objects.cc @@ -17,18 +17,18 @@ #include "intrinsic_objects.h" #include "art_field-inl.h" +#include "base/casts.h" #include "base/logging.h" -#include "class_root.h" -#include "handle.h" +#include "image.h" #include "obj_ptr-inl.h" -#include "mirror/object_array-alloc-inl.h" -#include "mirror/object_array-inl.h" namespace art { -static ObjPtr<mirror::ObjectArray<mirror::Object>> LookupIntegerCache(Thread* self, - ClassLinker* class_linker) - REQUIRES_SHARED(Locks::mutator_lock_) { +static constexpr size_t kIntrinsicObjectsOffset = + enum_cast<size_t>(ImageHeader::kIntrinsicObjectsStart); + +ObjPtr<mirror::ObjectArray<mirror::Object>> IntrinsicObjects::LookupIntegerCache( + Thread* self, ClassLinker* class_linker) { ObjPtr<mirror::Class> integer_cache_class = class_linker->LookupClass( self, "Ljava/lang/Integer$IntegerCache;", /* class_loader= */ nullptr); if (integer_cache_class == nullptr || !integer_cache_class->IsInitialized()) { @@ -44,47 +44,24 @@ static ObjPtr<mirror::ObjectArray<mirror::Object>> LookupIntegerCache(Thread* se return integer_cache; } -ObjPtr<mirror::ObjectArray<mirror::Object>> IntrinsicObjects::AllocateBootImageLiveObjects( - Thread* self, - ClassLinker* class_linker) REQUIRES_SHARED(Locks::mutator_lock_) { - // The objects used for the Integer.valueOf() intrinsic must remain live even if references - // to them are removed using reflection. Image roots are not accessible through reflection, - // so the array we construct here shall keep them alive. - StackHandleScope<1> hs(self); - Handle<mirror::ObjectArray<mirror::Object>> integer_cache = - hs.NewHandle(LookupIntegerCache(self, class_linker)); - size_t live_objects_size = - (integer_cache != nullptr) ? (/* cache */ 1u + integer_cache->GetLength()) : 0u; - ObjPtr<mirror::ObjectArray<mirror::Object>> live_objects = - mirror::ObjectArray<mirror::Object>::Alloc( - self, GetClassRoot<mirror::ObjectArray<mirror::Object>>(class_linker), live_objects_size); - int32_t index = 0; - if (integer_cache != nullptr) { - live_objects->Set(index++, integer_cache.Get()); - for (int32_t i = 0, length = integer_cache->GetLength(); i != length; ++i) { - live_objects->Set(index++, integer_cache->Get(i)); - } - } - CHECK_EQ(index, live_objects->GetLength()); - - if (kIsDebugBuild && integer_cache != nullptr) { - CHECK_EQ(integer_cache.Get(), GetIntegerValueOfCache(live_objects)); - for (int32_t i = 0, len = integer_cache->GetLength(); i != len; ++i) { - CHECK_EQ(integer_cache->GetWithoutChecks(i), GetIntegerValueOfObject(live_objects, i)); - } - } - return live_objects; +static bool HasIntrinsicObjects( + ObjPtr<mirror::ObjectArray<mirror::Object>> boot_image_live_objects) + REQUIRES_SHARED(Locks::mutator_lock_) { + DCHECK(boot_image_live_objects != nullptr); + uint32_t length = static_cast<uint32_t>(boot_image_live_objects->GetLength()); + DCHECK_GE(length, kIntrinsicObjectsOffset); + return length != kIntrinsicObjectsOffset; } ObjPtr<mirror::ObjectArray<mirror::Object>> IntrinsicObjects::GetIntegerValueOfCache( ObjPtr<mirror::ObjectArray<mirror::Object>> boot_image_live_objects) { - DCHECK(boot_image_live_objects != nullptr); - if (boot_image_live_objects->GetLength() == 0u) { + if (!HasIntrinsicObjects(boot_image_live_objects)) { return nullptr; // No intrinsic objects. } // No need for read barrier for boot image object or for verifying the value that was just stored. ObjPtr<mirror::Object> result = - boot_image_live_objects->GetWithoutChecks<kVerifyNone, kWithoutReadBarrier>(0); + boot_image_live_objects->GetWithoutChecks<kVerifyNone, kWithoutReadBarrier>( + kIntrinsicObjectsOffset); DCHECK(result != nullptr); DCHECK(result->IsObjectArray()); DCHECK(result->GetClass()->DescriptorEquals("[Ljava/lang/Integer;")); @@ -94,15 +71,14 @@ ObjPtr<mirror::ObjectArray<mirror::Object>> IntrinsicObjects::GetIntegerValueOfC ObjPtr<mirror::Object> IntrinsicObjects::GetIntegerValueOfObject( ObjPtr<mirror::ObjectArray<mirror::Object>> boot_image_live_objects, uint32_t index) { - DCHECK(boot_image_live_objects != nullptr); - DCHECK_NE(boot_image_live_objects->GetLength(), 0); + DCHECK(HasIntrinsicObjects(boot_image_live_objects)); DCHECK_LT(index, static_cast<uint32_t>(GetIntegerValueOfCache(boot_image_live_objects)->GetLength())); // No need for read barrier for boot image object or for verifying the value that was just stored. ObjPtr<mirror::Object> result = boot_image_live_objects->GetWithoutChecks<kVerifyNone, kWithoutReadBarrier>( - /* skip the IntegerCache.cache */ 1u + index); + kIntrinsicObjectsOffset + /* skip the IntegerCache.cache */ 1u + index); DCHECK(result != nullptr); DCHECK(result->GetClass()->DescriptorEquals("Ljava/lang/Integer;")); return result; @@ -110,8 +86,9 @@ ObjPtr<mirror::Object> IntrinsicObjects::GetIntegerValueOfObject( MemberOffset IntrinsicObjects::GetIntegerValueOfArrayDataOffset( ObjPtr<mirror::ObjectArray<mirror::Object>> boot_image_live_objects) { - DCHECK_NE(boot_image_live_objects->GetLength(), 0); - MemberOffset result = mirror::ObjectArray<mirror::Object>::OffsetOfElement(1u); + DCHECK(HasIntrinsicObjects(boot_image_live_objects)); + MemberOffset result = + mirror::ObjectArray<mirror::Object>::OffsetOfElement(kIntrinsicObjectsOffset + 1u); DCHECK_EQ(GetIntegerValueOfObject(boot_image_live_objects, 0u), (boot_image_live_objects ->GetFieldObject<mirror::Object, kVerifyNone, kWithoutReadBarrier>(result))); diff --git a/compiler/optimizing/intrinsic_objects.h b/compiler/optimizing/intrinsic_objects.h index 863017be38..ed764bd4b2 100644 --- a/compiler/optimizing/intrinsic_objects.h +++ b/compiler/optimizing/intrinsic_objects.h @@ -55,11 +55,9 @@ class IntrinsicObjects { return IndexField::Decode(intrinsic_data); } - static ObjPtr<mirror::ObjectArray<mirror::Object>> AllocateBootImageLiveObjects( - Thread* self, - ClassLinker* class_linker) REQUIRES_SHARED(Locks::mutator_lock_); - // Functions for retrieving data for Integer.valueOf(). + static ObjPtr<mirror::ObjectArray<mirror::Object>> LookupIntegerCache( + Thread* self, ClassLinker* class_linker) REQUIRES_SHARED(Locks::mutator_lock_); static ObjPtr<mirror::ObjectArray<mirror::Object>> GetIntegerValueOfCache( ObjPtr<mirror::ObjectArray<mirror::Object>> boot_image_live_objects) REQUIRES_SHARED(Locks::mutator_lock_); diff --git a/dex2oat/linker/image_writer.cc b/dex2oat/linker/image_writer.cc index 262b2242e4..afd221f000 100644 --- a/dex2oat/linker/image_writer.cc +++ b/dex2oat/linker/image_writer.cc @@ -148,6 +148,56 @@ static ArrayRef<const uint8_t> MaybeCompressData(ArrayRef<const uint8_t> source, // Separate objects into multiple bins to optimize dirty memory use. static constexpr bool kBinObjects = true; +ObjPtr<mirror::ObjectArray<mirror::Object>> AllocateBootImageLiveObjects( + Thread* self, Runtime* runtime) REQUIRES_SHARED(Locks::mutator_lock_) { + ClassLinker* class_linker = runtime->GetClassLinker(); + // The objects used for the Integer.valueOf() intrinsic must remain live even if references + // to them are removed using reflection. Image roots are not accessible through reflection, + // so the array we construct here shall keep them alive. + StackHandleScope<1> hs(self); + Handle<mirror::ObjectArray<mirror::Object>> integer_cache = + hs.NewHandle(IntrinsicObjects::LookupIntegerCache(self, class_linker)); + size_t live_objects_size = + enum_cast<size_t>(ImageHeader::kIntrinsicObjectsStart) + + ((integer_cache != nullptr) ? (/* cache */ 1u + integer_cache->GetLength()) : 0u); + ObjPtr<mirror::ObjectArray<mirror::Object>> live_objects = + mirror::ObjectArray<mirror::Object>::Alloc( + self, GetClassRoot<mirror::ObjectArray<mirror::Object>>(class_linker), live_objects_size); + int32_t index = 0u; + auto set_entry = [&](ImageHeader::BootImageLiveObjects entry, + ObjPtr<mirror::Object> value) REQUIRES_SHARED(Locks::mutator_lock_) { + DCHECK_EQ(index, enum_cast<int32_t>(entry)); + live_objects->Set</*kTransacrionActive=*/ false>(index, value); + ++index; + }; + set_entry(ImageHeader::kOomeWhenThrowingException, + runtime->GetPreAllocatedOutOfMemoryErrorWhenThrowingException()); + set_entry(ImageHeader::kOomeWhenThrowingOome, + runtime->GetPreAllocatedOutOfMemoryErrorWhenThrowingOOME()); + set_entry(ImageHeader::kOomeWhenHandlingStackOverflow, + runtime->GetPreAllocatedOutOfMemoryErrorWhenHandlingStackOverflow()); + set_entry(ImageHeader::kNoClassDefFoundError, runtime->GetPreAllocatedNoClassDefFoundError()); + set_entry(ImageHeader::kClearedJniWeakSentinel, runtime->GetSentinel().Read()); + + DCHECK_EQ(index, enum_cast<int32_t>(ImageHeader::kIntrinsicObjectsStart)); + if (integer_cache != nullptr) { + live_objects->Set(index++, integer_cache.Get()); + for (int32_t i = 0, length = integer_cache->GetLength(); i != length; ++i) { + live_objects->Set(index++, integer_cache->Get(i)); + } + } + CHECK_EQ(index, live_objects->GetLength()); + + if (kIsDebugBuild && integer_cache != nullptr) { + CHECK_EQ(integer_cache.Get(), IntrinsicObjects::GetIntegerValueOfCache(live_objects)); + for (int32_t i = 0, len = integer_cache->GetLength(); i != len; ++i) { + CHECK_EQ(integer_cache->GetWithoutChecks(i), + IntrinsicObjects::GetIntegerValueOfObject(live_objects, i)); + } + } + return live_objects; +} + ObjPtr<mirror::ClassLoader> ImageWriter::GetAppClassLoader() const REQUIRES_SHARED(Locks::mutator_lock_) { return compiler_options_.IsAppImage() @@ -1921,14 +1971,6 @@ ObjPtr<ObjectArray<Object>> ImageWriter::CreateImageRoots( self, GetClassRoot<ObjectArray<Object>>(class_linker), image_roots_size))); image_roots->Set<false>(ImageHeader::kDexCaches, dex_caches.Get()); image_roots->Set<false>(ImageHeader::kClassRoots, class_linker->GetClassRoots()); - image_roots->Set<false>(ImageHeader::kOomeWhenThrowingException, - runtime->GetPreAllocatedOutOfMemoryErrorWhenThrowingException()); - image_roots->Set<false>(ImageHeader::kOomeWhenThrowingOome, - runtime->GetPreAllocatedOutOfMemoryErrorWhenThrowingOOME()); - image_roots->Set<false>(ImageHeader::kOomeWhenHandlingStackOverflow, - runtime->GetPreAllocatedOutOfMemoryErrorWhenHandlingStackOverflow()); - image_roots->Set<false>(ImageHeader::kNoClassDefFoundError, - runtime->GetPreAllocatedNoClassDefFoundError()); if (!compiler_options_.IsAppImage()) { DCHECK(boot_image_live_objects != nullptr); image_roots->Set<false>(ImageHeader::kBootImageLiveObjects, boot_image_live_objects.Get()); @@ -2260,7 +2302,7 @@ void ImageWriter::CalculateNewObjectOffsets() { MutableHandle<ObjectArray<Object>> boot_image_live_objects = handles.NewHandle( compiler_options_.IsAppImage() ? nullptr - : IntrinsicObjects::AllocateBootImageLiveObjects(self, runtime->GetClassLinker())); + : AllocateBootImageLiveObjects(self, runtime)); std::vector<Handle<ObjectArray<Object>>> image_roots; for (size_t i = 0, size = oat_filenames_.size(); i != size; ++i) { image_roots.push_back(handles.NewHandle(CreateImageRoots(i, boot_image_live_objects))); diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index 5b7535d010..090e271421 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -110,10 +110,6 @@ const char* image_methods_descriptions_[] = { const char* image_roots_descriptions_[] = { "kDexCaches", "kClassRoots", - "kOomeWhenThrowingException", - "kOomeWhenThrowingOome", - "kOomeWhenHandlingStackOverflow", - "kNoClassDefFoundError", "kSpecialRoots", }; diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 1343b16193..b2e7d99497 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -951,12 +951,12 @@ bool ClassLinker::InitFromBootImage(std::string* error_msg) { gc::Heap* const heap = runtime->GetHeap(); std::vector<gc::space::ImageSpace*> spaces = heap->GetBootImageSpaces(); CHECK(!spaces.empty()); - uint32_t pointer_size_unchecked = spaces[0]->GetImageHeader().GetPointerSizeUnchecked(); + const ImageHeader& image_header = spaces[0]->GetImageHeader(); + uint32_t pointer_size_unchecked = image_header.GetPointerSizeUnchecked(); if (!ValidPointerSize(pointer_size_unchecked)) { *error_msg = StringPrintf("Invalid image pointer size: %u", pointer_size_unchecked); return false; } - const ImageHeader& image_header = spaces[0]->GetImageHeader(); image_pointer_size_ = image_header.GetPointerSize(); if (!runtime->IsAotCompiler()) { // Only the Aot compiler supports having an image with a different pointer size than the @@ -1057,15 +1057,15 @@ bool ClassLinker::InitFromBootImage(std::string* error_msg) { class_roots_ = GcRoot<mirror::ObjectArray<mirror::Class>>( ObjPtr<mirror::ObjectArray<mirror::Class>>::DownCast( - spaces[0]->GetImageHeader().GetImageRoot(ImageHeader::kClassRoots))); + image_header.GetImageRoot(ImageHeader::kClassRoots))); DCHECK_EQ(GetClassRoot<mirror::Class>(this)->GetClassFlags(), mirror::kClassFlagClass); - ObjPtr<mirror::Class> java_lang_Object = GetClassRoot<mirror::Object>(this); - java_lang_Object->SetObjectSize(sizeof(mirror::Object)); - // Allocate in non-movable so that it's possible to check if a JNI weak global ref has been - // cleared without triggering the read barrier and unintentionally mark the sentinel alive. - runtime->SetSentinel(heap->AllocNonMovableObject( - self, java_lang_Object, java_lang_Object->GetObjectSize(), VoidFunctor())); + DCHECK_EQ(GetClassRoot<mirror::Object>(this)->GetObjectSize(), sizeof(mirror::Object)); + ObjPtr<mirror::ObjectArray<mirror::Object>> boot_image_live_objects = + ObjPtr<mirror::ObjectArray<mirror::Object>>::DownCast( + image_header.GetImageRoot(ImageHeader::kBootImageLiveObjects)); + runtime->SetSentinel(boot_image_live_objects->Get(ImageHeader::kClearedJniWeakSentinel)); + DCHECK(runtime->GetSentinel().Read()->GetClass() == GetClassRoot<mirror::Object>(this)); const std::vector<std::string>& boot_class_path_locations = runtime->GetBootClassPathLocations(); CHECK_LE(spaces.size(), boot_class_path_locations.size()); diff --git a/runtime/image.cc b/runtime/image.cc index 64046d025d..0209a2955b 100644 --- a/runtime/image.cc +++ b/runtime/image.cc @@ -29,7 +29,7 @@ namespace art { const uint8_t ImageHeader::kImageMagic[] = { 'a', 'r', 't', '\n' }; -const uint8_t ImageHeader::kImageVersion[] = { '0', '7', '6', '\0' }; // SBAppend simplification. +const uint8_t ImageHeader::kImageVersion[] = { '0', '7', '7', '\0' }; // Use boot image sentinel. ImageHeader::ImageHeader(uint32_t image_reservation_size, uint32_t component_count, diff --git a/runtime/image.h b/runtime/image.h index 88bba13e19..46260552db 100644 --- a/runtime/image.h +++ b/runtime/image.h @@ -222,10 +222,6 @@ class PACKED(8) ImageHeader { enum ImageRoot { kDexCaches, kClassRoots, - kOomeWhenThrowingException, // Pre-allocated OOME when throwing exception. - kOomeWhenThrowingOome, // Pre-allocated OOME when throwing OOME. - kOomeWhenHandlingStackOverflow, // Pre-allocated OOME when handling StackOverflowError. - kNoClassDefFoundError, // Pre-allocated NoClassDefFoundError. kSpecialRoots, // Different for boot image and app image, see aliases below. kImageRootsMax, @@ -234,6 +230,15 @@ class PACKED(8) ImageHeader { kBootImageLiveObjects = kSpecialRoots, // Array of boot image objects that must be kept live. }; + enum BootImageLiveObjects { + kOomeWhenThrowingException, // Pre-allocated OOME when throwing exception. + kOomeWhenThrowingOome, // Pre-allocated OOME when throwing OOME. + kOomeWhenHandlingStackOverflow, // Pre-allocated OOME when handling StackOverflowError. + kNoClassDefFoundError, // Pre-allocated NoClassDefFoundError. + kClearedJniWeakSentinel, // Pre-allocated sentinel for cleared weak JNI references. + kIntrinsicObjectsStart + }; + /* * This describes the number and ordering of sections inside of Boot * and App Images. It is very important that changes to this struct diff --git a/runtime/runtime.cc b/runtime/runtime.cc index cda1fd9d5b..3ba888f8bb 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -1094,7 +1094,7 @@ static size_t OpenBootDexFiles(ArrayRef<const std::string> dex_filenames, return failure_count; } -void Runtime::SetSentinel(mirror::Object* sentinel) { +void Runtime::SetSentinel(ObjPtr<mirror::Object> sentinel) { CHECK(sentinel_.Read() == nullptr); CHECK(sentinel != nullptr); CHECK(!heap_->IsMovableObject(sentinel)); @@ -1612,20 +1612,23 @@ bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) { if (GetHeap()->HasBootImageSpace()) { const ImageHeader& image_header = GetHeap()->GetBootImageSpaces()[0]->GetImageHeader(); + ObjPtr<mirror::ObjectArray<mirror::Object>> boot_image_live_objects = + ObjPtr<mirror::ObjectArray<mirror::Object>>::DownCast( + image_header.GetImageRoot(ImageHeader::kBootImageLiveObjects)); pre_allocated_OutOfMemoryError_when_throwing_exception_ = GcRoot<mirror::Throwable>( - image_header.GetImageRoot(ImageHeader::kOomeWhenThrowingException)->AsThrowable()); + boot_image_live_objects->Get(ImageHeader::kOomeWhenThrowingException)->AsThrowable()); DCHECK(pre_allocated_OutOfMemoryError_when_throwing_exception_.Read()->GetClass() ->DescriptorEquals("Ljava/lang/OutOfMemoryError;")); pre_allocated_OutOfMemoryError_when_throwing_oome_ = GcRoot<mirror::Throwable>( - image_header.GetImageRoot(ImageHeader::kOomeWhenThrowingOome)->AsThrowable()); + boot_image_live_objects->Get(ImageHeader::kOomeWhenThrowingOome)->AsThrowable()); DCHECK(pre_allocated_OutOfMemoryError_when_throwing_oome_.Read()->GetClass() ->DescriptorEquals("Ljava/lang/OutOfMemoryError;")); pre_allocated_OutOfMemoryError_when_handling_stack_overflow_ = GcRoot<mirror::Throwable>( - image_header.GetImageRoot(ImageHeader::kOomeWhenHandlingStackOverflow)->AsThrowable()); + boot_image_live_objects->Get(ImageHeader::kOomeWhenHandlingStackOverflow)->AsThrowable()); DCHECK(pre_allocated_OutOfMemoryError_when_handling_stack_overflow_.Read()->GetClass() ->DescriptorEquals("Ljava/lang/OutOfMemoryError;")); pre_allocated_NoClassDefFoundError_ = GcRoot<mirror::Throwable>( - image_header.GetImageRoot(ImageHeader::kNoClassDefFoundError)->AsThrowable()); + boot_image_live_objects->Get(ImageHeader::kNoClassDefFoundError)->AsThrowable()); DCHECK(pre_allocated_NoClassDefFoundError_.Read()->GetClass() ->DescriptorEquals("Ljava/lang/NoClassDefFoundError;")); } else { diff --git a/runtime/runtime.h b/runtime/runtime.h index dd66b8568a..7050fd23b6 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -719,7 +719,7 @@ class Runtime { } // Called from class linker. - void SetSentinel(mirror::Object* sentinel) REQUIRES_SHARED(Locks::mutator_lock_); + void SetSentinel(ObjPtr<mirror::Object> sentinel) REQUIRES_SHARED(Locks::mutator_lock_); // For testing purpose only. // TODO: Remove this when this is no longer needed (b/116087961). GcRoot<mirror::Object> GetSentinel() REQUIRES_SHARED(Locks::mutator_lock_); |