Migrate Buffer peek*Array methods to art/
This is the first half of part 2 from
https://b.corp.google.com/issues/176942060#comment4.
We will later use art internals to improve performance.
Test: m
Test: old (https://paste.googleplex.com/5268030335483904) vs new (https://paste.googleplex.com/6393930242326528) benchmark results
Bug: 176942060
Change-Id: Icf59511630b18c5ddbb743f0bfda80f88250b320
diff --git a/runtime/Android.bp b/runtime/Android.bp
index 73a1533..9e0e78e 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -243,6 +243,7 @@
"native/java_lang_reflect_Parameter.cc",
"native/java_lang_reflect_Proxy.cc",
"native/java_util_concurrent_atomic_AtomicLong.cc",
+ "native/libcore_io_Memory.cc",
"native/libcore_util_CharsetUtils.cc",
"native/org_apache_harmony_dalvik_ddmc_DdmServer.cc",
"native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc",
diff --git a/runtime/native/libcore_io_Memory.cc b/runtime/native/libcore_io_Memory.cc
new file mode 100644
index 0000000..5e38280
--- /dev/null
+++ b/runtime/native/libcore_io_Memory.cc
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "libcore_io_Memory.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "jni/jni_internal.h"
+#include "native_util.h"
+#include "nativehelper/jni_macros.h"
+#include "nativehelper/scoped_primitive_array.h"
+#include "scoped_fast_native_object_access-inl.h"
+
+namespace art {
+
+// Use packed structures for access to unaligned data on targets with alignment restrictions.
+// The compiler will generate appropriate code to access these structures without
+// generating alignment exceptions.
+template <typename T>
+static inline T get_unaligned(const T* address) {
+ struct unaligned {
+ T v;
+ } __attribute__((packed));
+ const unaligned* p = reinterpret_cast<const unaligned*>(address);
+ return p->v;
+}
+
+template <typename T>
+static inline void put_unaligned(T* address, T v) {
+ struct unaligned {
+ T v;
+ } __attribute__((packed));
+ unaligned* p = reinterpret_cast<unaligned*>(address);
+ p->v = v;
+}
+
+template <typename T>
+static T cast(jlong address) {
+ return reinterpret_cast<T>(static_cast<uintptr_t>(address));
+}
+
+// Byte-swap 2 jshort values packed in a jint.
+static inline jint bswap_2x16(jint v) {
+ // v is initially ABCD
+ v = __builtin_bswap32(v); // v=DCBA
+ v = (v << 16) | ((v >> 16) & 0xffff); // v=BADC
+ return v;
+}
+
+static inline void swapShorts(jshort* dstShorts, const jshort* srcShorts, size_t count) {
+ // Do 32-bit swaps as long as possible...
+ jint* dst = reinterpret_cast<jint*>(dstShorts);
+ const jint* src = reinterpret_cast<const jint*>(srcShorts);
+ for (size_t i = 0; i < count / 2; ++i) {
+ jint v = get_unaligned<jint>(src++);
+ put_unaligned<jint>(dst++, bswap_2x16(v));
+ }
+ if ((count % 2) != 0) {
+ jshort v = get_unaligned<jshort>(reinterpret_cast<const jshort*>(src));
+ put_unaligned<jshort>(reinterpret_cast<jshort*>(dst), __builtin_bswap16(v));
+ }
+}
+
+static inline void swapInts(jint* dstInts, const jint* srcInts, size_t count) {
+ for (size_t i = 0; i < count; ++i) {
+ jint v = get_unaligned<int>(srcInts++);
+ put_unaligned<jint>(dstInts++, __builtin_bswap32(v));
+ }
+}
+
+static inline void swapLongs(jlong* dstLongs, const jlong* srcLongs, size_t count) {
+ jint* dst = reinterpret_cast<jint*>(dstLongs);
+ const jint* src = reinterpret_cast<const jint*>(srcLongs);
+ for (size_t i = 0; i < count; ++i) {
+ jint v1 = get_unaligned<jint>(src++);
+ jint v2 = get_unaligned<jint>(src++);
+ put_unaligned<jint>(dst++, __builtin_bswap32(v2));
+ put_unaligned<jint>(dst++, __builtin_bswap32(v1));
+ }
+}
+
+static void Memory_peekByteArray(
+ JNIEnv* env, jclass, jlong srcAddress, jbyteArray dst, jint dstOffset, jint byteCount) {
+ env->SetByteArrayRegion(dst, dstOffset, byteCount, cast<const jbyte*>(srcAddress));
+}
+
+// Implements the peekXArray methods:
+// - For unswapped access, we just use the JNI SetXArrayRegion functions.
+// - For swapped access, we use GetXArrayElements and our own copy-and-swap routines.
+// GetXArrayElements is disproportionately cheap on Dalvik because it doesn't copy (as opposed
+// to Hotspot, which always copies). The SWAP_FN copies and swaps in one pass, which is cheaper
+// than copying and then swapping in a second pass. Depending on future VM/GC changes, the
+// swapped case might need to be revisited.
+#define PEEKER(SCALAR_TYPE, JNI_NAME, SWAP_TYPE, SWAP_FN) \
+ { \
+ if (swap) { \
+ Scoped##JNI_NAME##ArrayRW elements(env, dst); \
+ if (elements.get() == NULL) { \
+ return; \
+ } \
+ const SWAP_TYPE* src = cast<const SWAP_TYPE*>(srcAddress); \
+ SWAP_FN(reinterpret_cast<SWAP_TYPE*>(elements.get()) + dstOffset, src, count); /*NOLINT*/ \
+ } else { \
+ const SCALAR_TYPE* src = cast<const SCALAR_TYPE*>(srcAddress); \
+ env->Set##JNI_NAME##ArrayRegion(dst, dstOffset, count, src); \
+ } \
+ }
+
+static void Memory_peekCharArray(JNIEnv* env,
+ jclass,
+ jlong srcAddress,
+ jcharArray dst,
+ jint dstOffset,
+ jint count,
+ jboolean swap) {
+ PEEKER(jchar, Char, jshort, swapShorts);
+}
+
+static void Memory_peekDoubleArray(JNIEnv* env,
+ jclass,
+ jlong srcAddress,
+ jdoubleArray dst,
+ jint dstOffset,
+ jint count,
+ jboolean swap) {
+ PEEKER(jdouble, Double, jlong, swapLongs);
+}
+
+static void Memory_peekFloatArray(JNIEnv* env,
+ jclass,
+ jlong srcAddress,
+ jfloatArray dst,
+ jint dstOffset,
+ jint count,
+ jboolean swap) {
+ PEEKER(jfloat, Float, jint, swapInts);
+}
+
+static void Memory_peekIntArray(JNIEnv* env,
+ jclass,
+ jlong srcAddress,
+ jintArray dst,
+ jint dstOffset,
+ jint count,
+ jboolean swap) {
+ PEEKER(jint, Int, jint, swapInts);
+}
+
+static void Memory_peekLongArray(JNIEnv* env,
+ jclass,
+ jlong srcAddress,
+ jlongArray dst,
+ jint dstOffset,
+ jint count,
+ jboolean swap) {
+ PEEKER(jlong, Long, jlong, swapLongs);
+}
+
+static void Memory_peekShortArray(JNIEnv* env,
+ jclass,
+ jlong srcAddress,
+ jshortArray dst,
+ jint dstOffset,
+ jint count,
+ jboolean swap) {
+ PEEKER(jshort, Short, jshort, swapShorts);
+}
+
+// The remaining Memory methods are contained in libcore/luni/src/main/native/libcore_io_Memory.cpp
+static JNINativeMethod gMethods[] = {
+ FAST_NATIVE_METHOD(Memory, peekByteArray, "(J[BII)V"),
+ FAST_NATIVE_METHOD(Memory, peekCharArray, "(J[CIIZ)V"),
+ FAST_NATIVE_METHOD(Memory, peekDoubleArray, "(J[DIIZ)V"),
+ FAST_NATIVE_METHOD(Memory, peekFloatArray, "(J[FIIZ)V"),
+ FAST_NATIVE_METHOD(Memory, peekIntArray, "(J[IIIZ)V"),
+ FAST_NATIVE_METHOD(Memory, peekLongArray, "(J[JIIZ)V"),
+ FAST_NATIVE_METHOD(Memory, peekShortArray, "(J[SIIZ)V"),
+};
+
+void register_libcore_io_Memory(JNIEnv* env) { REGISTER_NATIVE_METHODS("libcore/io/Memory"); }
+
+} // namespace art
diff --git a/runtime/native/libcore_io_Memory.h b/runtime/native/libcore_io_Memory.h
new file mode 100644
index 0000000..8c8a2ec
--- /dev/null
+++ b/runtime/native/libcore_io_Memory.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_NATIVE_LIBCORE_IO_MEMORY_H_
+#define ART_RUNTIME_NATIVE_LIBCORE_IO_MEMORY_H_
+
+#include <jni.h>
+
+namespace art {
+
+void register_libcore_io_Memory(JNIEnv* env);
+
+} // namespace art
+
+#endif // ART_RUNTIME_NATIVE_LIBCORE_IO_MEMORY_H_
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index b090022..e20f883 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -143,6 +143,7 @@
#include "native/java_lang_reflect_Parameter.h"
#include "native/java_lang_reflect_Proxy.h"
#include "native/java_util_concurrent_atomic_AtomicLong.h"
+#include "native/libcore_io_Memory.h"
#include "native/libcore_util_CharsetUtils.h"
#include "native/org_apache_harmony_dalvik_ddmc_DdmServer.h"
#include "native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.h"
@@ -2244,6 +2245,7 @@
register_java_lang_VMClassLoader(env);
register_java_util_concurrent_atomic_AtomicLong(env);
register_jdk_internal_misc_Unsafe(env);
+ register_libcore_io_Memory(env);
register_libcore_util_CharsetUtils(env);
register_org_apache_harmony_dalvik_ddmc_DdmServer(env);
register_org_apache_harmony_dalvik_ddmc_DdmVmInternal(env);