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) {