1 /*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "libcore_io_Memory.h"
18
19 #include <stdlib.h>
20 #include <string.h>
21
22 #include "jni/jni_internal.h"
23 #include "native_util.h"
24 #include "nativehelper/jni_macros.h"
25 #include "nativehelper/scoped_primitive_array.h"
26 #include "scoped_fast_native_object_access-inl.h"
27
28 namespace art HIDDEN {
29
30 // Use packed structures for access to unaligned data on targets with alignment restrictions.
31 // The compiler will generate appropriate code to access these structures without
32 // generating alignment exceptions.
33 template <typename T>
get_unaligned(const T * address)34 static inline T get_unaligned(const T* address) {
35 struct unaligned {
36 T v;
37 } __attribute__((packed));
38 const unaligned* p = reinterpret_cast<const unaligned*>(address);
39 return p->v;
40 }
41
42 template <typename T>
put_unaligned(T * address,T v)43 static inline void put_unaligned(T* address, T v) {
44 struct unaligned {
45 T v;
46 } __attribute__((packed));
47 unaligned* p = reinterpret_cast<unaligned*>(address);
48 p->v = v;
49 }
50
51 template <typename T>
cast(jlong address)52 static T cast(jlong address) {
53 return reinterpret_cast<T>(static_cast<uintptr_t>(address));
54 }
55
56 // Byte-swap 2 jshort values packed in a jint.
bswap_2x16(jint v)57 static inline jint bswap_2x16(jint v) {
58 // v is initially ABCD
59 v = __builtin_bswap32(v); // v=DCBA
60 v = (v << 16) | ((v >> 16) & 0xffff); // v=BADC
61 return v;
62 }
63
swapShorts(jshort * dstShorts,const jshort * srcShorts,size_t count)64 static inline void swapShorts(jshort* dstShorts, const jshort* srcShorts, size_t count) {
65 // Do 32-bit swaps as long as possible...
66 jint* dst = reinterpret_cast<jint*>(dstShorts);
67 const jint* src = reinterpret_cast<const jint*>(srcShorts);
68 for (size_t i = 0; i < count / 2; ++i) {
69 jint v = get_unaligned<jint>(src++);
70 put_unaligned<jint>(dst++, bswap_2x16(v));
71 }
72 if ((count % 2) != 0) {
73 jshort v = get_unaligned<jshort>(reinterpret_cast<const jshort*>(src));
74 put_unaligned<jshort>(reinterpret_cast<jshort*>(dst), __builtin_bswap16(v));
75 }
76 }
77
swapInts(jint * dstInts,const jint * srcInts,size_t count)78 static inline void swapInts(jint* dstInts, const jint* srcInts, size_t count) {
79 for (size_t i = 0; i < count; ++i) {
80 jint v = get_unaligned<int>(srcInts++);
81 put_unaligned<jint>(dstInts++, __builtin_bswap32(v));
82 }
83 }
84
swapLongs(jlong * dstLongs,const jlong * srcLongs,size_t count)85 static inline void swapLongs(jlong* dstLongs, const jlong* srcLongs, size_t count) {
86 jint* dst = reinterpret_cast<jint*>(dstLongs);
87 const jint* src = reinterpret_cast<const jint*>(srcLongs);
88 for (size_t i = 0; i < count; ++i) {
89 jint v1 = get_unaligned<jint>(src++);
90 jint v2 = get_unaligned<jint>(src++);
91 put_unaligned<jint>(dst++, __builtin_bswap32(v2));
92 put_unaligned<jint>(dst++, __builtin_bswap32(v1));
93 }
94 }
95
Memory_peekByteArray(JNIEnv * env,jclass,jlong srcAddress,jbyteArray dst,jint dstOffset,jint byteCount)96 static void Memory_peekByteArray(
97 JNIEnv* env, jclass, jlong srcAddress, jbyteArray dst, jint dstOffset, jint byteCount) {
98 env->SetByteArrayRegion(dst, dstOffset, byteCount, cast<const jbyte*>(srcAddress));
99 }
100
101 // Implements the peekXArray methods:
102 // - For unswapped access, we just use the JNI SetXArrayRegion functions.
103 // - For swapped access, we use GetXArrayElements and our own copy-and-swap routines.
104 // GetXArrayElements is disproportionately cheap on Dalvik because it doesn't copy (as opposed
105 // to Hotspot, which always copies). The SWAP_FN copies and swaps in one pass, which is cheaper
106 // than copying and then swapping in a second pass. Depending on future VM/GC changes, the
107 // swapped case might need to be revisited.
108 #define PEEKER(SCALAR_TYPE, JNI_NAME, SWAP_TYPE, SWAP_FN) \
109 { \
110 if (swap) { \
111 Scoped##JNI_NAME##ArrayRW elements(env, dst); \
112 if (elements.get() == NULL) { \
113 return; \
114 } \
115 const SWAP_TYPE* src = cast<const SWAP_TYPE*>(srcAddress); \
116 SWAP_FN(reinterpret_cast<SWAP_TYPE*>(elements.get()) + dstOffset, src, count); /*NOLINT*/ \
117 } else { \
118 const SCALAR_TYPE* src = cast<const SCALAR_TYPE*>(srcAddress); \
119 env->Set##JNI_NAME##ArrayRegion(dst, dstOffset, count, src); \
120 } \
121 }
122
Memory_peekCharArray(JNIEnv * env,jclass,jlong srcAddress,jcharArray dst,jint dstOffset,jint count,jboolean swap)123 static void Memory_peekCharArray(JNIEnv* env,
124 jclass,
125 jlong srcAddress,
126 jcharArray dst,
127 jint dstOffset,
128 jint count,
129 jboolean swap) {
130 PEEKER(jchar, Char, jshort, swapShorts);
131 }
132
Memory_peekDoubleArray(JNIEnv * env,jclass,jlong srcAddress,jdoubleArray dst,jint dstOffset,jint count,jboolean swap)133 static void Memory_peekDoubleArray(JNIEnv* env,
134 jclass,
135 jlong srcAddress,
136 jdoubleArray dst,
137 jint dstOffset,
138 jint count,
139 jboolean swap) {
140 PEEKER(jdouble, Double, jlong, swapLongs);
141 }
142
Memory_peekFloatArray(JNIEnv * env,jclass,jlong srcAddress,jfloatArray dst,jint dstOffset,jint count,jboolean swap)143 static void Memory_peekFloatArray(JNIEnv* env,
144 jclass,
145 jlong srcAddress,
146 jfloatArray dst,
147 jint dstOffset,
148 jint count,
149 jboolean swap) {
150 PEEKER(jfloat, Float, jint, swapInts);
151 }
152
Memory_peekIntArray(JNIEnv * env,jclass,jlong srcAddress,jintArray dst,jint dstOffset,jint count,jboolean swap)153 static void Memory_peekIntArray(JNIEnv* env,
154 jclass,
155 jlong srcAddress,
156 jintArray dst,
157 jint dstOffset,
158 jint count,
159 jboolean swap) {
160 PEEKER(jint, Int, jint, swapInts);
161 }
162
Memory_peekLongArray(JNIEnv * env,jclass,jlong srcAddress,jlongArray dst,jint dstOffset,jint count,jboolean swap)163 static void Memory_peekLongArray(JNIEnv* env,
164 jclass,
165 jlong srcAddress,
166 jlongArray dst,
167 jint dstOffset,
168 jint count,
169 jboolean swap) {
170 PEEKER(jlong, Long, jlong, swapLongs);
171 }
172
Memory_peekShortArray(JNIEnv * env,jclass,jlong srcAddress,jshortArray dst,jint dstOffset,jint count,jboolean swap)173 static void Memory_peekShortArray(JNIEnv* env,
174 jclass,
175 jlong srcAddress,
176 jshortArray dst,
177 jint dstOffset,
178 jint count,
179 jboolean swap) {
180 PEEKER(jshort, Short, jshort, swapShorts);
181 }
182
183 // The remaining Memory methods are contained in libcore/luni/src/main/native/libcore_io_Memory.cpp
184 static JNINativeMethod gMethods[] = {
185 FAST_NATIVE_METHOD(Memory, peekByteArray, "(J[BII)V"),
186 FAST_NATIVE_METHOD(Memory, peekCharArray, "(J[CIIZ)V"),
187 FAST_NATIVE_METHOD(Memory, peekDoubleArray, "(J[DIIZ)V"),
188 FAST_NATIVE_METHOD(Memory, peekFloatArray, "(J[FIIZ)V"),
189 FAST_NATIVE_METHOD(Memory, peekIntArray, "(J[IIIZ)V"),
190 FAST_NATIVE_METHOD(Memory, peekLongArray, "(J[JIIZ)V"),
191 FAST_NATIVE_METHOD(Memory, peekShortArray, "(J[SIIZ)V"),
192 };
193
register_libcore_io_Memory(JNIEnv * env)194 void register_libcore_io_Memory(JNIEnv* env) { REGISTER_NATIVE_METHODS("libcore/io/Memory"); }
195
196 } // namespace art
197