Unsafe: Add native implementations for new methods.
Change-Id: I9324deffa068d9e5d9e581363cec6c7fae969537
diff --git a/runtime/native/sun_misc_Unsafe.cc b/runtime/native/sun_misc_Unsafe.cc
index 65dece0..d613f73 100644
--- a/runtime/native/sun_misc_Unsafe.cc
+++ b/runtime/native/sun_misc_Unsafe.cc
@@ -182,6 +182,189 @@
Primitive::Type primitive_type = component->GetPrimitiveType();
return Primitive::ComponentSize(primitive_type);
}
+static jint Unsafe_addressSize(JNIEnv* env, jobject) {
+ return sizeof(void*);
+}
+
+static jint Unsafe_pageSize(JNIEnv* env, jobject) {
+ return sysconf(_SC_PAGESIZE);
+}
+
+static jlong Unsafe_allocateMemory(JNIEnv* env, jobject, jlong bytes) {
+ ScopedFastNativeObjectAccess soa(env);
+ // bytes is nonnegative and fits into size_t
+ if (bytes < 0 || bytes != (jlong)(size_t) bytes) {
+ ThrowIllegalAccessException(nullptr, "wrong number of bytes");
+ return 0;
+ }
+ void* mem = malloc(bytes);
+ if (mem == nullptr) {
+ soa.Self()->ThrowOutOfMemoryError("native alloc");
+ return 0;
+ }
+ return (uintptr_t) mem;
+}
+
+static void Unsafe_freeMemory(JNIEnv* env, jobject, jlong address) {
+ free((void*)(uintptr_t)address);
+}
+
+static void Unsafe_setMemory(JNIEnv* env, jobject, jlong address, jlong bytes, jbyte value) {
+ memset((void*)(uintptr_t)address, value, bytes);
+}
+
+static jbyte Unsafe_getByte$(JNIEnv* env, jobject, jlong address) {
+ return *reinterpret_cast<jbyte*>(address);
+}
+
+static void Unsafe_putByte$(JNIEnv* env, jobject, jlong address, jbyte value) {
+ *reinterpret_cast<jbyte*>(address) = value;
+}
+
+static jshort Unsafe_getShort$(JNIEnv* env, jobject, jlong address) {
+ return *reinterpret_cast<jshort*>(address);
+}
+
+static void Unsafe_putShort$(JNIEnv* env, jobject, jlong address, jshort value) {
+ *reinterpret_cast<jshort*>(address) = value;
+}
+
+static jchar Unsafe_getChar$(JNIEnv* env, jobject, jlong address) {
+ return *reinterpret_cast<jchar*>(address);
+}
+
+static void Unsafe_putChar$(JNIEnv* env, jobject, jlong address, jchar value) {
+ *reinterpret_cast<jchar*>(address) = value;
+}
+
+static jint Unsafe_getInt$(JNIEnv* env, jobject, jlong address) {
+ return *reinterpret_cast<jint*>(address);
+}
+
+static void Unsafe_putInt$(JNIEnv* env, jobject, jlong address, jint value) {
+ *reinterpret_cast<jint*>(address) = value;
+}
+
+static jlong Unsafe_getLong$(JNIEnv* env, jobject, jlong address) {
+ return *reinterpret_cast<jlong*>(address);
+}
+
+static void Unsafe_putLong$(JNIEnv* env, jobject, jlong address, jlong value) {
+ *reinterpret_cast<jlong*>(address) = value;
+}
+
+static jfloat Unsafe_getFloat$(JNIEnv* env, jobject, jlong address) {
+ return *reinterpret_cast<jfloat*>(address);
+}
+
+static void Unsafe_putFloat$(JNIEnv* env, jobject, jlong address, jfloat value) {
+ *reinterpret_cast<jfloat*>(address) = value;
+}
+static jdouble Unsafe_getDouble$(JNIEnv* env, jobject, jlong address) {
+ return *reinterpret_cast<jdouble*>(address);
+}
+
+static void Unsafe_putDouble$(JNIEnv* env, jobject, jlong address, jdouble value) {
+ *reinterpret_cast<jdouble*>(address) = value;
+}
+
+static jlong Unsafe_getAddress(JNIEnv* env, jobject, jlong address) {
+ void* p = (void*)(uintptr_t)address;
+ return (uintptr_t)(*(void**)p);
+}
+
+static void Unsafe_copyMemory(JNIEnv *env, jobject unsafe, jlong src, jlong dst, jlong size) {
+ if (size == 0) {
+ return;
+ }
+ // size is nonnegative and fits into size_t
+ if (size < 0 || size != (jlong)(size_t) size) {
+ ScopedFastNativeObjectAccess soa(env);
+ ThrowIllegalAccessException(nullptr, "wrong number of bytes");
+ }
+ size_t sz = (size_t)size;
+ memcpy(reinterpret_cast<void *>(dst), reinterpret_cast<void *>(src), sz);
+}
+
+template<typename T>
+static void copyToArray(jlong srcAddr, mirror::PrimitiveArray<T>* array, size_t size)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ const T* src = reinterpret_cast<T*>(srcAddr);
+ size_t sz = size / sizeof(T);
+ for (size_t i = 0; i < sz; ++i) {
+ array->Set(i, *(src + i));
+ }
+}
+
+template<typename T>
+static void copyFromArray(jlong dstAddr, mirror::PrimitiveArray<T>* array, size_t size)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_){
+ T* dst = reinterpret_cast<T*>(dstAddr);
+ size_t sz = size / sizeof(T);
+ for (size_t i = 0; i < sz; ++i) {
+ *(dst + i) = array->Get(i);
+ }
+}
+
+static void Unsafe_copyMemoryToPrimitiveArray(JNIEnv *env,
+ jobject unsafe,
+ jlong srcAddr,
+ jobject dstObj,
+ jlong dstOffset,
+ jlong size) {
+ ScopedObjectAccess soa(env);
+ if (size == 0) {
+ return;
+ }
+ // size is nonnegative and fits into size_t
+ if (size < 0 || size != (jlong)(size_t) size) {
+ ThrowIllegalAccessException(nullptr, "wrong number of bytes");
+ }
+ size_t sz = (size_t)size;
+ mirror::Object* dst = soa.Decode<mirror::Object*>(dstObj);
+ mirror::Class* component_type = dst->GetClass()->GetComponentType();
+ if (component_type->IsPrimitiveByte() || component_type->IsPrimitiveBoolean()) {
+ copyToArray(srcAddr, dst->AsByteSizedArray(), sz);
+ } else if (component_type->IsPrimitiveShort() || component_type->IsPrimitiveChar()) {
+ copyToArray(srcAddr, dst->AsShortSizedArray(), sz);
+ } else if (component_type->IsPrimitiveInt() || component_type->IsPrimitiveFloat()) {
+ copyToArray(srcAddr, dst->AsIntArray(), sz);
+ } else if (component_type->IsPrimitiveLong() || component_type->IsPrimitiveDouble()) {
+ copyToArray(srcAddr, dst->AsLongArray(), sz);
+ } else {
+ ThrowIllegalAccessException(nullptr, "not a primitive array");
+ }
+}
+
+static void Unsafe_copyMemoryFromPrimitiveArray(JNIEnv *env,
+ jobject unsafe,
+ jobject srcObj,
+ jlong srcOffset,
+ jlong dstAddr,
+ jlong size) {
+ ScopedObjectAccess soa(env);
+ if (size == 0) {
+ return;
+ }
+ // size is nonnegative and fits into size_t
+ if (size < 0 || size != (jlong)(size_t) size) {
+ ThrowIllegalAccessException(nullptr, "wrong number of bytes");
+ }
+ size_t sz = (size_t)size;
+ mirror::Object* src = soa.Decode<mirror::Object*>(srcObj);
+ mirror::Class* component_type = src->GetClass()->GetComponentType();
+ if (component_type->IsPrimitiveByte() || component_type->IsPrimitiveBoolean()) {
+ copyFromArray(dstAddr, src->AsByteSizedArray(), sz);
+ } else if (component_type->IsPrimitiveShort() || component_type->IsPrimitiveChar()) {
+ copyFromArray(dstAddr, src->AsShortSizedArray(), sz);
+ } else if (component_type->IsPrimitiveInt() || component_type->IsPrimitiveFloat()) {
+ copyFromArray(dstAddr, src->AsIntArray(), sz);
+ } else if (component_type->IsPrimitiveLong() || component_type->IsPrimitiveDouble()) {
+ copyFromArray(dstAddr, src->AsLongArray(), sz);
+ } else {
+ ThrowIllegalAccessException(nullptr, "not a primitive array");
+ }
+}
static JNINativeMethod gMethods[] = {
NATIVE_METHOD(Unsafe, compareAndSwapInt, "!(Ljava/lang/Object;JII)Z"),
@@ -204,6 +387,29 @@
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"),
+ NATIVE_METHOD(Unsafe, addressSize, "!()I"),
+ NATIVE_METHOD(Unsafe, pageSize, "!()I"),
+ NATIVE_METHOD(Unsafe, allocateMemory, "!(J)J"),
+ NATIVE_METHOD(Unsafe, freeMemory, "!(J)V"),
+ NATIVE_METHOD(Unsafe, setMemory, "!(JJB)V"),
+ NATIVE_METHOD(Unsafe, getByte$, "!(J)B"),
+ NATIVE_METHOD(Unsafe, putByte$, "!(JB)V"),
+ NATIVE_METHOD(Unsafe, getShort$, "!(J)S"),
+ NATIVE_METHOD(Unsafe, putShort$, "!(JS)V"),
+ NATIVE_METHOD(Unsafe, getChar$, "!(J)C"),
+ NATIVE_METHOD(Unsafe, putChar$, "!(JC)V"),
+ NATIVE_METHOD(Unsafe, getInt$, "!(J)I"),
+ NATIVE_METHOD(Unsafe, putInt$, "!(JI)V"),
+ NATIVE_METHOD(Unsafe, getLong$, "!(J)J"),
+ NATIVE_METHOD(Unsafe, putLong$, "!(JJ)V"),
+ NATIVE_METHOD(Unsafe, getFloat$, "!(J)F"),
+ NATIVE_METHOD(Unsafe, putFloat$, "!(JF)V"),
+ NATIVE_METHOD(Unsafe, getDouble$, "!(J)D"),
+ NATIVE_METHOD(Unsafe, putDouble$, "!(JD)V"),
+ NATIVE_METHOD(Unsafe, getAddress, "!(J)J"),
+ NATIVE_METHOD(Unsafe, copyMemory, "!(JJJ)V"),
+ NATIVE_METHOD(Unsafe, copyMemoryToPrimitiveArray, "!(JLjava/lang/Object;JJ)V"),
+ NATIVE_METHOD(Unsafe, copyMemoryFromPrimitiveArray, "!(Ljava/lang/Object;JJJ)V"),
};
void register_sun_misc_Unsafe(JNIEnv* env) {