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