diff options
author | 2014-02-10 16:19:09 -0800 | |
---|---|---|
committer | 2014-02-11 13:16:20 -0800 | |
commit | 4d2efce8bf1947880b90efc44448b4940c8016fb (patch) | |
tree | 61adad3b981719a12d00aa9be44f76c004dd44c4 | |
parent | 6b3697fec487b355d107b693c965919bf5fff906 (diff) |
Don't hardcode object layout in Unsafe and space_test.
Add a test for Unsafe.arrayBaseOffset() and Unsafe.arrayIndexScale().
Change-Id: I9cbdb79a4a7ee055129f41811a117910c8b2febd
-rw-r--r-- | build/Android.libarttest.mk | 3 | ||||
-rw-r--r-- | runtime/gc/space/space_test.cc | 27 | ||||
-rw-r--r-- | runtime/interpreter/interpreter.cc | 8 | ||||
-rw-r--r-- | runtime/native/sun_misc_Unsafe.cc | 17 | ||||
-rw-r--r-- | test/Android.mk | 3 | ||||
-rw-r--r-- | test/UnsafeTest/UnsafeTest.java | 78 | ||||
-rw-r--r-- | test/UnsafeTest/unsafe_test.cc | 40 |
7 files changed, 165 insertions, 11 deletions
diff --git a/build/Android.libarttest.mk b/build/Android.libarttest.mk index f946d919cf..65b78c959a 100644 --- a/build/Android.libarttest.mk +++ b/build/Android.libarttest.mk @@ -17,7 +17,8 @@ LIBARTTEST_COMMON_SRC_FILES := \ test/JniTest/jni_test.cc \ test/ReferenceMap/stack_walk_refmap_jni.cc \ - test/StackWalk/stack_walk_jni.cc + test/StackWalk/stack_walk_jni.cc \ + test/UnsafeTest/unsafe_test.cc # $(1): target or host define build-libarttest diff --git a/runtime/gc/space/space_test.cc b/runtime/gc/space/space_test.cc index 9989ffefaf..6d07a609f2 100644 --- a/runtime/gc/space/space_test.cc +++ b/runtime/gc/space/space_test.cc @@ -39,20 +39,23 @@ class SpaceTest : public CommonTest { 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 @@ void SpaceTest::AllocAndFreeListTestBody(CreateSpaceFn create_space) { 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 @@ void SpaceTest::SizeFootPrintGrowthLimitAndTrimBody(MallocSpace* space, intptr_t 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::SizeFootPrintGrowthLimitAndTrimBody(MallocSpace* space, intptr_t } 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 922e642630..c6faf4493f 100644 --- a/runtime/interpreter/interpreter.cc +++ b/runtime/interpreter/interpreter.cc @@ -80,6 +80,14 @@ static void UnstartedRuntimeJni(Thread* self, ArtMethod* method, 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 6c22003396..6727862ffe 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 @@ static void Unsafe_putOrderedObject(JNIEnv* env, jobject, jobject javaObj, jlong 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 @@ static JNINativeMethod gMethods[] = { 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) { diff --git a/test/Android.mk b/test/Android.mk index d716f9b5d3..4d47651bf9 100644 --- a/test/Android.mk +++ b/test/Android.mk @@ -50,7 +50,8 @@ TEST_OAT_DIRECTORIES := \ ParallelGC \ ReferenceMap \ StackWalk \ - ThreadStress + ThreadStress \ + UnsafeTest # TODO: Enable when the StackWalk2 tests are passing # StackWalk2 \ diff --git a/test/UnsafeTest/UnsafeTest.java b/test/UnsafeTest/UnsafeTest.java new file mode 100644 index 0000000000..f3d5289627 --- /dev/null +++ b/test/UnsafeTest/UnsafeTest.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.lang.reflect.Field; +import sun.misc.Unsafe; + +public class UnsafeTest { + static { + System.loadLibrary("arttest"); + } + + private static void check(int actual, int expected, String msg) { + if (actual != expected) { + System.logE(msg + " : " + actual + " != " + expected); + System.exit(-1); + } + } + + private static Unsafe getUnsafe() throws Exception { + Class<?> unsafeClass = Class.forName("sun.misc.Unsafe"); + Field f = unsafeClass.getDeclaredField("theUnsafe"); + f.setAccessible(true); + return (Unsafe) f.get(null); + } + + public static void main(String[] args) throws Exception { + Unsafe unsafe = getUnsafe(); + check(unsafe.arrayBaseOffset(boolean[].class), vmArrayBaseOffset(boolean[].class), + "Unsafe.arrayBaseOffset(boolean[])"); + check(unsafe.arrayBaseOffset(byte[].class), vmArrayBaseOffset(byte[].class), + "Unsafe.arrayBaseOffset(byte[])"); + check(unsafe.arrayBaseOffset(char[].class), vmArrayBaseOffset(char[].class), + "Unsafe.arrayBaseOffset(char[])"); + check(unsafe.arrayBaseOffset(double[].class), vmArrayBaseOffset(double[].class), + "Unsafe.arrayBaseOffset(double[])"); + check(unsafe.arrayBaseOffset(float[].class), vmArrayBaseOffset(float[].class), + "Unsafe.arrayBaseOffset(float[])"); + check(unsafe.arrayBaseOffset(int[].class), vmArrayBaseOffset(int[].class), + "Unsafe.arrayBaseOffset(int[])"); + check(unsafe.arrayBaseOffset(long[].class), vmArrayBaseOffset(long[].class), + "Unsafe.arrayBaseOffset(long[])"); + check(unsafe.arrayBaseOffset(Object[].class), vmArrayBaseOffset(Object[].class), + "Unsafe.arrayBaseOffset(Object[])"); + + check(unsafe.arrayIndexScale(boolean[].class), vmArrayIndexScale(boolean[].class), + "Unsafe.arrayIndexScale(boolean[])"); + check(unsafe.arrayIndexScale(byte[].class), vmArrayIndexScale(byte[].class), + "Unsafe.arrayIndexScale(byte[])"); + check(unsafe.arrayIndexScale(char[].class), vmArrayIndexScale(char[].class), + "Unsafe.arrayIndexScale(char[])"); + check(unsafe.arrayIndexScale(double[].class), vmArrayIndexScale(double[].class), + "Unsafe.arrayIndexScale(double[])"); + check(unsafe.arrayIndexScale(float[].class), vmArrayIndexScale(float[].class), + "Unsafe.arrayIndexScale(float[])"); + check(unsafe.arrayIndexScale(int[].class), vmArrayIndexScale(int[].class), + "Unsafe.arrayIndexScale(int[])"); + check(unsafe.arrayIndexScale(long[].class), vmArrayIndexScale(long[].class), + "Unsafe.arrayIndexScale(long[])"); + check(unsafe.arrayIndexScale(Object[].class), vmArrayIndexScale(Object[].class), + "Unsafe.arrayIndexScale(Object[])"); + } + + private static native int vmArrayBaseOffset(Class clazz); + private static native int vmArrayIndexScale(Class clazz); +} diff --git a/test/UnsafeTest/unsafe_test.cc b/test/UnsafeTest/unsafe_test.cc new file mode 100644 index 0000000000..e36ee149f0 --- /dev/null +++ b/test/UnsafeTest/unsafe_test.cc @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "jni.h" +#include "mirror/array.h" +#include "mirror/art_method-inl.h" +#include "mirror/class.h" +#include "mirror/class-inl.h" +#include "mirror/object-inl.h" +#include "scoped_thread_state_change.h" + +namespace art { + +extern "C" JNIEXPORT jint JNICALL Java_UnsafeTest_vmArrayBaseOffset(JNIEnv* env, jclass, jobject classObj) { + ScopedObjectAccess soa(env); + mirror::Class* klass = soa.Decode<mirror::Class*>(classObj); + return mirror::Array::DataOffset( + Primitive::ComponentSize(klass->GetComponentType()->GetPrimitiveType())).Int32Value(); +} + +extern "C" JNIEXPORT jint JNICALL Java_UnsafeTest_vmArrayIndexScale(JNIEnv* env, jclass, jobject classObj) { + ScopedObjectAccess soa(env); + mirror::Class* klass = soa.Decode<mirror::Class*>(classObj); + return Primitive::ComponentSize(klass->GetComponentType()->GetPrimitiveType()); +} + +} // namespace art |