diff options
author | 2019-06-13 10:52:32 +0100 | |
---|---|---|
committer | 2019-06-17 09:30:53 +0000 | |
commit | 024d69fb9936ca5a0031d35c9f248853cbc25d3f (patch) | |
tree | c1eeddf91ea15eda5d139d4592ac7f0df80e9be0 | |
parent | 43ae4acf219fe25a56e2055ebcebc4d08020a25d (diff) |
Use cleared JNI weak sentinel from boot image.
We were already adding the sentinel to the boot image,
so we may as well reuse the boot image copy.
Also move pre-allocated objects from class roots to the
boot image live objects.
Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing
Test: aosp_taimen-userdebug boots.
Change-Id: I635dcdd146ca2c6b55d187e9a545a9990b0b35ca
-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_); |