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 "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