• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 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 #include "libcore_io_Memory.h"
18 
19 #include <stdlib.h>
20 #include <string.h>
21 
22 #include "jni/jni_internal.h"
23 #include "native_util.h"
24 #include "nativehelper/jni_macros.h"
25 #include "nativehelper/scoped_primitive_array.h"
26 #include "scoped_fast_native_object_access-inl.h"
27 
28 namespace art HIDDEN {
29 
30 // Use packed structures for access to unaligned data on targets with alignment restrictions.
31 // The compiler will generate appropriate code to access these structures without
32 // generating alignment exceptions.
33 template <typename T>
get_unaligned(const T * address)34 static inline T get_unaligned(const T* address) {
35   struct unaligned {
36     T v;
37   } __attribute__((packed));
38   const unaligned* p = reinterpret_cast<const unaligned*>(address);
39   return p->v;
40 }
41 
42 template <typename T>
put_unaligned(T * address,T v)43 static inline void put_unaligned(T* address, T v) {
44   struct unaligned {
45     T v;
46   } __attribute__((packed));
47   unaligned* p = reinterpret_cast<unaligned*>(address);
48   p->v = v;
49 }
50 
51 template <typename T>
cast(jlong address)52 static T cast(jlong address) {
53   return reinterpret_cast<T>(static_cast<uintptr_t>(address));
54 }
55 
56 // Byte-swap 2 jshort values packed in a jint.
bswap_2x16(jint v)57 static inline jint bswap_2x16(jint v) {
58   // v is initially ABCD
59   v = __builtin_bswap32(v);              // v=DCBA
60   v = (v << 16) | ((v >> 16) & 0xffff);  // v=BADC
61   return v;
62 }
63 
swapShorts(jshort * dstShorts,const jshort * srcShorts,size_t count)64 static inline void swapShorts(jshort* dstShorts, const jshort* srcShorts, size_t count) {
65   // Do 32-bit swaps as long as possible...
66   jint* dst = reinterpret_cast<jint*>(dstShorts);
67   const jint* src = reinterpret_cast<const jint*>(srcShorts);
68   for (size_t i = 0; i < count / 2; ++i) {
69     jint v = get_unaligned<jint>(src++);
70     put_unaligned<jint>(dst++, bswap_2x16(v));
71   }
72   if ((count % 2) != 0) {
73     jshort v = get_unaligned<jshort>(reinterpret_cast<const jshort*>(src));
74     put_unaligned<jshort>(reinterpret_cast<jshort*>(dst), __builtin_bswap16(v));
75   }
76 }
77 
swapInts(jint * dstInts,const jint * srcInts,size_t count)78 static inline void swapInts(jint* dstInts, const jint* srcInts, size_t count) {
79   for (size_t i = 0; i < count; ++i) {
80     jint v = get_unaligned<int>(srcInts++);
81     put_unaligned<jint>(dstInts++, __builtin_bswap32(v));
82   }
83 }
84 
swapLongs(jlong * dstLongs,const jlong * srcLongs,size_t count)85 static inline void swapLongs(jlong* dstLongs, const jlong* srcLongs, size_t count) {
86   jint* dst = reinterpret_cast<jint*>(dstLongs);
87   const jint* src = reinterpret_cast<const jint*>(srcLongs);
88   for (size_t i = 0; i < count; ++i) {
89     jint v1 = get_unaligned<jint>(src++);
90     jint v2 = get_unaligned<jint>(src++);
91     put_unaligned<jint>(dst++, __builtin_bswap32(v2));
92     put_unaligned<jint>(dst++, __builtin_bswap32(v1));
93   }
94 }
95 
Memory_peekByteArray(JNIEnv * env,jclass,jlong srcAddress,jbyteArray dst,jint dstOffset,jint byteCount)96 static void Memory_peekByteArray(
97     JNIEnv* env, jclass, jlong srcAddress, jbyteArray dst, jint dstOffset, jint byteCount) {
98   env->SetByteArrayRegion(dst, dstOffset, byteCount, cast<const jbyte*>(srcAddress));
99 }
100 
101 // Implements the peekXArray methods:
102 // - For unswapped access, we just use the JNI SetXArrayRegion functions.
103 // - For swapped access, we use GetXArrayElements and our own copy-and-swap routines.
104 //   GetXArrayElements is disproportionately cheap on Dalvik because it doesn't copy (as opposed
105 //   to Hotspot, which always copies). The SWAP_FN copies and swaps in one pass, which is cheaper
106 //   than copying and then swapping in a second pass. Depending on future VM/GC changes, the
107 //   swapped case might need to be revisited.
108 #define PEEKER(SCALAR_TYPE, JNI_NAME, SWAP_TYPE, SWAP_FN)                                       \
109   {                                                                                             \
110     if (swap) {                                                                                 \
111       Scoped##JNI_NAME##ArrayRW elements(env, dst);                                             \
112       if (elements.get() == NULL) {                                                             \
113         return;                                                                                 \
114       }                                                                                         \
115       const SWAP_TYPE* src = cast<const SWAP_TYPE*>(srcAddress);                                \
116       SWAP_FN(reinterpret_cast<SWAP_TYPE*>(elements.get()) + dstOffset, src, count); /*NOLINT*/ \
117     } else {                                                                                    \
118       const SCALAR_TYPE* src = cast<const SCALAR_TYPE*>(srcAddress);                            \
119       env->Set##JNI_NAME##ArrayRegion(dst, dstOffset, count, src);                              \
120     }                                                                                           \
121   }
122 
Memory_peekCharArray(JNIEnv * env,jclass,jlong srcAddress,jcharArray dst,jint dstOffset,jint count,jboolean swap)123 static void Memory_peekCharArray(JNIEnv* env,
124                                  jclass,
125                                  jlong srcAddress,
126                                  jcharArray dst,
127                                  jint dstOffset,
128                                  jint count,
129                                  jboolean swap) {
130   PEEKER(jchar, Char, jshort, swapShorts);
131 }
132 
Memory_peekDoubleArray(JNIEnv * env,jclass,jlong srcAddress,jdoubleArray dst,jint dstOffset,jint count,jboolean swap)133 static void Memory_peekDoubleArray(JNIEnv* env,
134                                    jclass,
135                                    jlong srcAddress,
136                                    jdoubleArray dst,
137                                    jint dstOffset,
138                                    jint count,
139                                    jboolean swap) {
140   PEEKER(jdouble, Double, jlong, swapLongs);
141 }
142 
Memory_peekFloatArray(JNIEnv * env,jclass,jlong srcAddress,jfloatArray dst,jint dstOffset,jint count,jboolean swap)143 static void Memory_peekFloatArray(JNIEnv* env,
144                                   jclass,
145                                   jlong srcAddress,
146                                   jfloatArray dst,
147                                   jint dstOffset,
148                                   jint count,
149                                   jboolean swap) {
150   PEEKER(jfloat, Float, jint, swapInts);
151 }
152 
Memory_peekIntArray(JNIEnv * env,jclass,jlong srcAddress,jintArray dst,jint dstOffset,jint count,jboolean swap)153 static void Memory_peekIntArray(JNIEnv* env,
154                                 jclass,
155                                 jlong srcAddress,
156                                 jintArray dst,
157                                 jint dstOffset,
158                                 jint count,
159                                 jboolean swap) {
160   PEEKER(jint, Int, jint, swapInts);
161 }
162 
Memory_peekLongArray(JNIEnv * env,jclass,jlong srcAddress,jlongArray dst,jint dstOffset,jint count,jboolean swap)163 static void Memory_peekLongArray(JNIEnv* env,
164                                  jclass,
165                                  jlong srcAddress,
166                                  jlongArray dst,
167                                  jint dstOffset,
168                                  jint count,
169                                  jboolean swap) {
170   PEEKER(jlong, Long, jlong, swapLongs);
171 }
172 
Memory_peekShortArray(JNIEnv * env,jclass,jlong srcAddress,jshortArray dst,jint dstOffset,jint count,jboolean swap)173 static void Memory_peekShortArray(JNIEnv* env,
174                                   jclass,
175                                   jlong srcAddress,
176                                   jshortArray dst,
177                                   jint dstOffset,
178                                   jint count,
179                                   jboolean swap) {
180   PEEKER(jshort, Short, jshort, swapShorts);
181 }
182 
183 // The remaining Memory methods are contained in libcore/luni/src/main/native/libcore_io_Memory.cpp
184 static JNINativeMethod gMethods[] = {
185     FAST_NATIVE_METHOD(Memory, peekByteArray, "(J[BII)V"),
186     FAST_NATIVE_METHOD(Memory, peekCharArray, "(J[CIIZ)V"),
187     FAST_NATIVE_METHOD(Memory, peekDoubleArray, "(J[DIIZ)V"),
188     FAST_NATIVE_METHOD(Memory, peekFloatArray, "(J[FIIZ)V"),
189     FAST_NATIVE_METHOD(Memory, peekIntArray, "(J[IIIZ)V"),
190     FAST_NATIVE_METHOD(Memory, peekLongArray, "(J[JIIZ)V"),
191     FAST_NATIVE_METHOD(Memory, peekShortArray, "(J[SIIZ)V"),
192 };
193 
register_libcore_io_Memory(JNIEnv * env)194 void register_libcore_io_Memory(JNIEnv* env) { REGISTER_NATIVE_METHODS("libcore/io/Memory"); }
195 
196 }  // namespace art
197