Don't hardcode object layout in Unsafe and space_test.
Add a test for Unsafe.arrayBaseOffset() and Unsafe.arrayIndexScale().
Change-Id: I9cbdb79a4a7ee055129f41811a117910c8b2febd
diff --git a/runtime/gc/space/space_test.cc b/runtime/gc/space/space_test.cc
index 9989ffe..6d07a60 100644
--- a/runtime/gc/space/space_test.cc
+++ b/runtime/gc/space/space_test.cc
@@ -39,20 +39,23 @@
Runtime::Current()->GetHeap()->AddSpace(space);
}
void InstallClass(mirror::Object* o, size_t size) NO_THREAD_SAFETY_ANALYSIS {
- // Note the minimum size, which is the size of a zero-length byte array, is 12.
- EXPECT_GE(size, static_cast<size_t>(12));
+ // Note the minimum size, which is the size of a zero-length byte array.
+ EXPECT_GE(size, SizeOfZeroLengthByteArray());
SirtRef<mirror::ClassLoader> null_loader(Thread::Current(), NULL);
mirror::Class* byte_array_class = Runtime::Current()->GetClassLinker()->FindClass("[B", null_loader);
EXPECT_TRUE(byte_array_class != NULL);
o->SetClass(byte_array_class);
mirror::Array* arr = o->AsArray();
- // size_t header_size = sizeof(mirror::Object) + 4;
- size_t header_size = arr->DataOffset(1).Uint32Value();
+ size_t header_size = SizeOfZeroLengthByteArray();
int32_t length = size - header_size;
arr->SetLength(length);
EXPECT_EQ(arr->SizeOf(), size);
}
+ static size_t SizeOfZeroLengthByteArray() {
+ return mirror::Array::DataOffset(Primitive::ComponentSize(Primitive::kPrimByte)).Uint32Value();
+ }
+
static MallocSpace* CreateDlMallocSpace(const std::string& name, size_t initial_size, size_t growth_limit,
size_t capacity, byte* requested_begin) {
return DlMallocSpace::Create(name, initial_size, growth_limit, capacity, requested_begin);
@@ -355,9 +358,10 @@
mirror::Object* lots_of_objects[1024];
for (size_t i = 0; i < arraysize(lots_of_objects); i++) {
size_t allocation_size = 0;
- lots_of_objects[i] = space->Alloc(self, 16, &allocation_size);
+ size_t size_of_zero_length_byte_array = SizeOfZeroLengthByteArray();
+ lots_of_objects[i] = space->Alloc(self, size_of_zero_length_byte_array, &allocation_size);
EXPECT_TRUE(lots_of_objects[i] != nullptr);
- InstallClass(lots_of_objects[i], 16);
+ InstallClass(lots_of_objects[i], size_of_zero_length_byte_array);
EXPECT_EQ(allocation_size, space->AllocationSize(lots_of_objects[i]));
}
@@ -436,9 +440,10 @@
alloc_size = object_size;
} else {
alloc_size = test_rand(&rand_seed) % static_cast<size_t>(-object_size);
- // Note the minimum size, which is the size of a zero-length byte array, is 12.
- if (alloc_size < 12) {
- alloc_size = 12;
+ // Note the minimum size, which is the size of a zero-length byte array.
+ size_t size_of_zero_length_byte_array = SizeOfZeroLengthByteArray();
+ if (alloc_size < size_of_zero_length_byte_array) {
+ alloc_size = size_of_zero_length_byte_array;
}
}
mirror::Object* object;
@@ -562,6 +567,10 @@
}
void SpaceTest::SizeFootPrintGrowthLimitAndTrimDriver(size_t object_size, CreateSpaceFn create_space) {
+ if (object_size < SizeOfZeroLengthByteArray()) {
+ // Too small for the object layout/model.
+ return;
+ }
size_t initial_size = 4 * MB;
size_t growth_limit = 8 * MB;
size_t capacity = 16 * MB;
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index 922e642..c6faf44 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -80,6 +80,14 @@
Object* obj = reinterpret_cast<Object*>(args[0]);
Object* newValue = reinterpret_cast<Object*>(args[3]);
obj->SetFieldObject(MemberOffset((static_cast<uint64_t>(args[2]) << 32) | args[1]), newValue, false);
+ } else if (name == "int sun.misc.Unsafe.getArrayBaseOffsetForComponentType(java.lang.Class)") {
+ mirror::Class* component = reinterpret_cast<Object*>(args[0])->AsClass();
+ Primitive::Type primitive_type = component->GetPrimitiveType();
+ result->SetI(mirror::Array::DataOffset(Primitive::ComponentSize(primitive_type)).Int32Value());
+ } else if (name == "int sun.misc.Unsafe.getArrayIndexScaleForComponentType(java.lang.Class)") {
+ mirror::Class* component = reinterpret_cast<Object*>(args[0])->AsClass();
+ Primitive::Type primitive_type = component->GetPrimitiveType();
+ result->SetI(Primitive::ComponentSize(primitive_type));
} else {
LOG(FATAL) << "Attempt to invoke native method in non-started runtime: " << name;
}
diff --git a/runtime/native/sun_misc_Unsafe.cc b/runtime/native/sun_misc_Unsafe.cc
index 6c22003..6727862 100644
--- a/runtime/native/sun_misc_Unsafe.cc
+++ b/runtime/native/sun_misc_Unsafe.cc
@@ -16,6 +16,7 @@
#include "gc/accounting/card_table-inl.h"
#include "jni_internal.h"
+#include "mirror/array.h"
#include "mirror/object.h"
#include "mirror/object-inl.h"
#include "scoped_fast_native_object_access.h"
@@ -153,6 +154,20 @@
obj->SetFieldObject(MemberOffset(offset), newValue, false);
}
+static jint Unsafe_getArrayBaseOffsetForComponentType(JNIEnv* env, jclass, jobject component_class) {
+ ScopedFastNativeObjectAccess soa(env);
+ mirror::Class* component = soa.Decode<mirror::Class*>(component_class);
+ Primitive::Type primitive_type = component->GetPrimitiveType();
+ return mirror::Array::DataOffset(Primitive::ComponentSize(primitive_type)).Int32Value();
+}
+
+static jint Unsafe_getArrayIndexScaleForComponentType(JNIEnv* env, jclass, jobject component_class) {
+ ScopedFastNativeObjectAccess soa(env);
+ mirror::Class* component = soa.Decode<mirror::Class*>(component_class);
+ Primitive::Type primitive_type = component->GetPrimitiveType();
+ return Primitive::ComponentSize(primitive_type);
+}
+
static JNINativeMethod gMethods[] = {
NATIVE_METHOD(Unsafe, compareAndSwapInt, "!(Ljava/lang/Object;JII)Z"),
NATIVE_METHOD(Unsafe, compareAndSwapLong, "!(Ljava/lang/Object;JJJ)Z"),
@@ -172,6 +187,8 @@
NATIVE_METHOD(Unsafe, getObject, "!(Ljava/lang/Object;J)Ljava/lang/Object;"),
NATIVE_METHOD(Unsafe, putObject, "!(Ljava/lang/Object;JLjava/lang/Object;)V"),
NATIVE_METHOD(Unsafe, putOrderedObject, "!(Ljava/lang/Object;JLjava/lang/Object;)V"),
+ NATIVE_METHOD(Unsafe, getArrayBaseOffsetForComponentType, "!(Ljava/lang/Class;)I"),
+ NATIVE_METHOD(Unsafe, getArrayIndexScaleForComponentType, "!(Ljava/lang/Class;)I"),
};
void register_sun_misc_Unsafe(JNIEnv* env) {