summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Nicolas Geoffray <ngeoffray@google.com> 2023-11-12 21:10:16 +0000
committer Nicolas Geoffray <ngeoffray@google.com> 2023-11-17 11:02:27 +0000
commitcac08ecc868cc9b0b378cf380b1a18185708f4ca (patch)
tree50e2a527acf1f160c02279e16ca46b75ca658a62
parentd36e307dbf3e71f03aab1ccbcfdac35234d4e7a9 (diff)
Put all cached boxed values into boot_image_live_objects.
Test: test.py Change-Id: I16dc434207334aad4768e26704ce20dc98a31f6a
-rw-r--r--compiler/optimizing/intrinsic_objects.cc76
-rw-r--r--compiler/optimizing/intrinsic_objects.h58
-rw-r--r--compiler/optimizing/intrinsics.cc23
-rw-r--r--dex2oat/linker/image_writer.cc22
-rw-r--r--runtime/art_field.h6
-rw-r--r--runtime/well_known_classes.cc32
-rw-r--r--runtime/well_known_classes.h6
7 files changed, 139 insertions, 84 deletions
diff --git a/compiler/optimizing/intrinsic_objects.cc b/compiler/optimizing/intrinsic_objects.cc
index d7042d22c8..7c430acbe4 100644
--- a/compiler/optimizing/intrinsic_objects.cc
+++ b/compiler/optimizing/intrinsic_objects.cc
@@ -29,16 +29,41 @@ namespace art HIDDEN {
static constexpr size_t kIntrinsicObjectsOffset =
enum_cast<size_t>(ImageHeader::kIntrinsicObjectsStart);
-ObjPtr<mirror::ObjectArray<mirror::Object>> IntrinsicObjects::LookupIntegerCache() {
- ArtField* cache_field = WellKnownClasses::java_lang_Integer_IntegerCache_cache;
- ObjPtr<mirror::Class> integer_cache_class = cache_field->GetDeclaringClass();
- DCHECK(integer_cache_class->IsInitialized());
- ObjPtr<mirror::ObjectArray<mirror::Object>> integer_cache =
+template <typename T>
+static void FillIntrinsicsObjects(
+ ArtField* cache_field,
+ ObjPtr<mirror::ObjectArray<mirror::Object>> live_objects,
+ int32_t expected_low,
+ int32_t expected_high,
+ T type_check,
+ size_t& index)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ ObjPtr<mirror::ObjectArray<mirror::Object>> cache =
ObjPtr<mirror::ObjectArray<mirror::Object>>::DownCast(
- cache_field->GetObject(integer_cache_class));
- CHECK(integer_cache != nullptr);
- DCHECK(IntrinsicVisitor::CheckIntegerCacheFields(integer_cache));
- return integer_cache;
+ cache_field->GetObject(cache_field->GetDeclaringClass()));
+ DCHECK_EQ(expected_high - expected_low + 1, cache->GetLength());
+ for (int32_t i = 0, length = cache->GetLength(); i != length; ++i) {
+ live_objects->Set(index++, cache->Get(i));
+ type_check(cache->Get(i), expected_low++);
+ }
+}
+
+void IntrinsicObjects::FillIntrinsicObjects(
+ ObjPtr<mirror::ObjectArray<mirror::Object>> boot_image_live_objects, size_t start_index) {
+ DCHECK_EQ(start_index, ImageHeader::kIntrinsicObjectsStart);
+ size_t index = start_index;
+#define FILL_OBJECTS(name, low, high, type, offset) \
+ FillIntrinsicsObjects( \
+ WellKnownClasses::java_lang_ ##name ##_ ##name ##Cache_cache, \
+ boot_image_live_objects, \
+ low, \
+ high, \
+ [](ObjPtr<mirror::Object> obj, int32_t expected) REQUIRES_SHARED(Locks::mutator_lock_) { \
+ CHECK_EQ(expected, WellKnownClasses::java_lang_ ##name ##_value->Get ##name(obj)); \
+ }, \
+ index);
+ BOXED_TYPES(FILL_OBJECTS)
+#undef FILL_OBJECTS
}
static bool HasIntrinsicObjects(
@@ -50,43 +75,26 @@ static bool HasIntrinsicObjects(
return length != kIntrinsicObjectsOffset;
}
-ObjPtr<mirror::ObjectArray<mirror::Object>> IntrinsicObjects::GetIntegerValueOfCache(
- ObjPtr<mirror::ObjectArray<mirror::Object>> boot_image_live_objects) {
- 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>(
- kIntrinsicObjectsOffset);
- DCHECK(result != nullptr);
- DCHECK(result->IsObjectArray());
- DCHECK(result->GetClass()->DescriptorEquals("[Ljava/lang/Integer;"));
- return ObjPtr<mirror::ObjectArray<mirror::Object>>::DownCast(result);
-}
-
-ObjPtr<mirror::Object> IntrinsicObjects::GetIntegerValueOfObject(
+ObjPtr<mirror::Object> IntrinsicObjects::GetValueOfObject(
ObjPtr<mirror::ObjectArray<mirror::Object>> boot_image_live_objects,
+ size_t start_index,
uint32_t index) {
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>(
- kIntrinsicObjectsOffset + /* skip the IntegerCache.cache */ 1u + index);
+ kIntrinsicObjectsOffset + start_index + index);
DCHECK(result != nullptr);
- DCHECK(result->GetClass()->DescriptorEquals("Ljava/lang/Integer;"));
return result;
}
-MemberOffset IntrinsicObjects::GetIntegerValueOfArrayDataOffset(
- ObjPtr<mirror::ObjectArray<mirror::Object>> boot_image_live_objects) {
+MemberOffset IntrinsicObjects::GetValueOfArrayDataOffset(
+ ObjPtr<mirror::ObjectArray<mirror::Object>> boot_image_live_objects,
+ size_t start_index) {
DCHECK(HasIntrinsicObjects(boot_image_live_objects));
MemberOffset result =
- mirror::ObjectArray<mirror::Object>::OffsetOfElement(kIntrinsicObjectsOffset + 1u);
- DCHECK_EQ(GetIntegerValueOfObject(boot_image_live_objects, 0u),
+ mirror::ObjectArray<mirror::Object>::OffsetOfElement(kIntrinsicObjectsOffset + start_index);
+ DCHECK_EQ(GetValueOfObject(boot_image_live_objects, start_index, 0u),
(boot_image_live_objects
->GetFieldObject<mirror::Object, kVerifyNone, kWithoutReadBarrier>(result)));
return result;
diff --git a/compiler/optimizing/intrinsic_objects.h b/compiler/optimizing/intrinsic_objects.h
index 1cc8f4dbc3..61f4825224 100644
--- a/compiler/optimizing/intrinsic_objects.h
+++ b/compiler/optimizing/intrinsic_objects.h
@@ -21,11 +21,12 @@
#include "base/bit_utils.h"
#include "base/macros.h"
#include "base/mutex.h"
+#include "obj_ptr.h"
+#include "offsets.h"
namespace art HIDDEN {
class ClassLinker;
-template <class MirrorType> class ObjPtr;
class MemberOffset;
class Thread;
@@ -34,6 +35,20 @@ class Object;
template <class T> class ObjectArray;
} // namespace mirror
+#define BOXED_TYPES(V) \
+ V(Byte, -128, 127, DataType::Type::kInt8, 0) \
+ V(Short, -128, 127, DataType::Type::kInt16, kByteCacheLastIndex) \
+ V(Character, 0, 127, DataType::Type::kUint16, kShortCacheLastIndex) \
+ V(Integer, -128, 127, DataType::Type::kInt32, kCharacterCacheLastIndex)
+
+#define DEFINE_BOXED_CONSTANTS(name, low, high, primitive_type, start_index) \
+ static constexpr size_t k ##name ##CacheLastIndex = start_index + (high - low + 1); \
+ static constexpr size_t k ##name ##CacheFirstIndex = start_index;
+ BOXED_TYPES(DEFINE_BOXED_CONSTANTS)
+
+ static constexpr size_t kNumberOfBoxedCaches = kIntegerCacheLastIndex;
+#undef DEFINE_BOXED_CONSTANTS
+
class IntrinsicObjects {
public:
enum class PatchType {
@@ -56,25 +71,44 @@ class IntrinsicObjects {
return IndexField::Decode(intrinsic_data);
}
- // Functions for retrieving data for Integer.valueOf().
- EXPORT static ObjPtr<mirror::ObjectArray<mirror::Object>> LookupIntegerCache()
- REQUIRES_SHARED(Locks::mutator_lock_);
- EXPORT static ObjPtr<mirror::ObjectArray<mirror::Object>> GetIntegerValueOfCache(
- ObjPtr<mirror::ObjectArray<mirror::Object>> boot_image_live_objects)
- REQUIRES_SHARED(Locks::mutator_lock_);
- EXPORT static ObjPtr<mirror::Object> GetIntegerValueOfObject(
- ObjPtr<mirror::ObjectArray<mirror::Object>> boot_image_live_objects,
- uint32_t index) REQUIRES_SHARED(Locks::mutator_lock_);
- EXPORT static MemberOffset GetIntegerValueOfArrayDataOffset(
- ObjPtr<mirror::ObjectArray<mirror::Object>> boot_image_live_objects)
+ // Helpers returning addresses of objects, suitable for embedding in generated code.
+#define DEFINE_BOXED_ACCESSES(name, _, __, ___, start_index) \
+ static ObjPtr<mirror::Object> Get ##name ##ValueOfObject( \
+ ObjPtr<mirror::ObjectArray<mirror::Object>> boot_image_live_objects, \
+ uint32_t index) REQUIRES_SHARED(Locks::mutator_lock_) { \
+ return GetValueOfObject(boot_image_live_objects, k ##name ##CacheFirstIndex, index); \
+ } \
+ static MemberOffset Get ##name ##ValueOfArrayDataOffset( \
+ ObjPtr<mirror::ObjectArray<mirror::Object>> boot_image_live_objects) \
+ REQUIRES_SHARED(Locks::mutator_lock_) { \
+ return GetValueOfArrayDataOffset(boot_image_live_objects, k ##name ##CacheFirstIndex); \
+ }
+ BOXED_TYPES(DEFINE_BOXED_ACCESSES)
+#undef DEFINED_BOXED_ACCESSES
+
+ EXPORT static void FillIntrinsicObjects(
+ ObjPtr<mirror::ObjectArray<mirror::Object>> boot_image_live_objects, size_t start_index)
REQUIRES_SHARED(Locks::mutator_lock_);
+ static size_t GetNumberOfIntrinsicObjects() {
+ return kNumberOfBoxedCaches;
+ }
+
private:
static constexpr size_t kPatchTypeBits =
MinimumBitsToStore(static_cast<uint32_t>(PatchType::kLast));
static constexpr size_t kIndexBits = BitSizeOf<uint32_t>() - kPatchTypeBits;
using PatchTypeField = BitField<uint32_t, 0u, kPatchTypeBits>;
using IndexField = BitField<uint32_t, kPatchTypeBits, kIndexBits>;
+
+ EXPORT static ObjPtr<mirror::Object> GetValueOfObject(
+ ObjPtr<mirror::ObjectArray<mirror::Object>> boot_image_live_objects,
+ size_t start_index,
+ uint32_t index) REQUIRES_SHARED(Locks::mutator_lock_);
+
+ EXPORT static MemberOffset GetValueOfArrayDataOffset(
+ ObjPtr<mirror::ObjectArray<mirror::Object>> boot_image_live_objects,
+ size_t start_index) REQUIRES_SHARED(Locks::mutator_lock_);
};
} // namespace art
diff --git a/compiler/optimizing/intrinsics.cc b/compiler/optimizing/intrinsics.cc
index 39d10b819d..e443a51889 100644
--- a/compiler/optimizing/intrinsics.cc
+++ b/compiler/optimizing/intrinsics.cc
@@ -115,11 +115,8 @@ bool IntrinsicVisitor::CheckIntegerCacheFields(ObjPtr<mirror::ObjectArray<mirror
return true;
}
-static bool CheckIntegerCache(ObjPtr<mirror::ObjectArray<mirror::Object>> boot_image_live_objects,
- ObjPtr<mirror::ObjectArray<mirror::Object>> boot_image_cache)
+static bool CheckIntegerCache(ObjPtr<mirror::ObjectArray<mirror::Object>> boot_image_live_objects)
REQUIRES_SHARED(Locks::mutator_lock_) {
- DCHECK(boot_image_cache != nullptr);
-
// Since we have a cache in the boot image, both java.lang.Integer and
// java.lang.Integer$IntegerCache must be initialized in the boot image.
ObjPtr<mirror::Class> cache_class = WellKnownClasses::java_lang_Integer_IntegerCache.Get();
@@ -127,12 +124,8 @@ static bool CheckIntegerCache(ObjPtr<mirror::ObjectArray<mirror::Object>> boot_i
ObjPtr<mirror::Class> integer_class = WellKnownClasses::java_lang_Integer.Get();
DCHECK(integer_class->IsInitialized());
- // Check that the current cache is the same as the `boot_image_cache`.
- ObjPtr<mirror::ObjectArray<mirror::Object>> current_cache = GetIntegerCacheArray(cache_class);
- if (current_cache != boot_image_cache) {
- return false; // Messed up IntegerCache.cache.
- }
- if (!IntrinsicVisitor::CheckIntegerCacheFields(current_cache)) {
+ ObjPtr<mirror::ObjectArray<mirror::Object>> boot_image_cache = GetIntegerCacheArray(cache_class);
+ if (!IntrinsicVisitor::CheckIntegerCacheFields(boot_image_cache)) {
return false;
}
@@ -220,13 +213,7 @@ void IntrinsicVisitor::ComputeIntegerValueOfLocations(HInvoke* invoke,
} else {
ScopedObjectAccess soa(Thread::Current());
ObjPtr<mirror::ObjectArray<mirror::Object>> boot_image_live_objects = GetBootImageLiveObjects();
- ObjPtr<mirror::ObjectArray<mirror::Object>> cache =
- IntrinsicObjects::GetIntegerValueOfCache(boot_image_live_objects);
- if (cache == nullptr) {
- return; // No cache in the boot image.
- }
- DCHECK_IMPLIES(compiler_options.IsAotCompiler(),
- CheckIntegerCache(boot_image_live_objects, cache));
+ DCHECK_IMPLIES(compiler_options.IsAotCompiler(), CheckIntegerCache(boot_image_live_objects));
if (input->IsIntConstant()) {
if (kIsDebugBuild) {
@@ -314,8 +301,6 @@ IntrinsicVisitor::IntegerValueOfInfo IntrinsicVisitor::ComputeIntegerValueOfInfo
ArtField* value_field = integer_class->FindDeclaredInstanceField(kValueFieldName, "I");
DCHECK(value_field != nullptr);
info.value_offset = value_field->GetOffset().Uint32Value();
- DCHECK_EQ(info.length, dchecked_integral_cast<uint32_t>(
- IntrinsicObjects::GetIntegerValueOfCache(boot_image_live_objects)->GetLength()));
if (invoke->InputAt(0)->IsIntConstant()) {
int32_t input_value = invoke->InputAt(0)->AsIntConstant()->GetValue();
diff --git a/dex2oat/linker/image_writer.cc b/dex2oat/linker/image_writer.cc
index fac273c4da..b1ed99712b 100644
--- a/dex2oat/linker/image_writer.cc
+++ b/dex2oat/linker/image_writer.cc
@@ -355,15 +355,13 @@ HashMap<mirror::Object*, uint32_t> MatchDirtyObjectPaths(
static 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
+ // The objects used for intrinsics 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());
size_t live_objects_size =
enum_cast<size_t>(ImageHeader::kIntrinsicObjectsStart) +
- ((integer_cache != nullptr) ? (/* cache */ 1u + integer_cache->GetLength()) : 0u);
+ IntrinsicObjects::GetNumberOfIntrinsicObjects();
ObjPtr<mirror::ObjectArray<mirror::Object>> live_objects =
mirror::ObjectArray<mirror::Object>::Alloc(
self, GetClassRoot<mirror::ObjectArray<mirror::Object>>(class_linker), live_objects_size);
@@ -387,21 +385,7 @@ static ObjPtr<mirror::ObjectArray<mirror::Object>> AllocateBootImageLiveObjects(
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));
- }
- }
+ IntrinsicObjects::FillIntrinsicObjects(live_objects, index);
return live_objects;
}
diff --git a/runtime/art_field.h b/runtime/art_field.h
index c205920833..8a771af126 100644
--- a/runtime/art_field.h
+++ b/runtime/art_field.h
@@ -124,6 +124,9 @@ class ArtField final {
void SetByte(ObjPtr<mirror::Object> object, int8_t b) REQUIRES_SHARED(Locks::mutator_lock_);
uint16_t GetChar(ObjPtr<mirror::Object> object) REQUIRES_SHARED(Locks::mutator_lock_);
+ uint16_t GetCharacter(ObjPtr<mirror::Object> object) REQUIRES_SHARED(Locks::mutator_lock_) {
+ return GetChar(object);
+ }
template<bool kTransactionActive>
void SetChar(ObjPtr<mirror::Object> object, uint16_t c) REQUIRES_SHARED(Locks::mutator_lock_);
@@ -134,6 +137,9 @@ class ArtField final {
void SetShort(ObjPtr<mirror::Object> object, int16_t s) REQUIRES_SHARED(Locks::mutator_lock_);
int32_t GetInt(ObjPtr<mirror::Object> object) REQUIRES_SHARED(Locks::mutator_lock_);
+ int32_t GetInteger(ObjPtr<mirror::Object> object) REQUIRES_SHARED(Locks::mutator_lock_) {
+ return GetInt(object);
+ }
template<bool kTransactionActive>
void SetInt(ObjPtr<mirror::Object> object, int32_t i) REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc
index 49074e8e7f..7c77af9479 100644
--- a/runtime/well_known_classes.cc
+++ b/runtime/well_known_classes.cc
@@ -168,6 +168,12 @@ ArtField* WellKnownClasses::java_lang_Short_ShortCache_cache;
ArtField* WellKnownClasses::java_lang_Integer_IntegerCache_cache;
ArtField* WellKnownClasses::java_lang_Long_LongCache_cache;
+ArtField* WellKnownClasses::java_lang_Byte_value;
+ArtField* WellKnownClasses::java_lang_Character_value;
+ArtField* WellKnownClasses::java_lang_Short_value;
+ArtField* WellKnownClasses::java_lang_Integer_value;
+ArtField* WellKnownClasses::java_lang_Long_value;
+
static ObjPtr<mirror::Class> FindSystemClass(ClassLinker* class_linker,
Thread* self,
const char* descriptor)
@@ -241,6 +247,15 @@ static ArtField* CacheBoxingCacheField(ClassLinker* class_linker,
return CacheField(boxed_class, /*is_static=*/ true, "cache", cache_type);
}
+static ArtField* CacheValueInBoxField(ClassLinker* class_linker,
+ Thread* self,
+ const char* class_name,
+ const char* cache_type)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ ObjPtr<mirror::Class> boxed_class = FindSystemClass(class_linker, self, class_name);
+ return CacheField(boxed_class, /*is_static=*/ false, "value", cache_type);
+}
+
#define STRING_INIT_LIST(V) \
V(java_lang_String_init, "()V", newEmptyString, "newEmptyString", "()Ljava/lang/String;", NewEmptyString) \
V(java_lang_String_init_B, "([B)V", newStringFromBytes_B, "newStringFromBytes", "([B)Ljava/lang/String;", NewStringFromBytes_B) \
@@ -388,6 +403,17 @@ void WellKnownClasses::InitFieldsAndMethodsOnly(JNIEnv* env) {
java_lang_Long_LongCache_cache = CacheBoxingCacheField(
class_linker, self, "Ljava/lang/Long$LongCache;", "[Ljava/lang/Long;");
+ java_lang_Byte_value = CacheValueInBoxField(
+ class_linker, self, "Ljava/lang/Byte;", "B");
+ java_lang_Character_value = CacheValueInBoxField(
+ class_linker, self, "Ljava/lang/Character;", "C");
+ java_lang_Short_value = CacheValueInBoxField(
+ class_linker, self, "Ljava/lang/Short;", "S");
+ java_lang_Integer_value = CacheValueInBoxField(
+ class_linker, self, "Ljava/lang/Integer;", "I");
+ java_lang_Long_value = CacheValueInBoxField(
+ class_linker, self, "Ljava/lang/Long;", "J");
+
StackHandleScope<42u> hs(self);
Handle<mirror::Class> d_s_bdcl =
hs.NewHandle(FindSystemClass(class_linker, self, "Ldalvik/system/BaseDexClassLoader;"));
@@ -940,6 +966,12 @@ void WellKnownClasses::Clear() {
java_lang_Short_ShortCache_cache = nullptr;
java_lang_Integer_IntegerCache_cache = nullptr;
java_lang_Long_LongCache_cache = nullptr;
+
+ java_lang_Byte_value = nullptr;
+ java_lang_Character_value = nullptr;
+ java_lang_Short_value = nullptr;
+ java_lang_Integer_value = nullptr;
+ java_lang_Long_value = nullptr;
}
ObjPtr<mirror::Class> WellKnownClasses::ToClass(jclass global_jclass) {
diff --git a/runtime/well_known_classes.h b/runtime/well_known_classes.h
index 6ef5f6d3d9..f717030d82 100644
--- a/runtime/well_known_classes.h
+++ b/runtime/well_known_classes.h
@@ -213,6 +213,12 @@ struct WellKnownClasses {
static ArtField* java_lang_Integer_IntegerCache_cache;
static ArtField* java_lang_Long_LongCache_cache;
+ static ArtField* java_lang_Byte_value;
+ static ArtField* java_lang_Character_value;
+ static ArtField* java_lang_Short_value;
+ static ArtField* java_lang_Integer_value;
+ static ArtField* java_lang_Long_value;
+
static constexpr ClassFromField<&dalvik_system_BaseDexClassLoader_pathList>
dalvik_system_BaseDexClassLoader;
static constexpr ClassFromMethod<&dalvik_system_DelegateLastClassLoader_init>