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