Clean up primitive array helpers in Object.
Refactor these helpers and avoid read barriers. Remove
Class::Is{Int,Long}ArrayClass() and use the Object helpers
instead.
Remove the AsByteSizedArray() and AsShortSizedArray()
helpers that essentially break the type system and rewrite
their users, adding appropriate notes. {Float,Double}Array
uses in Unsafe would have previously failed a DCHECK().
Test: Additional test in 004-UnsafeTest.
Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing
Change-Id: I88b7e3df7de883f64cfc5eb437a40646f2884685
diff --git a/dex2oat/linker/image_writer.cc b/dex2oat/linker/image_writer.cc
index 5ca7f07..2b2b029 100644
--- a/dex2oat/linker/image_writer.cc
+++ b/dex2oat/linker/image_writer.cc
@@ -2670,10 +2670,8 @@
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 @@
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 @@
} 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 06c694c..ccd529a 100644
--- a/dex2oat/linker/image_writer.h
+++ b/dex2oat/linker/image_writer.h
@@ -541,7 +541,6 @@
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 b46abfb..10f395b 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -832,7 +832,7 @@
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 4427332..a6a5ba2 100644
--- a/runtime/mirror/array-inl.h
+++ b/runtime/mirror/array-inl.h
@@ -224,16 +224,14 @@
}
}
-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 @@
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 7211f30..8816c61 100644
--- a/runtime/mirror/array.h
+++ b/runtime/mirror/array.h
@@ -193,9 +193,7 @@
// 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 @@
// 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 9a4130d..3c41836 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -313,8 +313,7 @@
}
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 74fca54..9923cd3 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -484,20 +484,6 @@
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 feaac85..8d68dc9 100644
--- a/runtime/mirror/class_ext-inl.h
+++ b/runtime/mirror/class_ext-inl.h
@@ -32,9 +32,7 @@
}
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 8ae79a8..fcb7479 100644
--- a/runtime/mirror/object-inl.h
+++ b/runtime/mirror/object-inl.h
@@ -192,113 +192,102 @@
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 bool Object::IsShortArray() {
+ return IsSpecificPrimitiveArray<kVerifyFlags, Primitive::kPrimShort>();
+}
+
+template<VerifyObjectFlags kVerifyFlags>
inline ShortArray* Object::AsShortArray() {
- constexpr auto kNewFlags = RemoveThisFlags(kVerifyFlags);
- DCHECK(GetClass<kVerifyFlags>()->IsArrayClass());
- DCHECK(GetClass<kNewFlags>()->template GetComponentType<kNewFlags>()->IsPrimitiveShort());
+ DCHECK(IsShortArray<kVerifyFlags>());
return down_cast<ShortArray*>(this);
}
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());
- return down_cast<ShortArray*>(this);
-}
-
-template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption>
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 11e8cca..bca7511 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 @@
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>
+ bool IsByteArray() REQUIRES_SHARED(Locks::mutator_lock_);
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
ByteArray* AsByteArray() REQUIRES_SHARED(Locks::mutator_lock_);
- template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
- ByteArray* AsByteSizedArray() 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>
+ bool IsShortArray() REQUIRES_SHARED(Locks::mutator_lock_);
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
ShortArray* AsShortArray() REQUIRES_SHARED(Locks::mutator_lock_);
- template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
- ShortArray* AsShortSizedArray() 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 @@
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 2c4184c..e4bc8ce 100644
--- a/runtime/native/java_lang_System.cc
+++ b/runtime/native/java_lang_System.cc
@@ -101,32 +101,36 @@
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 a739c2d..5014f34 100644
--- a/runtime/native/sun_misc_Unsafe.cc
+++ b/runtime/native/sun_misc_Unsafe.cc
@@ -366,13 +366,17 @@
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 @@
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 d43d374..9176e89 100644
--- a/test/004-UnsafeTest/src/Main.java
+++ b/test/004-UnsafeTest/src/Main.java
@@ -32,6 +32,20 @@
}
}
+ 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 @@
testArrayIndexScale(unsafe);
testGetAndPutAndCAS(unsafe);
testGetAndPutVolatile(unsafe);
+ testCopyMemoryPrimitiveArrays(unsafe);
}
private static void testArrayBaseOffset(Unsafe unsafe) {
@@ -237,6 +252,38 @@
"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 @@
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 18d9ea8..e970aaa 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 @@
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