From 68d8ff4bc1b83c87e9dac0ac0394d1381369e223 Mon Sep 17 00:00:00 2001 From: Narayan Kamath Date: Mon, 16 Nov 2015 12:31:28 +0000 Subject: [PATCH] Move arrayCopy / identityHashCode from OpenJdkJvm to System. These functions are only ever called as the JNI implementation of System.arrayCopy (and never directly from native code) so it's cleaner to keep them as part of System's native implementation. Moreover, this change fixes issues in debug mode where taking the address of a function in a different shared library (potentially compiled with different compilation flags) generates incorrect code. Change-Id: I0da147b9917eb1bb418d3f253fb2bfad46e53e0c --- runtime/native/OpenjdkJvm.cc | 129 +++---------------------------------- runtime/native/java_lang_System.cc | 129 +++++++++++++++++++++++++++++++++++++ 2 files changed, 139 insertions(+), 119 deletions(-) diff --git a/runtime/native/OpenjdkJvm.cc b/runtime/native/OpenjdkJvm.cc index 25f1c550d..24155dae8 100644 --- a/runtime/native/OpenjdkJvm.cc +++ b/runtime/native/OpenjdkJvm.cc @@ -462,130 +462,21 @@ JNIEXPORT void JVM_SetNativeThreadName(JNIEnv* env, jobject jthread, jstring jav } } -JNIEXPORT jint JVM_IHashCode(JNIEnv* env, jobject javaObject) { - if (UNLIKELY(javaObject == nullptr)) { - return 0; - } - art::ScopedFastNativeObjectAccess soa(env); - art::mirror::Object* o = soa.Decode(javaObject); - return static_cast(o->IdentityHashCode()); +JNIEXPORT jint JVM_IHashCode(JNIEnv* env ATTRIBUTE_UNUSED, + jobject javaObject ATTRIBUTE_UNUSED) { + UNIMPLEMENTED(FATAL) << "JVM_IHashCode is not implemented"; + return 0; } JNIEXPORT jlong JVM_NanoTime(JNIEnv* env ATTRIBUTE_UNUSED, jclass unused ATTRIBUTE_UNUSED) { - timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - return now.tv_sec * 1000000000LL + now.tv_nsec; -} - -static void ThrowArrayStoreException_NotAnArray(const char* identifier, art::mirror::Object* array) - SHARED_LOCKS_REQUIRED(art::Locks::mutator_lock_) { - std::string actualType(art::PrettyTypeOf(array)); - art::Thread* self = art::Thread::Current(); - self->ThrowNewExceptionF("Ljava/lang/ArrayStoreException;", - "%s of type %s is not an array", identifier, actualType.c_str()); + UNIMPLEMENTED(FATAL) << "JVM_NanoTime is not implemented"; + return 0L; } -JNIEXPORT void JVM_ArrayCopy(JNIEnv* env, jclass unused ATTRIBUTE_UNUSED, jobject javaSrc, - jint srcPos, jobject javaDst, jint dstPos, jint length) { - // The API is defined in terms of length, but length is somewhat overloaded so we use count. - const jint count = length; - art::ScopedFastNativeObjectAccess soa(env); - - // Null pointer checks. - if (UNLIKELY(javaSrc == nullptr)) { - art::ThrowNullPointerException("src == null"); - return; - } - if (UNLIKELY(javaDst == nullptr)) { - art::ThrowNullPointerException("dst == null"); - return; - } - - // Make sure source and destination are both arrays. - art::mirror::Object* srcObject = soa.Decode(javaSrc); - if (UNLIKELY(!srcObject->IsArrayInstance())) { - ThrowArrayStoreException_NotAnArray("source", srcObject); - return; - } - art::mirror::Object* dstObject = soa.Decode(javaDst); - if (UNLIKELY(!dstObject->IsArrayInstance())) { - ThrowArrayStoreException_NotAnArray("destination", dstObject); - return; - } - art::mirror::Array* srcArray = srcObject->AsArray(); - art::mirror::Array* dstArray = dstObject->AsArray(); - - // Bounds checking. - if (UNLIKELY(srcPos < 0) || UNLIKELY(dstPos < 0) || UNLIKELY(count < 0) || - UNLIKELY(srcPos > srcArray->GetLength() - count) || - UNLIKELY(dstPos > dstArray->GetLength() - count)) { - soa.Self()->ThrowNewExceptionF("Ljava/lang/ArrayIndexOutOfBoundsException;", - "src.length=%d srcPos=%d dst.length=%d dstPos=%d length=%d", - srcArray->GetLength(), srcPos, dstArray->GetLength(), dstPos, - count); - return; - } - - art::mirror::Class* dstComponentType = dstArray->GetClass()->GetComponentType(); - art::mirror::Class* srcComponentType = srcArray->GetClass()->GetComponentType(); - art::Primitive::Type dstComponentPrimitiveType = dstComponentType->GetPrimitiveType(); - - if (LIKELY(srcComponentType == dstComponentType)) { - // Trivial assignability. - switch (dstComponentPrimitiveType) { - case art::Primitive::kPrimVoid: - LOG(FATAL) << "Unreachable, cannot have arrays of type void"; - return; - case art::Primitive::kPrimBoolean: - case art::Primitive::kPrimByte: - DCHECK_EQ(art::Primitive::ComponentSize(dstComponentPrimitiveType), 1U); - dstArray->AsByteSizedArray()->Memmove(dstPos, srcArray->AsByteSizedArray(), srcPos, count); - return; - case art::Primitive::kPrimChar: - case art::Primitive::kPrimShort: - DCHECK_EQ(art::Primitive::ComponentSize(dstComponentPrimitiveType), 2U); - dstArray->AsShortSizedArray()->Memmove(dstPos, srcArray->AsShortSizedArray(), srcPos, count); - return; - case art::Primitive::kPrimInt: - case art::Primitive::kPrimFloat: - DCHECK_EQ(art::Primitive::ComponentSize(dstComponentPrimitiveType), 4U); - dstArray->AsIntArray()->Memmove(dstPos, srcArray->AsIntArray(), srcPos, count); - return; - case art::Primitive::kPrimLong: - case art::Primitive::kPrimDouble: - DCHECK_EQ(art::Primitive::ComponentSize(dstComponentPrimitiveType), 8U); - dstArray->AsLongArray()->Memmove(dstPos, srcArray->AsLongArray(), srcPos, count); - return; - case art::Primitive::kPrimNot: { - art::mirror::ObjectArray* dstObjArray = dstArray->AsObjectArray(); - art::mirror::ObjectArray* srcObjArray = srcArray->AsObjectArray(); - dstObjArray->AssignableMemmove(dstPos, srcObjArray, srcPos, count); - return; - } - default: - LOG(FATAL) << "Unknown array type: " << art::PrettyTypeOf(srcArray); - return; - } - } - // If one of the arrays holds a primitive type the other array must hold the exact same type. - if (UNLIKELY((dstComponentPrimitiveType != art::Primitive::kPrimNot) || - srcComponentType->IsPrimitive())) { - std::string srcType(art::PrettyTypeOf(srcArray)); - std::string dstType(art::PrettyTypeOf(dstArray)); - soa.Self()->ThrowNewExceptionF("Ljava/lang/ArrayStoreException;", - "Incompatible types: src=%s, dst=%s", - srcType.c_str(), dstType.c_str()); - return; - } - // Arrays hold distinct types and so therefore can't alias - use memcpy instead of memmove. - art::mirror::ObjectArray* dstObjArray = dstArray->AsObjectArray(); - art::mirror::ObjectArray* srcObjArray = srcArray->AsObjectArray(); - // If we're assigning into say Object[] then we don't need per element checks. - if (dstComponentType->IsAssignableFrom(srcComponentType)) { - dstObjArray->AssignableMemcpy(dstPos, srcObjArray, srcPos, count); - return; - } - dstObjArray->AssignableCheckingMemcpy(dstPos, srcObjArray, srcPos, count, true); +JNIEXPORT void JVM_ArrayCopy(JNIEnv* /* env */, jclass /* unused */, jobject /* javaSrc */, + jint /* srcPos */, jobject /* javaDst */, jint /* dstPos */, + jint /* length */) { + UNIMPLEMENTED(FATAL) << "JVM_ArrayCopy is not implemented"; } JNIEXPORT jint JVM_FindSignal(const char* name ATTRIBUTE_UNUSED) { diff --git a/runtime/native/java_lang_System.cc b/runtime/native/java_lang_System.cc index 54472756e..736b42b73 100644 --- a/runtime/native/java_lang_System.cc +++ b/runtime/native/java_lang_System.cc @@ -28,6 +28,124 @@ namespace art { +/* + * We make guarantees about the atomicity of accesses to primitive variables. These guarantees + * also apply to elements of arrays. In particular, 8-bit, 16-bit, and 32-bit accesses must not + * cause "word tearing". Accesses to 64-bit array elements may be two 32-bit operations. + * References are never torn regardless of the number of bits used to represent them. + */ + +static void ThrowArrayStoreException_NotAnArray(const char* identifier, mirror::Object* array) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + std::string actualType(PrettyTypeOf(array)); + Thread* self = Thread::Current(); + self->ThrowNewExceptionF("Ljava/lang/ArrayStoreException;", + "%s of type %s is not an array", identifier, actualType.c_str()); +} + +static void System_arraycopy(JNIEnv* env, jclass, jobject javaSrc, jint srcPos, jobject javaDst, + jint dstPos, jint length) { + // The API is defined in terms of length, but length is somewhat overloaded so we use count. + const jint count = length; + ScopedFastNativeObjectAccess soa(env); + + // Null pointer checks. + if (UNLIKELY(javaSrc == nullptr)) { + ThrowNullPointerException("src == null"); + return; + } + if (UNLIKELY(javaDst == nullptr)) { + ThrowNullPointerException("dst == null"); + return; + } + + // Make sure source and destination are both arrays. + mirror::Object* srcObject = soa.Decode(javaSrc); + if (UNLIKELY(!srcObject->IsArrayInstance())) { + ThrowArrayStoreException_NotAnArray("source", srcObject); + return; + } + mirror::Object* dstObject = soa.Decode(javaDst); + if (UNLIKELY(!dstObject->IsArrayInstance())) { + ThrowArrayStoreException_NotAnArray("destination", dstObject); + return; + } + mirror::Array* srcArray = srcObject->AsArray(); + mirror::Array* dstArray = dstObject->AsArray(); + + // Bounds checking. + if (UNLIKELY(srcPos < 0) || UNLIKELY(dstPos < 0) || UNLIKELY(count < 0) || + UNLIKELY(srcPos > srcArray->GetLength() - count) || + UNLIKELY(dstPos > dstArray->GetLength() - count)) { + soa.Self()->ThrowNewExceptionF("Ljava/lang/ArrayIndexOutOfBoundsException;", + "src.length=%d srcPos=%d dst.length=%d dstPos=%d length=%d", + srcArray->GetLength(), srcPos, dstArray->GetLength(), dstPos, + count); + return; + } + + mirror::Class* dstComponentType = dstArray->GetClass()->GetComponentType(); + mirror::Class* srcComponentType = srcArray->GetClass()->GetComponentType(); + Primitive::Type dstComponentPrimitiveType = dstComponentType->GetPrimitiveType(); + + if (LIKELY(srcComponentType == dstComponentType)) { + // Trivial assignability. + switch (dstComponentPrimitiveType) { + case Primitive::kPrimVoid: + LOG(FATAL) << "Unreachable, cannot have arrays of type void"; + UNREACHABLE(); + case Primitive::kPrimBoolean: + case Primitive::kPrimByte: + DCHECK_EQ(Primitive::ComponentSize(dstComponentPrimitiveType), 1U); + dstArray->AsByteSizedArray()->Memmove(dstPos, srcArray->AsByteSizedArray(), srcPos, count); + return; + case Primitive::kPrimChar: + case Primitive::kPrimShort: + DCHECK_EQ(Primitive::ComponentSize(dstComponentPrimitiveType), 2U); + dstArray->AsShortSizedArray()->Memmove(dstPos, srcArray->AsShortSizedArray(), srcPos, count); + return; + case Primitive::kPrimInt: + case Primitive::kPrimFloat: + DCHECK_EQ(Primitive::ComponentSize(dstComponentPrimitiveType), 4U); + dstArray->AsIntArray()->Memmove(dstPos, srcArray->AsIntArray(), srcPos, count); + return; + case Primitive::kPrimLong: + case Primitive::kPrimDouble: + DCHECK_EQ(Primitive::ComponentSize(dstComponentPrimitiveType), 8U); + dstArray->AsLongArray()->Memmove(dstPos, srcArray->AsLongArray(), srcPos, count); + return; + case Primitive::kPrimNot: { + mirror::ObjectArray* dstObjArray = dstArray->AsObjectArray(); + mirror::ObjectArray* srcObjArray = srcArray->AsObjectArray(); + dstObjArray->AssignableMemmove(dstPos, srcObjArray, srcPos, count); + return; + } + default: + LOG(FATAL) << "Unknown array type: " << PrettyTypeOf(srcArray); + UNREACHABLE(); + } + } + // If one of the arrays holds a primitive type the other array must hold the exact same type. + if (UNLIKELY((dstComponentPrimitiveType != Primitive::kPrimNot) || + srcComponentType->IsPrimitive())) { + std::string srcType(PrettyTypeOf(srcArray)); + std::string dstType(PrettyTypeOf(dstArray)); + soa.Self()->ThrowNewExceptionF("Ljava/lang/ArrayStoreException;", + "Incompatible types: src=%s, dst=%s", + srcType.c_str(), dstType.c_str()); + return; + } + // Arrays hold distinct types and so therefore can't alias - use memcpy instead of memmove. + mirror::ObjectArray* dstObjArray = dstArray->AsObjectArray(); + mirror::ObjectArray* srcObjArray = srcArray->AsObjectArray(); + // If we're assigning into say Object[] then we don't need per element checks. + if (dstComponentType->IsAssignableFrom(srcComponentType)) { + dstObjArray->AssignableMemcpy(dstPos, srcObjArray, srcPos, count); + return; + } + dstObjArray->AssignableCheckingMemcpy(dstPos, srcObjArray, srcPos, count, true); +} + // Template to convert general array to that of its specific primitive type. template inline T* AsPrimitiveArray(mirror::Array* array) { @@ -97,7 +215,17 @@ static void System_arraycopyBooleanUnchecked(JNIEnv* env, jclass, jobject javaSr javaDst, dstPos, count); } +static jint System_identityHashCode(JNIEnv* env, jclass, jobject javaObject) { + if (UNLIKELY(javaObject == nullptr)) { + return 0; + } + ScopedFastNativeObjectAccess soa(env); + mirror::Object* o = soa.Decode(javaObject); + return static_cast(o->IdentityHashCode()); +} + static JNINativeMethod gMethods[] = { + NATIVE_METHOD(System, arraycopy, "!(Ljava/lang/Object;ILjava/lang/Object;II)V"), NATIVE_METHOD(System, arraycopyCharUnchecked, "!([CI[CII)V"), NATIVE_METHOD(System, arraycopyByteUnchecked, "!([BI[BII)V"), NATIVE_METHOD(System, arraycopyShortUnchecked, "!([SI[SII)V"), @@ -106,6 +234,7 @@ static JNINativeMethod gMethods[] = { NATIVE_METHOD(System, arraycopyFloatUnchecked, "!([FI[FII)V"), NATIVE_METHOD(System, arraycopyDoubleUnchecked, "!([DI[DII)V"), NATIVE_METHOD(System, arraycopyBooleanUnchecked, "!([ZI[ZII)V"), + NATIVE_METHOD(System, identityHashCode, "!(Ljava/lang/Object;)I"), }; void register_java_lang_System(JNIEnv* env) { -- 2.11.0