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 41 template <typename T> static T cast(jint address) { 42 return reinterpret_cast<T>(static_cast<uintptr_t>(address)); 43 } 44 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 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 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 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 92 static jbyte Memory_peekByte(JNIEnv*, jclass, jint srcAddress) { 93 return *cast<const jbyte*>(srcAddress); 94 } 95 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 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 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 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 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 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 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 145 static void Memory_pokeByte(JNIEnv*, jclass, jint dstAddress, jbyte value) { 146 *cast<jbyte*>(dstAddress) = value; 147 } 148 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 }; 354 int register_libcore_io_Memory(JNIEnv* env) { 355 return jniRegisterNativeMethods(env, "libcore/io/Memory", gMethods, NELEM(gMethods)); 356 } 357