summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/optimizing/intrinsic_objects.cc67
-rw-r--r--compiler/optimizing/intrinsic_objects.h6
-rw-r--r--dex2oat/linker/image_writer.cc60
-rw-r--r--oatdump/oatdump.cc4
-rw-r--r--runtime/class_linker.cc18
-rw-r--r--runtime/image.cc2
-rw-r--r--runtime/image.h13
-rw-r--r--runtime/runtime.cc13
-rw-r--r--runtime/runtime.h2
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_);