summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/optimizing/intrinsics.cc45
-rw-r--r--dex2oat/linker/image_writer.cc87
-rw-r--r--dex2oat/linker/image_writer.h2
-rw-r--r--runtime/class_linker.cc8
-rw-r--r--runtime/image.cc2
-rw-r--r--runtime/image.h12
-rw-r--r--runtime/runtime.cc1
7 files changed, 104 insertions, 53 deletions
diff --git a/compiler/optimizing/intrinsics.cc b/compiler/optimizing/intrinsics.cc
index 056f533398..02f736d775 100644
--- a/compiler/optimizing/intrinsics.cc
+++ b/compiler/optimizing/intrinsics.cc
@@ -272,34 +272,33 @@ IntrinsicVisitor::IntegerValueOfInfo IntrinsicVisitor::ComputeIntegerValueOfInfo
ClassLinker* class_linker = runtime->GetClassLinker();
gc::Heap* heap = runtime->GetHeap();
IntegerValueOfInfo info;
- info.integer_cache =
- class_linker->FindSystemClass(self, "Ljava/lang/Integer$IntegerCache;").Ptr();
- if (info.integer_cache == nullptr) {
- self->ClearException();
+ info.integer_cache = class_linker->LookupClass(self,
+ "Ljava/lang/Integer$IntegerCache;",
+ /* class_loader */ nullptr).Ptr();
+ if (info.integer_cache == nullptr || !info.integer_cache->IsInitialized()) {
+ // Optimization only works if the class is initialized.
return info;
}
- if (!heap->ObjectIsInBootImageSpace(info.integer_cache) || !info.integer_cache->IsInitialized()) {
- // Optimization only works if the class is initialized and in the boot image.
+ if (!heap->ObjectIsInBootImageSpace(info.integer_cache)) {
+ // Optimization only works if the class is in the boot image.
+ // TODO: Implement the intrinsic for boot image compilation.
return info;
}
- info.integer = class_linker->FindSystemClass(self, "Ljava/lang/Integer;").Ptr();
- if (info.integer == nullptr) {
- self->ClearException();
- return info;
- }
- if (!heap->ObjectIsInBootImageSpace(info.integer) || !info.integer->IsInitialized()) {
- // Optimization only works if the class is initialized and in the boot image.
+ info.integer =
+ class_linker->LookupClass(self, "Ljava/lang/Integer;", /* class_loader */ nullptr).Ptr();
+ DCHECK(info.integer != nullptr);
+ DCHECK(info.integer->IsInitialized()); // Must be initialized since IntegerCache is initialized.
+ if (!heap->ObjectIsInBootImageSpace(info.integer)) {
+ // Optimization only works if the class is in the boot image.
return info;
}
ArtField* field = info.integer_cache->FindDeclaredStaticField("cache", "[Ljava/lang/Integer;");
- if (field == nullptr) {
- return info;
- }
+ CHECK(field != nullptr);
info.cache = static_cast<mirror::ObjectArray<mirror::Object>*>(
field->GetObject(info.integer_cache).Ptr());
if (info.cache == nullptr) {
- return info;
+ return info; // Did someone mess up the IntegerCache using reflection?
}
if (!heap->ObjectIsInBootImageSpace(info.cache)) {
@@ -308,21 +307,15 @@ IntrinsicVisitor::IntegerValueOfInfo IntrinsicVisitor::ComputeIntegerValueOfInfo
}
field = info.integer->FindDeclaredInstanceField("value", "I");
- if (field == nullptr) {
- return info;
- }
+ CHECK(field != nullptr);
info.value_offset = field->GetOffset().Int32Value();
field = info.integer_cache->FindDeclaredStaticField("low", "I");
- if (field == nullptr) {
- return info;
- }
+ CHECK(field != nullptr);
info.low = field->GetInt(info.integer_cache);
field = info.integer_cache->FindDeclaredStaticField("high", "I");
- if (field == nullptr) {
- return info;
- }
+ CHECK(field != nullptr);
info.high = field->GetInt(info.integer_cache);
DCHECK_EQ(info.cache->GetLength(), info.high - info.low + 1);
diff --git a/dex2oat/linker/image_writer.cc b/dex2oat/linker/image_writer.cc
index dc0709013c..f1cb068a38 100644
--- a/dex2oat/linker/image_writer.cc
+++ b/dex2oat/linker/image_writer.cc
@@ -1261,15 +1261,8 @@ mirror::String* ImageWriter::FindInternedString(mirror::String* string) {
return nullptr;
}
-
-ObjectArray<Object>* ImageWriter::CreateImageRoots(size_t oat_index) const {
- Runtime* runtime = Runtime::Current();
- ClassLinker* class_linker = runtime->GetClassLinker();
- Thread* self = Thread::Current();
- StackHandleScope<3> hs(self);
- Handle<Class> object_array_class(hs.NewHandle(
- class_linker->FindSystemClass(self, "[Ljava/lang/Object;")));
-
+ObjPtr<mirror::ObjectArray<mirror::Object>> ImageWriter::CollectDexCaches(Thread* self,
+ size_t oat_index) const {
std::unordered_set<const DexFile*> image_dex_files;
for (auto& pair : dex_file_oat_index_map_) {
const DexFile* image_dex_file = pair.first;
@@ -1284,6 +1277,7 @@ ObjectArray<Object>* ImageWriter::CreateImageRoots(size_t oat_index) const {
// ObjectArray, we lock the dex lock twice, first to get the number
// of dex caches first and then lock it again to copy the dex
// caches. We check that the number of dex caches does not change.
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
size_t dex_cache_count = 0;
{
ReaderMutexLock mu(self, *Locks::dex_lock_);
@@ -1300,8 +1294,8 @@ ObjectArray<Object>* ImageWriter::CreateImageRoots(size_t oat_index) const {
}
}
}
- Handle<ObjectArray<Object>> dex_caches(
- hs.NewHandle(ObjectArray<Object>::Alloc(self, object_array_class.Get(), dex_cache_count)));
+ ObjPtr<ObjectArray<Object>> dex_caches = ObjectArray<Object>::Alloc(
+ self, GetClassRoot<ObjectArray<Object>>(class_linker), dex_cache_count);
CHECK(dex_caches != nullptr) << "Failed to allocate a dex cache array.";
{
ReaderMutexLock mu(self, *Locks::dex_lock_);
@@ -1335,11 +1329,62 @@ ObjectArray<Object>* ImageWriter::CreateImageRoots(size_t oat_index) const {
}
}
}
+ return dex_caches;
+}
+
+static ObjPtr<mirror::ObjectArray<mirror::Object>> LookupIntegerCache(Thread* self,
+ ClassLinker* class_linker)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ ObjPtr<mirror::Class> integer_cache_class = class_linker->LookupClass(
+ self, "Ljava/lang/Integer$IntegerCache;", /* class_linker */ nullptr);
+ if (integer_cache_class == nullptr || !integer_cache_class->IsInitialized()) {
+ return nullptr;
+ }
+ ArtField* cache_field =
+ integer_cache_class->FindDeclaredStaticField("cache", "[Ljava/lang/Integer;");
+ CHECK(cache_field != nullptr);
+ ObjPtr<ObjectArray<mirror::Object>> integer_cache =
+ ObjPtr<ObjectArray<mirror::Object>>::DownCast(cache_field->GetObject(integer_cache_class));
+ CHECK(integer_cache != nullptr);
+ return integer_cache;
+}
+
+static ObjPtr<mirror::ObjectArray<mirror::Object>> CollectBootImageLiveObjects(
+ 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<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 = ObjectArray<Object>::Alloc(
+ self, GetClassRoot<ObjectArray<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());
+ return live_objects;
+}
+
+ObjectArray<Object>* ImageWriter::CreateImageRoots(size_t oat_index) const {
+ Runtime* runtime = Runtime::Current();
+ ClassLinker* class_linker = runtime->GetClassLinker();
+ Thread* self = Thread::Current();
+ StackHandleScope<2> hs(self);
+
+ Handle<ObjectArray<Object>> dex_caches(hs.NewHandle(CollectDexCaches(self, oat_index)));
// build an Object[] of the roots needed to restore the runtime
int32_t image_roots_size = ImageHeader::NumberOfImageRoots(compile_app_image_);
- auto image_roots(hs.NewHandle(
- ObjectArray<Object>::Alloc(self, object_array_class.Get(), image_roots_size)));
+ Handle<ObjectArray<Object>> image_roots(hs.NewHandle(ObjectArray<Object>::Alloc(
+ 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,
@@ -1350,10 +1395,16 @@ ObjectArray<Object>* ImageWriter::CreateImageRoots(size_t oat_index) const {
runtime->GetPreAllocatedOutOfMemoryErrorWhenHandlingStackOverflow());
image_roots->Set<false>(ImageHeader::kNoClassDefFoundError,
runtime->GetPreAllocatedNoClassDefFoundError());
- // image_roots[ImageHeader::kClassLoader] will be set later for app image.
- static_assert(ImageHeader::kClassLoader + 1u == ImageHeader::kImageRootsMax,
- "Class loader should be the last image root.");
- for (int32_t i = 0; i < ImageHeader::kImageRootsMax - 1; ++i) {
+ if (!compile_app_image_) {
+ ObjPtr<ObjectArray<Object>> boot_image_live_objects =
+ CollectBootImageLiveObjects(self, class_linker);
+ image_roots->Set<false>(ImageHeader::kBootImageLiveObjects, boot_image_live_objects);
+ }
+ for (int32_t i = 0, num = ImageHeader::NumberOfImageRoots(compile_app_image_); i != num; ++i) {
+ if (compile_app_image_ && i == ImageHeader::kAppImageClassLoader) {
+ // image_roots[ImageHeader::kAppImageClassLoader] will be set later for app image.
+ continue;
+ }
CHECK(image_roots->Get(i) != nullptr);
}
return image_roots.Get();
@@ -1781,7 +1832,7 @@ void ImageWriter::CalculateNewObjectOffsets() {
CHECK_EQ(class_loaders_.size(), 1u);
CHECK_EQ(image_roots.size(), 1u);
CHECK(*class_loaders_.begin() != nullptr);
- image_roots[0]->Set<false>(ImageHeader::kClassLoader, *class_loaders_.begin());
+ image_roots[0]->Set<false>(ImageHeader::kAppImageClassLoader, *class_loaders_.begin());
}
// Verify that all objects have assigned image bin slots.
diff --git a/dex2oat/linker/image_writer.h b/dex2oat/linker/image_writer.h
index 960d698689..c282a2ade8 100644
--- a/dex2oat/linker/image_writer.h
+++ b/dex2oat/linker/image_writer.h
@@ -450,6 +450,8 @@ class ImageWriter FINAL {
REQUIRES_SHARED(Locks::mutator_lock_);
void CreateHeader(size_t oat_index)
REQUIRES_SHARED(Locks::mutator_lock_);
+ ObjPtr<mirror::ObjectArray<mirror::Object>> CollectDexCaches(Thread* self, size_t oat_index) const
+ REQUIRES_SHARED(Locks::mutator_lock_);
mirror::ObjectArray<mirror::Object>* CreateImageRoots(size_t oat_index) const
REQUIRES_SHARED(Locks::mutator_lock_);
void CalculateObjectBinSlots(mirror::Object* obj)
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index be636d80a8..45332c8a1a 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -990,8 +990,7 @@ bool ClassLinker::InitFromBootImage(std::string* error_msg) {
class_roots_ = GcRoot<mirror::ObjectArray<mirror::Class>>(
ObjPtr<mirror::ObjectArray<mirror::Class>>::DownCast(MakeObjPtr(
spaces[0]->GetImageHeader().GetImageRoot(ImageHeader::kClassRoots))));
- DCHECK_EQ(GetClassRoot(ClassRoot::kJavaLangClass, this)->GetClassFlags(),
- mirror::kClassFlagClass);
+ 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));
@@ -1610,10 +1609,9 @@ bool ClassLinker::AddImageSpace(
hs.NewHandle(dex_caches_object->AsObjectArray<mirror::DexCache>()));
Handle<mirror::ObjectArray<mirror::Class>> class_roots(hs.NewHandle(
header.GetImageRoot(ImageHeader::kClassRoots)->AsObjectArray<mirror::Class>()));
- static_assert(ImageHeader::kClassLoader + 1u == ImageHeader::kImageRootsMax,
- "Class loader should be the last image root.");
MutableHandle<mirror::ClassLoader> image_class_loader(hs.NewHandle(
- app_image ? header.GetImageRoot(ImageHeader::kClassLoader)->AsClassLoader() : nullptr));
+ app_image ? header.GetImageRoot(ImageHeader::kAppImageClassLoader)->AsClassLoader()
+ : nullptr));
DCHECK(class_roots != nullptr);
if (class_roots->GetLength() != static_cast<int32_t>(ClassRoot::kMax)) {
*error_msg = StringPrintf("Expected %d class roots but got %d",
diff --git a/runtime/image.cc b/runtime/image.cc
index 17fc664bd7..7819c0bc00 100644
--- a/runtime/image.cc
+++ b/runtime/image.cc
@@ -26,7 +26,7 @@
namespace art {
const uint8_t ImageHeader::kImageMagic[] = { 'a', 'r', 't', '\n' };
-const uint8_t ImageHeader::kImageVersion[] = { '0', '6', '1', '\0' }; // Pre-allocated Throwables.
+const uint8_t ImageHeader::kImageVersion[] = { '0', '6', '2', '\0' }; // Boot image live objects.
ImageHeader::ImageHeader(uint32_t image_begin,
uint32_t image_size,
diff --git a/runtime/image.h b/runtime/image.h
index c6fc052a60..c1cde0a74a 100644
--- a/runtime/image.h
+++ b/runtime/image.h
@@ -211,8 +211,12 @@ class PACKED(4) ImageHeader {
kOomeWhenThrowingOome, // Pre-allocated OOME when throwing OOME.
kOomeWhenHandlingStackOverflow, // Pre-allocated OOME when handling StackOverflowError.
kNoClassDefFoundError, // Pre-allocated NoClassDefFoundError.
- kClassLoader, // App image only.
+ kSpecialRoots, // Different for boot image and app image, see aliases below.
kImageRootsMax,
+
+ // Aliases.
+ kAppImageClassLoader = kSpecialRoots, // The class loader used to build the app image.
+ kBootImageLiveObjects = kSpecialRoots, // Array of boot image objects that must be kept live.
};
enum ImageSections {
@@ -229,8 +233,10 @@ class PACKED(4) ImageHeader {
kSectionCount, // Number of elements in enum.
};
- static size_t NumberOfImageRoots(bool app_image) {
- return app_image ? kImageRootsMax : kImageRootsMax - 1u;
+ static size_t NumberOfImageRoots(bool app_image ATTRIBUTE_UNUSED) {
+ // At the moment, boot image and app image have the same number of roots,
+ // though the meaning of the kSpecialRoots is different.
+ return kImageRootsMax;
}
ArtMethod* GetImageMethod(ImageMethod index) const;
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 1e327fc8ed..b4dfc1195d 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -2045,6 +2045,7 @@ void Runtime::VisitNonThreadRoots(RootVisitor* visitor) {
pre_allocated_OutOfMemoryError_when_handling_stack_overflow_
.VisitRootIfNonNull(visitor, RootInfo(kRootVMInternal));
pre_allocated_NoClassDefFoundError_.VisitRootIfNonNull(visitor, RootInfo(kRootVMInternal));
+ VisitImageRoots(visitor);
verifier::MethodVerifier::VisitStaticRoots(visitor);
VisitTransactionRoots(visitor);
}