Home | History | Annotate | Download | only in native
      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