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