1 /*
2 * Copyright (C) 2007 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 #define LOG_TAG "Memory"
18
19 #include "JNIHelp.h"
20 #include "JniConstants.h"
21 #include "nativehelper/jni_macros.h"
22 #include "Portability.h"
23 #include "ScopedBytes.h"
24 #include "ScopedPrimitiveArray.h"
25
26 #include <errno.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <sys/mman.h>
30
31 // Use packed structures for access to unaligned data on targets with alignment restrictions.
32 // The compiler will generate appropriate code to access these structures without
33 // generating alignment exceptions.
get_unaligned(const T * address)34 template <typename T> static inline T get_unaligned(const T* address) {
35 struct unaligned { T v; } __attribute__ ((packed));
36 const unaligned* p = reinterpret_cast<const unaligned*>(address);
37 return p->v;
38 }
39
put_unaligned(T * address,T v)40 template <typename T> static inline void put_unaligned(T* address, T v) {
41 struct unaligned { T v; } __attribute__ ((packed));
42 unaligned* p = reinterpret_cast<unaligned*>(address);
43 p->v = v;
44 }
45
cast(jlong address)46 template <typename T> static T cast(jlong address) {
47 return reinterpret_cast<T>(static_cast<uintptr_t>(address));
48 }
49
50 // Byte-swap 2 jshort values packed in a jint.
bswap_2x16(jint v)51 static inline jint bswap_2x16(jint v) {
52 // v is initially ABCD
53 #if defined(__mips__) && defined(__mips_isa_rev) && (__mips_isa_rev >= 2)
54 __asm__ volatile ("wsbh %0, %0" : "+r" (v)); // v=BADC
55 #else
56 v = bswap_32(v); // v=DCBA
57 v = (v << 16) | ((v >> 16) & 0xffff); // v=BADC
58 #endif
59 return v;
60 }
61
swapShorts(jshort * dstShorts,const jshort * srcShorts,size_t count)62 static inline void swapShorts(jshort* dstShorts, const jshort* srcShorts, size_t count) {
63 // Do 32-bit swaps as long as possible...
64 jint* dst = reinterpret_cast<jint*>(dstShorts);
65 const jint* src = reinterpret_cast<const jint*>(srcShorts);
66 for (size_t i = 0; i < count / 2; ++i) {
67 jint v = get_unaligned<jint>(src++);
68 put_unaligned<jint>(dst++, bswap_2x16(v));
69 }
70 if ((count % 2) != 0) {
71 jshort v = get_unaligned<jshort>(reinterpret_cast<const jshort*>(src));
72 put_unaligned<jshort>(reinterpret_cast<jshort*>(dst), bswap_16(v));
73 }
74 }
75
swapInts(jint * dstInts,const jint * srcInts,size_t count)76 static inline void swapInts(jint* dstInts, const jint* srcInts, size_t count) {
77 for (size_t i = 0; i < count; ++i) {
78 jint v = get_unaligned<int>(srcInts++);
79 put_unaligned<jint>(dstInts++, bswap_32(v));
80 }
81 }
82
swapLongs(jlong * dstLongs,const jlong * srcLongs,size_t count)83 static inline void swapLongs(jlong* dstLongs, const jlong* srcLongs, size_t count) {
84 jint* dst = reinterpret_cast<jint*>(dstLongs);
85 const jint* src = reinterpret_cast<const jint*>(srcLongs);
86 for (size_t i = 0; i < count; ++i) {
87 jint v1 = get_unaligned<jint>(src++);
88 jint v2 = get_unaligned<jint>(src++);
89 put_unaligned<jint>(dst++, bswap_32(v2));
90 put_unaligned<jint>(dst++, bswap_32(v1));
91 }
92 }
93
Memory_memmove(JNIEnv * env,jclass,jobject dstObject,jint dstOffset,jobject srcObject,jint srcOffset,jlong length)94 static void Memory_memmove(JNIEnv* env, jclass, jobject dstObject, jint dstOffset, jobject srcObject, jint srcOffset, jlong length) {
95 ScopedBytesRW dstBytes(env, dstObject);
96 if (dstBytes.get() == NULL) {
97 return;
98 }
99 ScopedBytesRO srcBytes(env, srcObject);
100 if (srcBytes.get() == NULL) {
101 return;
102 }
103 memmove(dstBytes.get() + dstOffset, srcBytes.get() + srcOffset, length);
104 }
105
Memory_peekByte(JNIEnv *,jclass,jlong srcAddress)106 static jbyte Memory_peekByte(JNIEnv*, jclass, jlong srcAddress) {
107 return *cast<const jbyte*>(srcAddress);
108 }
109
Memory_peekByteArray(JNIEnv * env,jclass,jlong srcAddress,jbyteArray dst,jint dstOffset,jint byteCount)110 static void Memory_peekByteArray(JNIEnv* env, jclass, jlong srcAddress, jbyteArray dst, jint dstOffset, jint byteCount) {
111 env->SetByteArrayRegion(dst, dstOffset, byteCount, cast<const jbyte*>(srcAddress));
112 }
113
114 // Implements the peekXArray methods:
115 // - For unswapped access, we just use the JNI SetXArrayRegion functions.
116 // - For swapped access, we use GetXArrayElements and our own copy-and-swap routines.
117 // GetXArrayElements is disproportionately cheap on Dalvik because it doesn't copy (as opposed
118 // to Hotspot, which always copies). The SWAP_FN copies and swaps in one pass, which is cheaper
119 // than copying and then swapping in a second pass. Depending on future VM/GC changes, the
120 // swapped case might need to be revisited.
121 #define PEEKER(SCALAR_TYPE, JNI_NAME, SWAP_TYPE, SWAP_FN) { \
122 if (swap) { \
123 Scoped ## JNI_NAME ## ArrayRW elements(env, dst); \
124 if (elements.get() == NULL) { \
125 return; \
126 } \
127 const SWAP_TYPE* src = cast<const SWAP_TYPE*>(srcAddress); \
128 SWAP_FN(reinterpret_cast<SWAP_TYPE*>(elements.get()) + dstOffset, src, count); /*NOLINT*/ \
129 } else { \
130 const SCALAR_TYPE* src = cast<const SCALAR_TYPE*>(srcAddress); \
131 env->Set ## JNI_NAME ## ArrayRegion(dst, dstOffset, count, src); \
132 } \
133 }
134
Memory_peekCharArray(JNIEnv * env,jclass,jlong srcAddress,jcharArray dst,jint dstOffset,jint count,jboolean swap)135 static void Memory_peekCharArray(JNIEnv* env, jclass, jlong srcAddress, jcharArray dst, jint dstOffset, jint count, jboolean swap) {
136 PEEKER(jchar, Char, jshort, swapShorts);
137 }
138
Memory_peekDoubleArray(JNIEnv * env,jclass,jlong srcAddress,jdoubleArray dst,jint dstOffset,jint count,jboolean swap)139 static void Memory_peekDoubleArray(JNIEnv* env, jclass, jlong srcAddress, jdoubleArray dst, jint dstOffset, jint count, 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, jclass, jlong srcAddress, jfloatArray dst, jint dstOffset, jint count, jboolean swap) {
144 PEEKER(jfloat, Float, jint, swapInts);
145 }
146
Memory_peekIntArray(JNIEnv * env,jclass,jlong srcAddress,jintArray dst,jint dstOffset,jint count,jboolean swap)147 static void Memory_peekIntArray(JNIEnv* env, jclass, jlong srcAddress, jintArray dst, jint dstOffset, jint count, jboolean swap) {
148 PEEKER(jint, Int, jint, swapInts);
149 }
150
Memory_peekLongArray(JNIEnv * env,jclass,jlong srcAddress,jlongArray dst,jint dstOffset,jint count,jboolean swap)151 static void Memory_peekLongArray(JNIEnv* env, jclass, jlong srcAddress, jlongArray dst, jint dstOffset, jint count, jboolean swap) {
152 PEEKER(jlong, Long, jlong, swapLongs);
153 }
154
Memory_peekShortArray(JNIEnv * env,jclass,jlong srcAddress,jshortArray dst,jint dstOffset,jint count,jboolean swap)155 static void Memory_peekShortArray(JNIEnv* env, jclass, jlong srcAddress, jshortArray dst, jint dstOffset, jint count, jboolean swap) {
156 PEEKER(jshort, Short, jshort, swapShorts);
157 }
158
Memory_pokeByte(JNIEnv *,jclass,jlong dstAddress,jbyte value)159 static void Memory_pokeByte(JNIEnv*, jclass, jlong dstAddress, jbyte value) {
160 *cast<jbyte*>(dstAddress) = value;
161 }
162
Memory_pokeByteArray(JNIEnv * env,jclass,jlong dstAddress,jbyteArray src,jint offset,jint length)163 static void Memory_pokeByteArray(JNIEnv* env, jclass, jlong dstAddress, jbyteArray src, jint offset, jint length) {
164 env->GetByteArrayRegion(src, offset, length, cast<jbyte*>(dstAddress));
165 }
166
167 // Implements the pokeXArray methods:
168 // - For unswapped access, we just use the JNI GetXArrayRegion functions.
169 // - For swapped access, we use GetXArrayElements and our own copy-and-swap routines.
170 // GetXArrayElements is disproportionately cheap on Dalvik because it doesn't copy (as opposed
171 // to Hotspot, which always copies). The SWAP_FN copies and swaps in one pass, which is cheaper
172 // than copying and then swapping in a second pass. Depending on future VM/GC changes, the
173 // swapped case might need to be revisited.
174 #define POKER(SCALAR_TYPE, JNI_NAME, SWAP_TYPE, SWAP_FN) { \
175 if (swap) { \
176 Scoped ## JNI_NAME ## ArrayRO elements(env, src); \
177 if (elements.get() == NULL) { \
178 return; \
179 } \
180 const SWAP_TYPE* src = reinterpret_cast<const SWAP_TYPE*>(elements.get()) + srcOffset; \
181 SWAP_FN(cast<SWAP_TYPE*>(dstAddress), src, count); /*NOLINT*/ \
182 } else { \
183 env->Get ## JNI_NAME ## ArrayRegion(src, srcOffset, count, cast<SCALAR_TYPE*>(dstAddress)); /*NOLINT*/ \
184 } \
185 }
186
Memory_pokeCharArray(JNIEnv * env,jclass,jlong dstAddress,jcharArray src,jint srcOffset,jint count,jboolean swap)187 static void Memory_pokeCharArray(JNIEnv* env, jclass, jlong dstAddress, jcharArray src, jint srcOffset, jint count, jboolean swap) {
188 POKER(jchar, Char, jshort, swapShorts);
189 }
190
Memory_pokeDoubleArray(JNIEnv * env,jclass,jlong dstAddress,jdoubleArray src,jint srcOffset,jint count,jboolean swap)191 static void Memory_pokeDoubleArray(JNIEnv* env, jclass, jlong dstAddress, jdoubleArray src, jint srcOffset, jint count, jboolean swap) {
192 POKER(jdouble, Double, jlong, swapLongs);
193 }
194
Memory_pokeFloatArray(JNIEnv * env,jclass,jlong dstAddress,jfloatArray src,jint srcOffset,jint count,jboolean swap)195 static void Memory_pokeFloatArray(JNIEnv* env, jclass, jlong dstAddress, jfloatArray src, jint srcOffset, jint count, jboolean swap) {
196 POKER(jfloat, Float, jint, swapInts);
197 }
198
Memory_pokeIntArray(JNIEnv * env,jclass,jlong dstAddress,jintArray src,jint srcOffset,jint count,jboolean swap)199 static void Memory_pokeIntArray(JNIEnv* env, jclass, jlong dstAddress, jintArray src, jint srcOffset, jint count, jboolean swap) {
200 POKER(jint, Int, jint, swapInts);
201 }
202
Memory_pokeLongArray(JNIEnv * env,jclass,jlong dstAddress,jlongArray src,jint srcOffset,jint count,jboolean swap)203 static void Memory_pokeLongArray(JNIEnv* env, jclass, jlong dstAddress, jlongArray src, jint srcOffset, jint count, jboolean swap) {
204 POKER(jlong, Long, jlong, swapLongs);
205 }
206
Memory_pokeShortArray(JNIEnv * env,jclass,jlong dstAddress,jshortArray src,jint srcOffset,jint count,jboolean swap)207 static void Memory_pokeShortArray(JNIEnv* env, jclass, jlong dstAddress, jshortArray src, jint srcOffset, jint count, jboolean swap) {
208 POKER(jshort, Short, jshort, swapShorts);
209 }
210
Memory_peekShortNative(JNIEnv *,jclass,jlong srcAddress)211 static jshort Memory_peekShortNative(JNIEnv*, jclass, jlong srcAddress) {
212 return get_unaligned<jshort>(cast<const jshort*>(srcAddress));
213 }
214
Memory_pokeShortNative(JNIEnv *,jclass,jlong dstAddress,jshort value)215 static void Memory_pokeShortNative(JNIEnv*, jclass, jlong dstAddress, jshort value) {
216 put_unaligned<jshort>(cast<jshort*>(dstAddress), value);
217 }
218
Memory_peekIntNative(JNIEnv *,jclass,jlong srcAddress)219 static jint Memory_peekIntNative(JNIEnv*, jclass, jlong srcAddress) {
220 return get_unaligned<jint>(cast<const jint*>(srcAddress));
221 }
222
Memory_pokeIntNative(JNIEnv *,jclass,jlong dstAddress,jint value)223 static void Memory_pokeIntNative(JNIEnv*, jclass, jlong dstAddress, jint value) {
224 put_unaligned<jint>(cast<jint*>(dstAddress), value);
225 }
226
Memory_peekLongNative(JNIEnv *,jclass,jlong srcAddress)227 static jlong Memory_peekLongNative(JNIEnv*, jclass, jlong srcAddress) {
228 return get_unaligned<jlong>(cast<const jlong*>(srcAddress));
229 }
230
Memory_pokeLongNative(JNIEnv *,jclass,jlong dstAddress,jlong value)231 static void Memory_pokeLongNative(JNIEnv*, jclass, jlong dstAddress, jlong value) {
232 put_unaligned<jlong>(cast<jlong*>(dstAddress), value);
233 }
234
unsafeBulkCopy(jbyte * dst,const jbyte * src,jint byteCount,jint sizeofElement,jboolean swap)235 static void unsafeBulkCopy(jbyte* dst, const jbyte* src, jint byteCount,
236 jint sizeofElement, jboolean swap) {
237 if (!swap) {
238 memcpy(dst, src, byteCount);
239 return;
240 }
241
242 if (sizeofElement == 2) {
243 jshort* dstShorts = reinterpret_cast<jshort*>(dst);
244 const jshort* srcShorts = reinterpret_cast<const jshort*>(src);
245 swapShorts(dstShorts, srcShorts, byteCount / 2);
246 } else if (sizeofElement == 4) {
247 jint* dstInts = reinterpret_cast<jint*>(dst);
248 const jint* srcInts = reinterpret_cast<const jint*>(src);
249 swapInts(dstInts, srcInts, byteCount / 4);
250 } else if (sizeofElement == 8) {
251 jlong* dstLongs = reinterpret_cast<jlong*>(dst);
252 const jlong* srcLongs = reinterpret_cast<const jlong*>(src);
253 swapLongs(dstLongs, srcLongs, byteCount / 8);
254 }
255 }
256
Memory_unsafeBulkGet(JNIEnv * env,jclass,jobject dstObject,jint dstOffset,jint byteCount,jbyteArray srcArray,jint srcOffset,jint sizeofElement,jboolean swap)257 static void Memory_unsafeBulkGet(JNIEnv* env, jclass, jobject dstObject, jint dstOffset,
258 jint byteCount, jbyteArray srcArray, jint srcOffset, jint sizeofElement, jboolean swap) {
259 ScopedByteArrayRO srcBytes(env, srcArray);
260 if (srcBytes.get() == NULL) {
261 return;
262 }
263 jarray dstArray = reinterpret_cast<jarray>(dstObject);
264 jbyte* dstBytes = reinterpret_cast<jbyte*>(env->GetPrimitiveArrayCritical(dstArray, NULL));
265 if (dstBytes == NULL) {
266 return;
267 }
268 jbyte* dst = dstBytes + dstOffset*sizeofElement;
269 const jbyte* src = srcBytes.get() + srcOffset;
270 unsafeBulkCopy(dst, src, byteCount, sizeofElement, swap);
271 env->ReleasePrimitiveArrayCritical(dstArray, dstBytes, 0);
272 }
273
Memory_unsafeBulkPut(JNIEnv * env,jclass,jbyteArray dstArray,jint dstOffset,jint byteCount,jobject srcObject,jint srcOffset,jint sizeofElement,jboolean swap)274 static void Memory_unsafeBulkPut(JNIEnv* env, jclass, jbyteArray dstArray, jint dstOffset,
275 jint byteCount, jobject srcObject, jint srcOffset, jint sizeofElement, jboolean swap) {
276 ScopedByteArrayRW dstBytes(env, dstArray);
277 if (dstBytes.get() == NULL) {
278 return;
279 }
280 jarray srcArray = reinterpret_cast<jarray>(srcObject);
281 jbyte* srcBytes = reinterpret_cast<jbyte*>(env->GetPrimitiveArrayCritical(srcArray, NULL));
282 if (srcBytes == NULL) {
283 return;
284 }
285 jbyte* dst = dstBytes.get() + dstOffset;
286 const jbyte* src = srcBytes + srcOffset*sizeofElement;
287 unsafeBulkCopy(dst, src, byteCount, sizeofElement, swap);
288 env->ReleasePrimitiveArrayCritical(srcArray, srcBytes, 0);
289 }
290
291 static JNINativeMethod gMethods[] = {
292 NATIVE_METHOD(Memory, memmove, "(Ljava/lang/Object;ILjava/lang/Object;IJ)V"),
293 FAST_NATIVE_METHOD(Memory, peekByte, "(J)B"),
294 NATIVE_METHOD(Memory, peekByteArray, "(J[BII)V"),
295 NATIVE_METHOD(Memory, peekCharArray, "(J[CIIZ)V"),
296 NATIVE_METHOD(Memory, peekDoubleArray, "(J[DIIZ)V"),
297 NATIVE_METHOD(Memory, peekFloatArray, "(J[FIIZ)V"),
298 FAST_NATIVE_METHOD(Memory, peekIntNative, "(J)I"),
299 NATIVE_METHOD(Memory, peekIntArray, "(J[IIIZ)V"),
300 FAST_NATIVE_METHOD(Memory, peekLongNative, "(J)J"),
301 NATIVE_METHOD(Memory, peekLongArray, "(J[JIIZ)V"),
302 FAST_NATIVE_METHOD(Memory, peekShortNative, "(J)S"),
303 NATIVE_METHOD(Memory, peekShortArray, "(J[SIIZ)V"),
304 FAST_NATIVE_METHOD(Memory, pokeByte, "(JB)V"),
305 NATIVE_METHOD(Memory, pokeByteArray, "(J[BII)V"),
306 NATIVE_METHOD(Memory, pokeCharArray, "(J[CIIZ)V"),
307 NATIVE_METHOD(Memory, pokeDoubleArray, "(J[DIIZ)V"),
308 NATIVE_METHOD(Memory, pokeFloatArray, "(J[FIIZ)V"),
309 FAST_NATIVE_METHOD(Memory, pokeIntNative, "(JI)V"),
310 NATIVE_METHOD(Memory, pokeIntArray, "(J[IIIZ)V"),
311 FAST_NATIVE_METHOD(Memory, pokeLongNative, "(JJ)V"),
312 NATIVE_METHOD(Memory, pokeLongArray, "(J[JIIZ)V"),
313 FAST_NATIVE_METHOD(Memory, pokeShortNative, "(JS)V"),
314 NATIVE_METHOD(Memory, pokeShortArray, "(J[SIIZ)V"),
315 NATIVE_METHOD(Memory, unsafeBulkGet, "(Ljava/lang/Object;II[BIIZ)V"),
316 NATIVE_METHOD(Memory, unsafeBulkPut, "([BIILjava/lang/Object;IIZ)V"),
317 };
register_libcore_io_Memory(JNIEnv * env)318 void register_libcore_io_Memory(JNIEnv* env) {
319 jniRegisterNativeMethods(env, "libcore/io/Memory", gMethods, NELEM(gMethods));
320 }
321