• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "ScopedBytes.h"
22 #include "ScopedPrimitiveArray.h"
23 #include "UniquePtr.h"
24 
25 #include <byteswap.h>
26 #include <errno.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <sys/mman.h>
30 
31 #if defined(__arm__)
32 // 32-bit ARM has load/store alignment restrictions for longs.
33 #define LONG_ALIGNMENT_MASK 0x3
34 #elif defined(__i386__)
35 // x86 can load anything at any alignment.
36 #define LONG_ALIGNMENT_MASK 0x0
37 #else
38 #error unknown load/store alignment restrictions for this architecture
39 #endif
40 
cast(jint address)41 template <typename T> static T cast(jint address) {
42     return reinterpret_cast<T>(static_cast<uintptr_t>(address));
43 }
44 
swapShorts(jshort * dstShorts,const jshort * srcShorts,size_t count)45 static inline void swapShorts(jshort* dstShorts, const jshort* srcShorts, size_t count) {
46     // Do 32-bit swaps as long as possible...
47     jint* dst = reinterpret_cast<jint*>(dstShorts);
48     const jint* src = reinterpret_cast<const jint*>(srcShorts);
49     for (size_t i = 0; i < count / 2; ++i) {
50         jint v = *src++;                            // v=ABCD
51         v = bswap_32(v);                            // v=DCBA
52         jint v2 = (v << 16) | ((v >> 16) & 0xffff); // v=BADC
53         *dst++ = v2;
54     }
55     // ...with one last 16-bit swap if necessary.
56     if ((count % 2) != 0) {
57         jshort v = *reinterpret_cast<const jshort*>(src);
58         *reinterpret_cast<jshort*>(dst) = bswap_16(v);
59     }
60 }
61 
swapInts(jint * dstInts,const jint * srcInts,size_t count)62 static inline void swapInts(jint* dstInts, const jint* srcInts, size_t count) {
63     for (size_t i = 0; i < count; ++i) {
64         jint v = *srcInts++;
65         *dstInts++ = bswap_32(v);
66     }
67 }
68 
swapLongs(jlong * dstLongs,const jlong * srcLongs,size_t count)69 static inline void swapLongs(jlong* dstLongs, const jlong* srcLongs, size_t count) {
70     jint* dst = reinterpret_cast<jint*>(dstLongs);
71     const jint* src = reinterpret_cast<const jint*>(srcLongs);
72     for (size_t i = 0; i < count; ++i) {
73         jint v1 = *src++;
74         jint v2 = *src++;
75         *dst++ = bswap_32(v2);
76         *dst++ = bswap_32(v1);
77     }
78 }
79 
Memory_memmove(JNIEnv * env,jclass,jobject dstObject,jint dstOffset,jobject srcObject,jint srcOffset,jlong length)80 static void Memory_memmove(JNIEnv* env, jclass, jobject dstObject, jint dstOffset, jobject srcObject, jint srcOffset, jlong length) {
81     ScopedBytesRW dstBytes(env, dstObject);
82     if (dstBytes.get() == NULL) {
83         return;
84     }
85     ScopedBytesRO srcBytes(env, srcObject);
86     if (srcBytes.get() == NULL) {
87         return;
88     }
89     memmove(dstBytes.get() + dstOffset, srcBytes.get() + srcOffset, length);
90 }
91 
Memory_peekByte(JNIEnv *,jclass,jint srcAddress)92 static jbyte Memory_peekByte(JNIEnv*, jclass, jint srcAddress) {
93     return *cast<const jbyte*>(srcAddress);
94 }
95 
Memory_peekByteArray(JNIEnv * env,jclass,jint srcAddress,jbyteArray dst,jint dstOffset,jint byteCount)96 static void Memory_peekByteArray(JNIEnv* env, jclass, jint srcAddress, jbyteArray dst, jint dstOffset, jint byteCount) {
97     env->SetByteArrayRegion(dst, dstOffset, byteCount, cast<const jbyte*>(srcAddress));
98 }
99 
100 // Implements the peekXArray methods:
101 // - For unswapped access, we just use the JNI SetXArrayRegion functions.
102 // - For swapped access, we use GetXArrayElements and our own copy-and-swap routines.
103 //   GetXArrayElements is disproportionately cheap on Dalvik because it doesn't copy (as opposed
104 //   to Hotspot, which always copies). The SWAP_FN copies and swaps in one pass, which is cheaper
105 //   than copying and then swapping in a second pass. Depending on future VM/GC changes, the
106 //   swapped case might need to be revisited.
107 #define PEEKER(SCALAR_TYPE, JNI_NAME, SWAP_TYPE, SWAP_FN) { \
108     if (swap) { \
109         Scoped ## JNI_NAME ## ArrayRW elements(env, dst); \
110         if (elements.get() == NULL) { \
111             return; \
112         } \
113         const SWAP_TYPE* src = cast<const SWAP_TYPE*>(srcAddress); \
114         SWAP_FN(reinterpret_cast<SWAP_TYPE*>(elements.get()) + dstOffset, src, count); \
115     } else { \
116         const SCALAR_TYPE* src = cast<const SCALAR_TYPE*>(srcAddress); \
117         env->Set ## JNI_NAME ## ArrayRegion(dst, dstOffset, count, src); \
118     } \
119 }
120 
Memory_peekCharArray(JNIEnv * env,jclass,jint srcAddress,jcharArray dst,jint dstOffset,jint count,jboolean swap)121 static void Memory_peekCharArray(JNIEnv* env, jclass, jint srcAddress, jcharArray dst, jint dstOffset, jint count, jboolean swap) {
122     PEEKER(jchar, Char, jshort, swapShorts);
123 }
124 
Memory_peekDoubleArray(JNIEnv * env,jclass,jint srcAddress,jdoubleArray dst,jint dstOffset,jint count,jboolean swap)125 static void Memory_peekDoubleArray(JNIEnv* env, jclass, jint srcAddress, jdoubleArray dst, jint dstOffset, jint count, jboolean swap) {
126     PEEKER(jdouble, Double, jlong, swapLongs);
127 }
128 
Memory_peekFloatArray(JNIEnv * env,jclass,jint srcAddress,jfloatArray dst,jint dstOffset,jint count,jboolean swap)129 static void Memory_peekFloatArray(JNIEnv* env, jclass, jint srcAddress, jfloatArray dst, jint dstOffset, jint count, jboolean swap) {
130     PEEKER(jfloat, Float, jint, swapInts);
131 }
132 
Memory_peekIntArray(JNIEnv * env,jclass,jint srcAddress,jintArray dst,jint dstOffset,jint count,jboolean swap)133 static void Memory_peekIntArray(JNIEnv* env, jclass, jint srcAddress, jintArray dst, jint dstOffset, jint count, jboolean swap) {
134     PEEKER(jint, Int, jint, swapInts);
135 }
136 
Memory_peekLongArray(JNIEnv * env,jclass,jint srcAddress,jlongArray dst,jint dstOffset,jint count,jboolean swap)137 static void Memory_peekLongArray(JNIEnv* env, jclass, jint srcAddress, jlongArray dst, jint dstOffset, jint count, jboolean swap) {
138     PEEKER(jlong, Long, jlong, swapLongs);
139 }
140 
Memory_peekShortArray(JNIEnv * env,jclass,jint srcAddress,jshortArray dst,jint dstOffset,jint count,jboolean swap)141 static void Memory_peekShortArray(JNIEnv* env, jclass, jint srcAddress, jshortArray dst, jint dstOffset, jint count, jboolean swap) {
142     PEEKER(jshort, Short, jshort, swapShorts);
143 }
144 
Memory_pokeByte(JNIEnv *,jclass,jint dstAddress,jbyte value)145 static void Memory_pokeByte(JNIEnv*, jclass, jint dstAddress, jbyte value) {
146     *cast<jbyte*>(dstAddress) = value;
147 }
148 
Memory_pokeByteArray(JNIEnv * env,jclass,jint dstAddress,jbyteArray src,jint offset,jint length)149 static void Memory_pokeByteArray(JNIEnv* env, jclass, jint dstAddress, jbyteArray src, jint offset, jint length) {
150     env->GetByteArrayRegion(src, offset, length, cast<jbyte*>(dstAddress));
151 }
152 
153 // Implements the pokeXArray methods:
154 // - For unswapped access, we just use the JNI GetXArrayRegion functions.
155 // - For swapped access, we use GetXArrayElements and our own copy-and-swap routines.
156 //   GetXArrayElements is disproportionately cheap on Dalvik because it doesn't copy (as opposed
157 //   to Hotspot, which always copies). The SWAP_FN copies and swaps in one pass, which is cheaper
158 //   than copying and then swapping in a second pass. Depending on future VM/GC changes, the
159 //   swapped case might need to be revisited.
160 #define POKER(SCALAR_TYPE, JNI_NAME, SWAP_TYPE, SWAP_FN) { \
161     if (swap) { \
162         Scoped ## JNI_NAME ## ArrayRO elements(env, src); \
163         if (elements.get() == NULL) { \
164             return; \
165         } \
166         const SWAP_TYPE* src = reinterpret_cast<const SWAP_TYPE*>(elements.get()) + srcOffset; \
167         SWAP_FN(cast<SWAP_TYPE*>(dstAddress), src, count); \
168     } else { \
169         env->Get ## JNI_NAME ## ArrayRegion(src, srcOffset, count, cast<SCALAR_TYPE*>(dstAddress)); \
170     } \
171 }
172 
Memory_pokeCharArray(JNIEnv * env,jclass,jint dstAddress,jcharArray src,jint srcOffset,jint count,jboolean swap)173 static void Memory_pokeCharArray(JNIEnv* env, jclass, jint dstAddress, jcharArray src, jint srcOffset, jint count, jboolean swap) {
174     POKER(jchar, Char, jshort, swapShorts);
175 }
176 
Memory_pokeDoubleArray(JNIEnv * env,jclass,jint dstAddress,jdoubleArray src,jint srcOffset,jint count,jboolean swap)177 static void Memory_pokeDoubleArray(JNIEnv* env, jclass, jint dstAddress, jdoubleArray src, jint srcOffset, jint count, jboolean swap) {
178     POKER(jdouble, Double, jlong, swapLongs);
179 }
180 
Memory_pokeFloatArray(JNIEnv * env,jclass,jint dstAddress,jfloatArray src,jint srcOffset,jint count,jboolean swap)181 static void Memory_pokeFloatArray(JNIEnv* env, jclass, jint dstAddress, jfloatArray src, jint srcOffset, jint count, jboolean swap) {
182     POKER(jfloat, Float, jint, swapInts);
183 }
184 
Memory_pokeIntArray(JNIEnv * env,jclass,jint dstAddress,jintArray src,jint srcOffset,jint count,jboolean swap)185 static void Memory_pokeIntArray(JNIEnv* env, jclass, jint dstAddress, jintArray src, jint srcOffset, jint count, jboolean swap) {
186     POKER(jint, Int, jint, swapInts);
187 }
188 
Memory_pokeLongArray(JNIEnv * env,jclass,jint dstAddress,jlongArray src,jint srcOffset,jint count,jboolean swap)189 static void Memory_pokeLongArray(JNIEnv* env, jclass, jint dstAddress, jlongArray src, jint srcOffset, jint count, jboolean swap) {
190     POKER(jlong, Long, jlong, swapLongs);
191 }
192 
Memory_pokeShortArray(JNIEnv * env,jclass,jint dstAddress,jshortArray src,jint srcOffset,jint count,jboolean swap)193 static void Memory_pokeShortArray(JNIEnv* env, jclass, jint dstAddress, jshortArray src, jint srcOffset, jint count, jboolean swap) {
194     POKER(jshort, Short, jshort, swapShorts);
195 }
196 
Memory_peekShort(JNIEnv *,jclass,jint srcAddress,jboolean swap)197 static jshort Memory_peekShort(JNIEnv*, jclass, jint srcAddress, jboolean swap) {
198     jshort result = *cast<const jshort*>(srcAddress);
199     if (swap) {
200         result = bswap_16(result);
201     }
202     return result;
203 }
204 
Memory_pokeShort(JNIEnv *,jclass,jint dstAddress,jshort value,jboolean swap)205 static void Memory_pokeShort(JNIEnv*, jclass, jint dstAddress, jshort value, jboolean swap) {
206     if (swap) {
207         value = bswap_16(value);
208     }
209     *cast<jshort*>(dstAddress) = value;
210 }
211 
Memory_peekInt(JNIEnv *,jclass,jint srcAddress,jboolean swap)212 static jint Memory_peekInt(JNIEnv*, jclass, jint srcAddress, jboolean swap) {
213     jint result = *cast<const jint*>(srcAddress);
214     if (swap) {
215         result = bswap_32(result);
216     }
217     return result;
218 }
219 
Memory_pokeInt(JNIEnv *,jclass,jint dstAddress,jint value,jboolean swap)220 static void Memory_pokeInt(JNIEnv*, jclass, jint dstAddress, jint value, jboolean swap) {
221     if (swap) {
222         value = bswap_32(value);
223     }
224     *cast<jint*>(dstAddress) = value;
225 }
226 
Memory_peekLong(JNIEnv *,jclass,jint srcAddress,jboolean swap)227 static jlong Memory_peekLong(JNIEnv*, jclass, jint srcAddress, jboolean swap) {
228     jlong result;
229     if ((srcAddress & LONG_ALIGNMENT_MASK) == 0) {
230         result = *cast<const jlong*>(srcAddress);
231     } else {
232         // Handle unaligned memory access one byte at a time
233         const jbyte* src = cast<const jbyte*>(srcAddress);
234         jbyte* dst = reinterpret_cast<jbyte*>(&result);
235         dst[0] = src[0];
236         dst[1] = src[1];
237         dst[2] = src[2];
238         dst[3] = src[3];
239         dst[4] = src[4];
240         dst[5] = src[5];
241         dst[6] = src[6];
242         dst[7] = src[7];
243     }
244     if (swap) {
245         result = bswap_64(result);
246     }
247     return result;
248 }
249 
Memory_pokeLong(JNIEnv *,jclass,jint dstAddress,jlong value,jboolean swap)250 static void Memory_pokeLong(JNIEnv*, jclass, jint dstAddress, jlong value, jboolean swap) {
251     if (swap) {
252         value = bswap_64(value);
253     }
254     if ((dstAddress & LONG_ALIGNMENT_MASK) == 0) {
255         *cast<jlong*>(dstAddress) = value;
256     } else {
257         // Handle unaligned memory access one byte at a time
258         const jbyte* src = reinterpret_cast<const jbyte*>(&value);
259         jbyte* dst = cast<jbyte*>(dstAddress);
260         dst[0] = src[0];
261         dst[1] = src[1];
262         dst[2] = src[2];
263         dst[3] = src[3];
264         dst[4] = src[4];
265         dst[5] = src[5];
266         dst[6] = src[6];
267         dst[7] = src[7];
268     }
269 }
270 
unsafeBulkCopy(jbyte * dst,const jbyte * src,jint byteCount,jint sizeofElement,jboolean swap)271 static void unsafeBulkCopy(jbyte* dst, const jbyte* src, jint byteCount,
272         jint sizeofElement, jboolean swap) {
273     if (!swap) {
274         memcpy(dst, src, byteCount);
275         return;
276     }
277 
278     if (sizeofElement == 2) {
279         jshort* dstShorts = reinterpret_cast<jshort*>(dst);
280         const jshort* srcShorts = reinterpret_cast<const jshort*>(src);
281         swapShorts(dstShorts, srcShorts, byteCount / 2);
282     } else if (sizeofElement == 4) {
283         jint* dstInts = reinterpret_cast<jint*>(dst);
284         const jint* srcInts = reinterpret_cast<const jint*>(src);
285         swapInts(dstInts, srcInts, byteCount / 4);
286     } else if (sizeofElement == 8) {
287         jlong* dstLongs = reinterpret_cast<jlong*>(dst);
288         const jlong* srcLongs = reinterpret_cast<const jlong*>(src);
289         swapLongs(dstLongs, srcLongs, byteCount / 8);
290     }
291 }
292 
Memory_unsafeBulkGet(JNIEnv * env,jclass,jobject dstObject,jint dstOffset,jint byteCount,jbyteArray srcArray,jint srcOffset,jint sizeofElement,jboolean swap)293 static void Memory_unsafeBulkGet(JNIEnv* env, jclass, jobject dstObject, jint dstOffset,
294         jint byteCount, jbyteArray srcArray, jint srcOffset, jint sizeofElement, jboolean swap) {
295     ScopedByteArrayRO srcBytes(env, srcArray);
296     if (srcBytes.get() == NULL) {
297         return;
298     }
299     jarray dstArray = reinterpret_cast<jarray>(dstObject);
300     jbyte* dstBytes = reinterpret_cast<jbyte*>(env->GetPrimitiveArrayCritical(dstArray, NULL));
301     if (dstBytes == NULL) {
302         return;
303     }
304     jbyte* dst = dstBytes + dstOffset*sizeofElement;
305     const jbyte* src = srcBytes.get() + srcOffset;
306     unsafeBulkCopy(dst, src, byteCount, sizeofElement, swap);
307     env->ReleasePrimitiveArrayCritical(dstArray, dstBytes, 0);
308 }
309 
Memory_unsafeBulkPut(JNIEnv * env,jclass,jbyteArray dstArray,jint dstOffset,jint byteCount,jobject srcObject,jint srcOffset,jint sizeofElement,jboolean swap)310 static void Memory_unsafeBulkPut(JNIEnv* env, jclass, jbyteArray dstArray, jint dstOffset,
311         jint byteCount, jobject srcObject, jint srcOffset, jint sizeofElement, jboolean swap) {
312     ScopedByteArrayRW dstBytes(env, dstArray);
313     if (dstBytes.get() == NULL) {
314         return;
315     }
316     jarray srcArray = reinterpret_cast<jarray>(srcObject);
317     jbyte* srcBytes = reinterpret_cast<jbyte*>(env->GetPrimitiveArrayCritical(srcArray, NULL));
318     if (srcBytes == NULL) {
319         return;
320     }
321     jbyte* dst = dstBytes.get() + dstOffset;
322     const jbyte* src = srcBytes + srcOffset*sizeofElement;
323     unsafeBulkCopy(dst, src, byteCount, sizeofElement, swap);
324     env->ReleasePrimitiveArrayCritical(srcArray, srcBytes, 0);
325 }
326 
327 static JNINativeMethod gMethods[] = {
328     NATIVE_METHOD(Memory, memmove, "(Ljava/lang/Object;ILjava/lang/Object;IJ)V"),
329     NATIVE_METHOD(Memory, peekByte, "!(I)B"),
330     NATIVE_METHOD(Memory, peekByteArray, "(I[BII)V"),
331     NATIVE_METHOD(Memory, peekCharArray, "(I[CIIZ)V"),
332     NATIVE_METHOD(Memory, peekDoubleArray, "(I[DIIZ)V"),
333     NATIVE_METHOD(Memory, peekFloatArray, "(I[FIIZ)V"),
334     NATIVE_METHOD(Memory, peekInt, "!(IZ)I"),
335     NATIVE_METHOD(Memory, peekIntArray, "(I[IIIZ)V"),
336     NATIVE_METHOD(Memory, peekLong, "!(IZ)J"),
337     NATIVE_METHOD(Memory, peekLongArray, "(I[JIIZ)V"),
338     NATIVE_METHOD(Memory, peekShort, "!(IZ)S"),
339     NATIVE_METHOD(Memory, peekShortArray, "(I[SIIZ)V"),
340     NATIVE_METHOD(Memory, pokeByte, "!(IB)V"),
341     NATIVE_METHOD(Memory, pokeByteArray, "(I[BII)V"),
342     NATIVE_METHOD(Memory, pokeCharArray, "(I[CIIZ)V"),
343     NATIVE_METHOD(Memory, pokeDoubleArray, "(I[DIIZ)V"),
344     NATIVE_METHOD(Memory, pokeFloatArray, "(I[FIIZ)V"),
345     NATIVE_METHOD(Memory, pokeInt, "!(IIZ)V"),
346     NATIVE_METHOD(Memory, pokeIntArray, "(I[IIIZ)V"),
347     NATIVE_METHOD(Memory, pokeLong, "!(IJZ)V"),
348     NATIVE_METHOD(Memory, pokeLongArray, "(I[JIIZ)V"),
349     NATIVE_METHOD(Memory, pokeShort, "!(ISZ)V"),
350     NATIVE_METHOD(Memory, pokeShortArray, "(I[SIIZ)V"),
351     NATIVE_METHOD(Memory, unsafeBulkGet, "(Ljava/lang/Object;II[BIIZ)V"),
352     NATIVE_METHOD(Memory, unsafeBulkPut, "([BIILjava/lang/Object;IIZ)V"),
353 };
register_libcore_io_Memory(JNIEnv * env)354 void register_libcore_io_Memory(JNIEnv* env) {
355     jniRegisterNativeMethods(env, "libcore/io/Memory", gMethods, NELEM(gMethods));
356 }
357