diff options
-rw-r--r-- | dex2oat/linker/image_writer.cc | 10 | ||||
-rw-r--r-- | dex2oat/linker/image_writer.h | 1 | ||||
-rw-r--r-- | runtime/gc/space/image_space.cc | 2 | ||||
-rw-r--r-- | runtime/mirror/array-inl.h | 12 | ||||
-rw-r--r-- | runtime/mirror/array.h | 8 | ||||
-rw-r--r-- | runtime/mirror/class-inl.h | 3 | ||||
-rw-r--r-- | runtime/mirror/class.h | 14 | ||||
-rw-r--r-- | runtime/mirror/class_ext-inl.h | 4 | ||||
-rw-r--r-- | runtime/mirror/object-inl.h | 91 | ||||
-rw-r--r-- | runtime/mirror/object.h | 30 | ||||
-rw-r--r-- | runtime/native/java_lang_System.cc | 28 | ||||
-rw-r--r-- | runtime/native/sun_misc_Unsafe.cc | 24 | ||||
-rw-r--r-- | test/004-UnsafeTest/src/Main.java | 49 | ||||
-rw-r--r-- | test/004-UnsafeTest/unsafe_test.cc | 13 |
14 files changed, 166 insertions, 123 deletions
diff --git a/dex2oat/linker/image_writer.cc b/dex2oat/linker/image_writer.cc index 5ca7f0733d..2b2b02941a 100644 --- a/dex2oat/linker/image_writer.cc +++ b/dex2oat/linker/image_writer.cc @@ -2670,10 +2670,8 @@ void ImageWriter::CopyAndFixupObjects() { void ImageWriter::FixupPointerArray(mirror::Object* dst, mirror::PointerArray* arr, - mirror::Class* klass, Bin array_type) { - CHECK(klass->IsArrayClass()); - CHECK(arr->IsIntArray() || arr->IsLongArray()) << klass->PrettyClass() << " " << arr; + CHECK(arr->IsIntArray() || arr->IsLongArray()) << arr->GetClass()->PrettyClass() << " " << arr; // Fixup int and long pointers for the ArtMethod or ArtField arrays. const size_t num_elements = arr->GetLength(); CopyAndFixupReference( @@ -2879,13 +2877,12 @@ void ImageWriter::FixupObject(Object* orig, Object* copy) { if (kUseBakerReadBarrier) { orig->AssertReadBarrierState(); } - auto* klass = orig->GetClass(); - if (klass->IsIntArrayClass() || klass->IsLongArrayClass()) { + if (orig->IsIntArray() || orig->IsLongArray()) { // Is this a native pointer array? auto it = pointer_arrays_.find(down_cast<mirror::PointerArray*>(orig)); if (it != pointer_arrays_.end()) { // Should only need to fixup every pointer array exactly once. - FixupPointerArray(copy, down_cast<mirror::PointerArray*>(orig), klass, it->second); + FixupPointerArray(copy, down_cast<mirror::PointerArray*>(orig), it->second); pointer_arrays_.erase(it); return; } @@ -2895,6 +2892,7 @@ void ImageWriter::FixupObject(Object* orig, Object* copy) { } else { ObjPtr<mirror::ObjectArray<mirror::Class>> class_roots = Runtime::Current()->GetClassLinker()->GetClassRoots(); + ObjPtr<mirror::Class> klass = orig->GetClass(); if (klass == GetClassRoot<mirror::Method>(class_roots) || klass == GetClassRoot<mirror::Constructor>(class_roots)) { // Need to go update the ArtMethod. diff --git a/dex2oat/linker/image_writer.h b/dex2oat/linker/image_writer.h index 06c694c793..ccd529aa13 100644 --- a/dex2oat/linker/image_writer.h +++ b/dex2oat/linker/image_writer.h @@ -541,7 +541,6 @@ class ImageWriter final { REQUIRES_SHARED(Locks::mutator_lock_); void FixupPointerArray(mirror::Object* dst, mirror::PointerArray* arr, - mirror::Class* klass, Bin array_type) REQUIRES_SHARED(Locks::mutator_lock_); diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc index b46abfbf6e..10f395b49c 100644 --- a/runtime/gc/space/image_space.cc +++ b/runtime/gc/space/image_space.cc @@ -832,7 +832,7 @@ class ImageSpace::Loader { reinterpret_cast<uintptr_t>(array) + kObjectAlignment); // If the bit is not set then the contents have not yet been updated. if (!visited_->Test(contents_bit)) { - array->Fixup<kVerifyNone, kWithoutReadBarrier>(array, pointer_size_, visitor); + array->Fixup<kVerifyNone>(array, pointer_size_, visitor); visited_->Set(contents_bit); } } diff --git a/runtime/mirror/array-inl.h b/runtime/mirror/array-inl.h index 442733234b..a6a5ba298c 100644 --- a/runtime/mirror/array-inl.h +++ b/runtime/mirror/array-inl.h @@ -224,16 +224,14 @@ inline void PrimitiveArray<T>::Memcpy(int32_t dst_pos, } } -template<typename T, VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption> +template<typename T, VerifyObjectFlags kVerifyFlags> inline T PointerArray::GetElementPtrSize(uint32_t idx, PointerSize ptr_size) { // C style casts here since we sometimes have T be a pointer, or sometimes an integer // (for stack traces). if (ptr_size == PointerSize::k64) { - return (T)static_cast<uintptr_t>( - AsLongArray<kVerifyFlags, kReadBarrierOption>()->GetWithoutChecks(idx)); + return (T)static_cast<uintptr_t>(AsLongArray<kVerifyFlags>()->GetWithoutChecks(idx)); } - return (T)static_cast<uintptr_t>(static_cast<uint32_t>( - AsIntArray<kVerifyFlags, kReadBarrierOption>()->GetWithoutChecks(idx))); + return (T)static_cast<uintptr_t>(AsIntArray<kVerifyFlags>()->GetWithoutChecks(idx)); } template<bool kTransactionActive, bool kUnchecked> @@ -255,12 +253,12 @@ inline void PointerArray::SetElementPtrSize(uint32_t idx, T* element, PointerSiz ptr_size); } -template <VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption, typename Visitor> +template <VerifyObjectFlags kVerifyFlags, typename Visitor> inline void PointerArray::Fixup(mirror::PointerArray* dest, PointerSize pointer_size, const Visitor& visitor) { for (size_t i = 0, count = GetLength(); i < count; ++i) { - void* ptr = GetElementPtrSize<void*, kVerifyFlags, kReadBarrierOption>(i, pointer_size); + void* ptr = GetElementPtrSize<void*, kVerifyFlags>(i, pointer_size); void* new_ptr = visitor(ptr); if (ptr != new_ptr) { dest->SetElementPtrSize<false, true>(i, new_ptr, pointer_size); diff --git a/runtime/mirror/array.h b/runtime/mirror/array.h index 7211f30baa..8816c619df 100644 --- a/runtime/mirror/array.h +++ b/runtime/mirror/array.h @@ -193,9 +193,7 @@ extern template class PrimitiveArray<int16_t>; // ShortArray // Either an IntArray or a LongArray. class PointerArray : public Array { public: - template<typename T, - VerifyObjectFlags kVerifyFlags = kVerifyNone, - ReadBarrierOption kReadBarrierOption = kWithReadBarrier> + template<typename T, VerifyObjectFlags kVerifyFlags = kVerifyNone> T GetElementPtrSize(uint32_t idx, PointerSize ptr_size) REQUIRES_SHARED(Locks::mutator_lock_); @@ -216,9 +214,7 @@ class PointerArray : public Array { // Fixup the pointers in the dest arrays by passing our pointers through the visitor. Only copies // to dest if visitor(source_ptr) != source_ptr. - template <VerifyObjectFlags kVerifyFlags = kVerifyNone, - ReadBarrierOption kReadBarrierOption = kWithReadBarrier, - typename Visitor> + template <VerifyObjectFlags kVerifyFlags = kVerifyNone, typename Visitor> void Fixup(mirror::PointerArray* dest, PointerSize pointer_size, const Visitor& visitor) REQUIRES_SHARED(Locks::mutator_lock_); diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h index 9a4130d0d5..3c418369d2 100644 --- a/runtime/mirror/class-inl.h +++ b/runtime/mirror/class-inl.h @@ -313,8 +313,7 @@ inline ArtMethod* Class::GetVTableEntry(uint32_t i, PointerSize pointer_size) { } auto* vtable = GetVTable<kVerifyFlags, kReadBarrierOption>(); DCHECK(vtable != nullptr); - return vtable->template GetElementPtrSize<ArtMethod*, kVerifyFlags, kReadBarrierOption>( - i, pointer_size); + return vtable->template GetElementPtrSize<ArtMethod*, kVerifyFlags>(i, pointer_size); } template<VerifyObjectFlags kVerifyFlags> diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h index 74fca549ea..9923cd3426 100644 --- a/runtime/mirror/class.h +++ b/runtime/mirror/class.h @@ -484,20 +484,6 @@ class MANAGED Class final : public Object { template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> ALWAYS_INLINE bool IsObjectArrayClass() REQUIRES_SHARED(Locks::mutator_lock_); - template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> - bool IsIntArrayClass() REQUIRES_SHARED(Locks::mutator_lock_) { - constexpr auto kNewFlags = static_cast<VerifyObjectFlags>(kVerifyFlags & ~kVerifyThis); - auto* component_type = GetComponentType<kVerifyFlags>(); - return component_type != nullptr && component_type->template IsPrimitiveInt<kNewFlags>(); - } - - template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> - bool IsLongArrayClass() REQUIRES_SHARED(Locks::mutator_lock_) { - constexpr auto kNewFlags = static_cast<VerifyObjectFlags>(kVerifyFlags & ~kVerifyThis); - auto* component_type = GetComponentType<kVerifyFlags>(); - return component_type != nullptr && component_type->template IsPrimitiveLong<kNewFlags>(); - } - // Creates a raw object instance but does not invoke the default constructor. template<bool kIsInstrumented, bool kCheckAddFinalizer = true> ALWAYS_INLINE ObjPtr<Object> Alloc(Thread* self, gc::AllocatorType allocator_type) diff --git a/runtime/mirror/class_ext-inl.h b/runtime/mirror/class_ext-inl.h index feaac8580a..8d68dc92f9 100644 --- a/runtime/mirror/class_ext-inl.h +++ b/runtime/mirror/class_ext-inl.h @@ -32,9 +32,7 @@ void ClassExt::VisitNativeRoots(Visitor& visitor, PointerSize pointer_size) { } int32_t len = arr->GetLength(); for (int32_t i = 0; i < len; i++) { - ArtMethod* method = arr->GetElementPtrSize<ArtMethod*, - kDefaultVerifyFlags, - kReadBarrierOption>(i, pointer_size); + ArtMethod* method = arr->GetElementPtrSize<ArtMethod*, kDefaultVerifyFlags>(i, pointer_size); if (method != nullptr) { method->VisitRoots<kReadBarrierOption>(visitor, pointer_size); } diff --git a/runtime/mirror/object-inl.h b/runtime/mirror/object-inl.h index 8ae79a8c66..fcb7479d5d 100644 --- a/runtime/mirror/object-inl.h +++ b/runtime/mirror/object-inl.h @@ -192,113 +192,102 @@ inline Array* Object::AsArray() { return down_cast<Array*>(this); } +template<VerifyObjectFlags kVerifyFlags, Primitive::Type kType> +ALWAYS_INLINE bool Object::IsSpecificPrimitiveArray() { + // We do not need a read barrier here as the primitive type is constant, + // both from-space and to-space component type classes shall yield the same result. + ObjPtr<Class> klass = GetClass<kVerifyFlags, kWithoutReadBarrier>(); + constexpr auto kNewFlags = RemoveThisFlags(kVerifyFlags); + ObjPtr<Class> const component_type = klass->GetComponentType<kNewFlags, kWithoutReadBarrier>(); + return component_type != nullptr && + component_type->GetPrimitiveType<kNewFlags>() == kType; +} + +template<VerifyObjectFlags kVerifyFlags> +inline bool Object::IsBooleanArray() { + return IsSpecificPrimitiveArray<kVerifyFlags, Primitive::kPrimBoolean>(); +} + template<VerifyObjectFlags kVerifyFlags> inline BooleanArray* Object::AsBooleanArray() { - constexpr auto kNewFlags = RemoveThisFlags(kVerifyFlags); - DCHECK(GetClass<kVerifyFlags>()->IsArrayClass()); - DCHECK(GetClass<kNewFlags>()->GetComponentType()->IsPrimitiveBoolean()); + DCHECK(IsBooleanArray<kVerifyFlags>()); return down_cast<BooleanArray*>(this); } template<VerifyObjectFlags kVerifyFlags> +inline bool Object::IsByteArray() { + return IsSpecificPrimitiveArray<kVerifyFlags, Primitive::kPrimByte>(); +} + +template<VerifyObjectFlags kVerifyFlags> inline ByteArray* Object::AsByteArray() { - constexpr auto kNewFlags = RemoveThisFlags(kVerifyFlags); - DCHECK(GetClass<kVerifyFlags>()->IsArrayClass()); - DCHECK(GetClass<kNewFlags>()->template GetComponentType<kNewFlags>()->IsPrimitiveByte()); + DCHECK(IsByteArray<kVerifyFlags>()); return down_cast<ByteArray*>(this); } template<VerifyObjectFlags kVerifyFlags> -inline ByteArray* Object::AsByteSizedArray() { - constexpr auto kNewFlags = RemoveThisFlags(kVerifyFlags); - DCHECK(GetClass<kVerifyFlags>()->IsArrayClass()); - DCHECK(GetClass<kNewFlags>()->template GetComponentType<kNewFlags>()->IsPrimitiveByte() || - GetClass<kNewFlags>()->template GetComponentType<kNewFlags>()->IsPrimitiveBoolean()); - return down_cast<ByteArray*>(this); +inline bool Object::IsCharArray() { + return IsSpecificPrimitiveArray<kVerifyFlags, Primitive::kPrimChar>(); } template<VerifyObjectFlags kVerifyFlags> inline CharArray* Object::AsCharArray() { - constexpr auto kNewFlags = RemoveThisFlags(kVerifyFlags); - DCHECK(GetClass<kVerifyFlags>()->IsArrayClass()); - DCHECK(GetClass<kNewFlags>()->template GetComponentType<kNewFlags>()->IsPrimitiveChar()); + DCHECK(IsCharArray<kVerifyFlags>()); return down_cast<CharArray*>(this); } template<VerifyObjectFlags kVerifyFlags> -inline ShortArray* Object::AsShortArray() { - constexpr auto kNewFlags = RemoveThisFlags(kVerifyFlags); - DCHECK(GetClass<kVerifyFlags>()->IsArrayClass()); - DCHECK(GetClass<kNewFlags>()->template GetComponentType<kNewFlags>()->IsPrimitiveShort()); - return down_cast<ShortArray*>(this); +inline bool Object::IsShortArray() { + return IsSpecificPrimitiveArray<kVerifyFlags, Primitive::kPrimShort>(); } template<VerifyObjectFlags kVerifyFlags> -inline ShortArray* Object::AsShortSizedArray() { - constexpr auto kNewFlags = RemoveThisFlags(kVerifyFlags); - DCHECK(GetClass<kVerifyFlags>()->IsArrayClass()); - DCHECK(GetClass<kNewFlags>()->template GetComponentType<kNewFlags>()->IsPrimitiveShort() || - GetClass<kNewFlags>()->template GetComponentType<kNewFlags>()->IsPrimitiveChar()); +inline ShortArray* Object::AsShortArray() { + DCHECK(IsShortArray<kVerifyFlags>()); return down_cast<ShortArray*>(this); } -template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption> +template<VerifyObjectFlags kVerifyFlags> inline bool Object::IsIntArray() { - constexpr auto kNewFlags = RemoveThisFlags(kVerifyFlags); - ObjPtr<Class> klass = GetClass<kVerifyFlags, kReadBarrierOption>(); - ObjPtr<Class> component_type = klass->GetComponentType<kVerifyFlags, kReadBarrierOption>(); - return component_type != nullptr && component_type->template IsPrimitiveInt<kNewFlags>(); + return IsSpecificPrimitiveArray<kVerifyFlags, Primitive::kPrimInt>(); } -template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption> +template<VerifyObjectFlags kVerifyFlags> inline IntArray* Object::AsIntArray() { - DCHECK((IsIntArray<kVerifyFlags, kReadBarrierOption>())); + DCHECK((IsIntArray<kVerifyFlags>())); return down_cast<IntArray*>(this); } -template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption> +template<VerifyObjectFlags kVerifyFlags> inline bool Object::IsLongArray() { - constexpr auto kNewFlags = RemoveThisFlags(kVerifyFlags); - ObjPtr<Class> klass = GetClass<kVerifyFlags, kReadBarrierOption>(); - ObjPtr<Class> component_type = klass->GetComponentType<kVerifyFlags, kReadBarrierOption>(); - return component_type != nullptr && component_type->template IsPrimitiveLong<kNewFlags>(); + return IsSpecificPrimitiveArray<kVerifyFlags, Primitive::kPrimLong>(); } -template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption> +template<VerifyObjectFlags kVerifyFlags> inline LongArray* Object::AsLongArray() { - DCHECK((IsLongArray<kVerifyFlags, kReadBarrierOption>())); + DCHECK((IsLongArray<kVerifyFlags>())); return down_cast<LongArray*>(this); } template<VerifyObjectFlags kVerifyFlags> inline bool Object::IsFloatArray() { - constexpr auto kNewFlags = RemoveThisFlags(kVerifyFlags); - auto* component_type = GetClass<kVerifyFlags>()->GetComponentType(); - return component_type != nullptr && component_type->template IsPrimitiveFloat<kNewFlags>(); + return IsSpecificPrimitiveArray<kVerifyFlags, Primitive::kPrimFloat>(); } template<VerifyObjectFlags kVerifyFlags> inline FloatArray* Object::AsFloatArray() { DCHECK(IsFloatArray<kVerifyFlags>()); - constexpr auto kNewFlags = RemoveThisFlags(kVerifyFlags); - DCHECK(GetClass<kVerifyFlags>()->IsArrayClass()); - DCHECK(GetClass<kNewFlags>()->template GetComponentType<kNewFlags>()->IsPrimitiveFloat()); return down_cast<FloatArray*>(this); } template<VerifyObjectFlags kVerifyFlags> inline bool Object::IsDoubleArray() { - constexpr auto kNewFlags = RemoveThisFlags(kVerifyFlags); - auto* component_type = GetClass<kVerifyFlags>()->GetComponentType(); - return component_type != nullptr && component_type->template IsPrimitiveDouble<kNewFlags>(); + return IsSpecificPrimitiveArray<kVerifyFlags, Primitive::kPrimDouble>(); } template<VerifyObjectFlags kVerifyFlags> inline DoubleArray* Object::AsDoubleArray() { DCHECK(IsDoubleArray<kVerifyFlags>()); - constexpr auto kNewFlags = RemoveThisFlags(kVerifyFlags); - DCHECK(GetClass<kVerifyFlags>()->IsArrayClass()); - DCHECK(GetClass<kNewFlags>()->template GetComponentType<kNewFlags>()->IsPrimitiveDouble()); return down_cast<DoubleArray*>(this); } diff --git a/runtime/mirror/object.h b/runtime/mirror/object.h index 11e8ccadc4..bca7511489 100644 --- a/runtime/mirror/object.h +++ b/runtime/mirror/object.h @@ -21,6 +21,7 @@ #include "base/casts.h" #include "base/enums.h" #include "base/globals.h" +#include "dex/primitive.h" #include "obj_ptr.h" #include "object_reference.h" #include "offsets.h" @@ -199,31 +200,33 @@ class MANAGED LOCKABLE Object { Array* AsArray() REQUIRES_SHARED(Locks::mutator_lock_); template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> + bool IsBooleanArray() REQUIRES_SHARED(Locks::mutator_lock_); + template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> BooleanArray* AsBooleanArray() REQUIRES_SHARED(Locks::mutator_lock_); + template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> - ByteArray* AsByteArray() REQUIRES_SHARED(Locks::mutator_lock_); + bool IsByteArray() REQUIRES_SHARED(Locks::mutator_lock_); template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> - ByteArray* AsByteSizedArray() REQUIRES_SHARED(Locks::mutator_lock_); + ByteArray* AsByteArray() REQUIRES_SHARED(Locks::mutator_lock_); template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> + bool IsCharArray() REQUIRES_SHARED(Locks::mutator_lock_); + template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> CharArray* AsCharArray() REQUIRES_SHARED(Locks::mutator_lock_); + template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> - ShortArray* AsShortArray() REQUIRES_SHARED(Locks::mutator_lock_); + bool IsShortArray() REQUIRES_SHARED(Locks::mutator_lock_); template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> - ShortArray* AsShortSizedArray() REQUIRES_SHARED(Locks::mutator_lock_); + ShortArray* AsShortArray() REQUIRES_SHARED(Locks::mutator_lock_); - template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, - ReadBarrierOption kReadBarrierOption = kWithReadBarrier> + template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> bool IsIntArray() REQUIRES_SHARED(Locks::mutator_lock_); - template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, - ReadBarrierOption kReadBarrierOption = kWithReadBarrier> + template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> IntArray* AsIntArray() REQUIRES_SHARED(Locks::mutator_lock_); - template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, - ReadBarrierOption kReadBarrierOption = kWithReadBarrier> + template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> bool IsLongArray() REQUIRES_SHARED(Locks::mutator_lock_); - template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, - ReadBarrierOption kReadBarrierOption = kWithReadBarrier> + template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> LongArray* AsLongArray() REQUIRES_SHARED(Locks::mutator_lock_); template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> @@ -757,6 +760,9 @@ class MANAGED LOCKABLE Object { size_t num_bytes) REQUIRES_SHARED(Locks::mutator_lock_); + template<VerifyObjectFlags kVerifyFlags, Primitive::Type kType> + bool IsSpecificPrimitiveArray() REQUIRES_SHARED(Locks::mutator_lock_); + static Atomic<uint32_t> hash_code_seed; // The Class representing the type of the object. diff --git a/runtime/native/java_lang_System.cc b/runtime/native/java_lang_System.cc index 2c4184c285..e4bc8ce5a2 100644 --- a/runtime/native/java_lang_System.cc +++ b/runtime/native/java_lang_System.cc @@ -101,32 +101,36 @@ static void System_arraycopy(JNIEnv* env, jclass, jobject javaSrc, jint srcPos, case Primitive::kPrimBoolean: case Primitive::kPrimByte: DCHECK_EQ(Primitive::ComponentSize(dstComponentPrimitiveType), 1U); - dstArray->AsByteSizedArray()->Memmove(dstPos, srcArray->AsByteSizedArray(), srcPos, count); + // Note: Treating BooleanArray as ByteArray. + ObjPtr<mirror::ByteArray>::DownCast(dstArray)->Memmove( + dstPos, ObjPtr<mirror::ByteArray>::DownCast(srcArray), srcPos, count); return; case Primitive::kPrimChar: case Primitive::kPrimShort: DCHECK_EQ(Primitive::ComponentSize(dstComponentPrimitiveType), 2U); - dstArray->AsShortSizedArray()->Memmove(dstPos, srcArray->AsShortSizedArray(), srcPos, count); + // Note: Treating CharArray as ShortArray. + ObjPtr<mirror::ShortArray>::DownCast(dstArray)->Memmove( + dstPos, ObjPtr<mirror::ShortArray>::DownCast(srcArray), srcPos, count); return; case Primitive::kPrimInt: - DCHECK_EQ(Primitive::ComponentSize(dstComponentPrimitiveType), 4U); - dstArray->AsIntArray()->Memmove(dstPos, srcArray->AsIntArray(), srcPos, count); - return; case Primitive::kPrimFloat: DCHECK_EQ(Primitive::ComponentSize(dstComponentPrimitiveType), 4U); - dstArray->AsFloatArray()->Memmove(dstPos, srcArray->AsFloatArray(), srcPos, count); + // Note: Treating FloatArray as IntArray. + ObjPtr<mirror::IntArray>::DownCast(dstArray)->Memmove( + dstPos, ObjPtr<mirror::IntArray>::DownCast(srcArray), srcPos, count); return; case Primitive::kPrimLong: - DCHECK_EQ(Primitive::ComponentSize(dstComponentPrimitiveType), 8U); - dstArray->AsLongArray()->Memmove(dstPos, srcArray->AsLongArray(), srcPos, count); - return; case Primitive::kPrimDouble: DCHECK_EQ(Primitive::ComponentSize(dstComponentPrimitiveType), 8U); - dstArray->AsDoubleArray()->Memmove(dstPos, srcArray->AsDoubleArray(), srcPos, count); + // Note: Treating DoubleArray as LongArray. + ObjPtr<mirror::LongArray>::DownCast(dstArray)->Memmove( + dstPos, ObjPtr<mirror::LongArray>::DownCast(srcArray), srcPos, count); return; case Primitive::kPrimNot: { - mirror::ObjectArray<mirror::Object>* dstObjArray = dstArray->AsObjectArray<mirror::Object>(); - mirror::ObjectArray<mirror::Object>* srcObjArray = srcArray->AsObjectArray<mirror::Object>(); + mirror::ObjectArray<mirror::Object>* dstObjArray = + dstArray->AsObjectArray<mirror::Object>(); + mirror::ObjectArray<mirror::Object>* srcObjArray = + srcArray->AsObjectArray<mirror::Object>(); dstObjArray->AssignableMemmove(dstPos, srcObjArray, srcPos, count); return; } diff --git a/runtime/native/sun_misc_Unsafe.cc b/runtime/native/sun_misc_Unsafe.cc index a739c2d16e..5014f340cd 100644 --- a/runtime/native/sun_misc_Unsafe.cc +++ b/runtime/native/sun_misc_Unsafe.cc @@ -366,13 +366,17 @@ static void Unsafe_copyMemoryToPrimitiveArray(JNIEnv *env, ObjPtr<mirror::Object> dst = soa.Decode<mirror::Object>(dstObj); ObjPtr<mirror::Class> component_type = dst->GetClass()->GetComponentType(); if (component_type->IsPrimitiveByte() || component_type->IsPrimitiveBoolean()) { - copyToArray(srcAddr, MakeObjPtr(dst->AsByteSizedArray()), dst_offset, sz); + // Note: Treating BooleanArray as ByteArray. + copyToArray(srcAddr, ObjPtr<mirror::ByteArray>::DownCast(dst), dst_offset, sz); } else if (component_type->IsPrimitiveShort() || component_type->IsPrimitiveChar()) { - copyToArray(srcAddr, MakeObjPtr(dst->AsShortSizedArray()), dst_offset, sz); + // Note: Treating CharArray as ShortArray. + copyToArray(srcAddr, ObjPtr<mirror::ShortArray>::DownCast(dst), dst_offset, sz); } else if (component_type->IsPrimitiveInt() || component_type->IsPrimitiveFloat()) { - copyToArray(srcAddr, MakeObjPtr(dst->AsIntArray()), dst_offset, sz); + // Note: Treating FloatArray as IntArray. + copyToArray(srcAddr, ObjPtr<mirror::IntArray>::DownCast(dst), dst_offset, sz); } else if (component_type->IsPrimitiveLong() || component_type->IsPrimitiveDouble()) { - copyToArray(srcAddr, MakeObjPtr(dst->AsLongArray()), dst_offset, sz); + // Note: Treating DoubleArray as LongArray. + copyToArray(srcAddr, ObjPtr<mirror::LongArray>::DownCast(dst), dst_offset, sz); } else { ThrowIllegalAccessException("not a primitive array"); } @@ -397,13 +401,17 @@ static void Unsafe_copyMemoryFromPrimitiveArray(JNIEnv *env, ObjPtr<mirror::Object> src = soa.Decode<mirror::Object>(srcObj); ObjPtr<mirror::Class> component_type = src->GetClass()->GetComponentType(); if (component_type->IsPrimitiveByte() || component_type->IsPrimitiveBoolean()) { - copyFromArray(dstAddr, MakeObjPtr(src->AsByteSizedArray()), src_offset, sz); + // Note: Treating BooleanArray as ByteArray. + copyFromArray(dstAddr, ObjPtr<mirror::ByteArray>::DownCast(src), src_offset, sz); } else if (component_type->IsPrimitiveShort() || component_type->IsPrimitiveChar()) { - copyFromArray(dstAddr, MakeObjPtr(src->AsShortSizedArray()), src_offset, sz); + // Note: Treating CharArray as ShortArray. + copyFromArray(dstAddr, ObjPtr<mirror::ShortArray>::DownCast(src), src_offset, sz); } else if (component_type->IsPrimitiveInt() || component_type->IsPrimitiveFloat()) { - copyFromArray(dstAddr, MakeObjPtr(src->AsIntArray()), src_offset, sz); + // Note: Treating FloatArray as IntArray. + copyFromArray(dstAddr, ObjPtr<mirror::IntArray>::DownCast(src), src_offset, sz); } else if (component_type->IsPrimitiveLong() || component_type->IsPrimitiveDouble()) { - copyFromArray(dstAddr, MakeObjPtr(src->AsLongArray()), src_offset, sz); + // Note: Treating DoubleArray as LongArray. + copyFromArray(dstAddr, ObjPtr<mirror::LongArray>::DownCast(src), src_offset, sz); } else { ThrowIllegalAccessException("not a primitive array"); } diff --git a/test/004-UnsafeTest/src/Main.java b/test/004-UnsafeTest/src/Main.java index d43d374a42..9176e89aaf 100644 --- a/test/004-UnsafeTest/src/Main.java +++ b/test/004-UnsafeTest/src/Main.java @@ -32,6 +32,20 @@ public class Main { } } + private static void check(float actual, float expected, String msg) { + if (actual != expected) { + System.out.println(msg + " : " + actual + " != " + expected); + System.exit(1); + } + } + + private static void check(double actual, double expected, String msg) { + if (actual != expected) { + System.out.println(msg + " : " + actual + " != " + expected); + System.exit(1); + } + } + private static void check(Object actual, Object expected, String msg) { if (actual != expected) { System.out.println(msg + " : " + actual + " != " + expected); @@ -54,6 +68,7 @@ public class Main { testArrayIndexScale(unsafe); testGetAndPutAndCAS(unsafe); testGetAndPutVolatile(unsafe); + testCopyMemoryPrimitiveArrays(unsafe); } private static void testArrayBaseOffset(Unsafe unsafe) { @@ -237,6 +252,38 @@ public class Main { "Unsafe.getObjectVolatile(Object, long)"); } + // Regression test for "copyMemory" operations hitting a DCHECK() for float/double arrays. + private static void testCopyMemoryPrimitiveArrays(Unsafe unsafe) { + int size = 4 * 1024; + long memory = unsafeTestMalloc(size); + + int floatSize = 4; + float[] inputFloats = new float[size / floatSize]; + for (int i = 0; i != inputFloats.length; ++i) { + inputFloats[i] = ((float)i) + 0.5f; + } + float[] outputFloats = new float[size / floatSize]; + unsafe.copyMemoryFromPrimitiveArray(inputFloats, 0, memory, size); + unsafe.copyMemoryToPrimitiveArray(memory, outputFloats, 0, size); + for (int i = 0; i != inputFloats.length; ++i) { + check(inputFloats[i], outputFloats[i], "unsafe.copyMemory/float"); + } + + int doubleSize = 8; + double[] inputDoubles = new double[size / doubleSize]; + for (int i = 0; i != inputDoubles.length; ++i) { + inputDoubles[i] = ((double)i) + 0.5; + } + double[] outputDoubles = new double[size / doubleSize]; + unsafe.copyMemoryFromPrimitiveArray(inputDoubles, 0, memory, size); + unsafe.copyMemoryToPrimitiveArray(memory, outputDoubles, 0, size); + for (int i = 0; i != inputDoubles.length; ++i) { + check(inputDoubles[i], outputDoubles[i], "unsafe.copyMemory/double"); + } + + unsafeTestFree(memory); + } + private static class TestClass { public int intVar = 0; public long longVar = 0; @@ -251,4 +298,6 @@ public class Main { private static native int vmArrayBaseOffset(Class<?> clazz); private static native int vmArrayIndexScale(Class<?> clazz); + private static native long unsafeTestMalloc(long size); + private static native void unsafeTestFree(long memory); } diff --git a/test/004-UnsafeTest/unsafe_test.cc b/test/004-UnsafeTest/unsafe_test.cc index 18d9ea8913..e970aaa840 100644 --- a/test/004-UnsafeTest/unsafe_test.cc +++ b/test/004-UnsafeTest/unsafe_test.cc @@ -15,6 +15,7 @@ */ #include "art_method-inl.h" +#include "base/casts.h" #include "jni.h" #include "mirror/array.h" #include "mirror/class-inl.h" @@ -37,4 +38,16 @@ extern "C" JNIEXPORT jint JNICALL Java_Main_vmArrayIndexScale(JNIEnv* env, jclas return Primitive::ComponentSize(klass->GetComponentType()->GetPrimitiveType()); } +extern "C" JNIEXPORT jlong JNICALL Java_Main_unsafeTestMalloc(JNIEnv*, jclass, jlong size) { + void* memory = malloc(dchecked_integral_cast<size_t>(size)); + CHECK(memory != nullptr); + return reinterpret_cast64<jlong>(memory); +} + +extern "C" JNIEXPORT void JNICALL Java_Main_unsafeTestFree(JNIEnv*, jclass, jlong memory) { + void* mem = reinterpret_cast64<void*>(memory); + CHECK(mem != nullptr); + free(mem); +} + } // namespace art |