197 lines
7.9 KiB
C++
197 lines
7.9 KiB
C++
|
/*
|
||
|
* Copyright (C) 2010 The Android Open Source Project
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*/
|
||
|
|
||
|
#include "libcore_io_Memory.h"
|
||
|
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
#include "jni/jni_internal.h"
|
||
|
#include "native_util.h"
|
||
|
#include "nativehelper/jni_macros.h"
|
||
|
#include "nativehelper/scoped_primitive_array.h"
|
||
|
#include "scoped_fast_native_object_access-inl.h"
|
||
|
|
||
|
namespace art {
|
||
|
|
||
|
// Use packed structures for access to unaligned data on targets with alignment restrictions.
|
||
|
// The compiler will generate appropriate code to access these structures without
|
||
|
// generating alignment exceptions.
|
||
|
template <typename T>
|
||
|
static inline T get_unaligned(const T* address) {
|
||
|
struct unaligned {
|
||
|
T v;
|
||
|
} __attribute__((packed));
|
||
|
const unaligned* p = reinterpret_cast<const unaligned*>(address);
|
||
|
return p->v;
|
||
|
}
|
||
|
|
||
|
template <typename T>
|
||
|
static inline void put_unaligned(T* address, T v) {
|
||
|
struct unaligned {
|
||
|
T v;
|
||
|
} __attribute__((packed));
|
||
|
unaligned* p = reinterpret_cast<unaligned*>(address);
|
||
|
p->v = v;
|
||
|
}
|
||
|
|
||
|
template <typename T>
|
||
|
static T cast(jlong address) {
|
||
|
return reinterpret_cast<T>(static_cast<uintptr_t>(address));
|
||
|
}
|
||
|
|
||
|
// Byte-swap 2 jshort values packed in a jint.
|
||
|
static inline jint bswap_2x16(jint v) {
|
||
|
// v is initially ABCD
|
||
|
v = __builtin_bswap32(v); // v=DCBA
|
||
|
v = (v << 16) | ((v >> 16) & 0xffff); // v=BADC
|
||
|
return v;
|
||
|
}
|
||
|
|
||
|
static inline void swapShorts(jshort* dstShorts, const jshort* srcShorts, size_t count) {
|
||
|
// Do 32-bit swaps as long as possible...
|
||
|
jint* dst = reinterpret_cast<jint*>(dstShorts);
|
||
|
const jint* src = reinterpret_cast<const jint*>(srcShorts);
|
||
|
for (size_t i = 0; i < count / 2; ++i) {
|
||
|
jint v = get_unaligned<jint>(src++);
|
||
|
put_unaligned<jint>(dst++, bswap_2x16(v));
|
||
|
}
|
||
|
if ((count % 2) != 0) {
|
||
|
jshort v = get_unaligned<jshort>(reinterpret_cast<const jshort*>(src));
|
||
|
put_unaligned<jshort>(reinterpret_cast<jshort*>(dst), __builtin_bswap16(v));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static inline void swapInts(jint* dstInts, const jint* srcInts, size_t count) {
|
||
|
for (size_t i = 0; i < count; ++i) {
|
||
|
jint v = get_unaligned<int>(srcInts++);
|
||
|
put_unaligned<jint>(dstInts++, __builtin_bswap32(v));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static inline void swapLongs(jlong* dstLongs, const jlong* srcLongs, size_t count) {
|
||
|
jint* dst = reinterpret_cast<jint*>(dstLongs);
|
||
|
const jint* src = reinterpret_cast<const jint*>(srcLongs);
|
||
|
for (size_t i = 0; i < count; ++i) {
|
||
|
jint v1 = get_unaligned<jint>(src++);
|
||
|
jint v2 = get_unaligned<jint>(src++);
|
||
|
put_unaligned<jint>(dst++, __builtin_bswap32(v2));
|
||
|
put_unaligned<jint>(dst++, __builtin_bswap32(v1));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void Memory_peekByteArray(
|
||
|
JNIEnv* env, jclass, jlong srcAddress, jbyteArray dst, jint dstOffset, jint byteCount) {
|
||
|
env->SetByteArrayRegion(dst, dstOffset, byteCount, cast<const jbyte*>(srcAddress));
|
||
|
}
|
||
|
|
||
|
// Implements the peekXArray methods:
|
||
|
// - For unswapped access, we just use the JNI SetXArrayRegion functions.
|
||
|
// - For swapped access, we use GetXArrayElements and our own copy-and-swap routines.
|
||
|
// GetXArrayElements is disproportionately cheap on Dalvik because it doesn't copy (as opposed
|
||
|
// to Hotspot, which always copies). The SWAP_FN copies and swaps in one pass, which is cheaper
|
||
|
// than copying and then swapping in a second pass. Depending on future VM/GC changes, the
|
||
|
// swapped case might need to be revisited.
|
||
|
#define PEEKER(SCALAR_TYPE, JNI_NAME, SWAP_TYPE, SWAP_FN) \
|
||
|
{ \
|
||
|
if (swap) { \
|
||
|
Scoped##JNI_NAME##ArrayRW elements(env, dst); \
|
||
|
if (elements.get() == NULL) { \
|
||
|
return; \
|
||
|
} \
|
||
|
const SWAP_TYPE* src = cast<const SWAP_TYPE*>(srcAddress); \
|
||
|
SWAP_FN(reinterpret_cast<SWAP_TYPE*>(elements.get()) + dstOffset, src, count); /*NOLINT*/ \
|
||
|
} else { \
|
||
|
const SCALAR_TYPE* src = cast<const SCALAR_TYPE*>(srcAddress); \
|
||
|
env->Set##JNI_NAME##ArrayRegion(dst, dstOffset, count, src); \
|
||
|
} \
|
||
|
}
|
||
|
|
||
|
static void Memory_peekCharArray(JNIEnv* env,
|
||
|
jclass,
|
||
|
jlong srcAddress,
|
||
|
jcharArray dst,
|
||
|
jint dstOffset,
|
||
|
jint count,
|
||
|
jboolean swap) {
|
||
|
PEEKER(jchar, Char, jshort, swapShorts);
|
||
|
}
|
||
|
|
||
|
static void Memory_peekDoubleArray(JNIEnv* env,
|
||
|
jclass,
|
||
|
jlong srcAddress,
|
||
|
jdoubleArray dst,
|
||
|
jint dstOffset,
|
||
|
jint count,
|
||
|
jboolean swap) {
|
||
|
PEEKER(jdouble, Double, jlong, swapLongs);
|
||
|
}
|
||
|
|
||
|
static void Memory_peekFloatArray(JNIEnv* env,
|
||
|
jclass,
|
||
|
jlong srcAddress,
|
||
|
jfloatArray dst,
|
||
|
jint dstOffset,
|
||
|
jint count,
|
||
|
jboolean swap) {
|
||
|
PEEKER(jfloat, Float, jint, swapInts);
|
||
|
}
|
||
|
|
||
|
static void Memory_peekIntArray(JNIEnv* env,
|
||
|
jclass,
|
||
|
jlong srcAddress,
|
||
|
jintArray dst,
|
||
|
jint dstOffset,
|
||
|
jint count,
|
||
|
jboolean swap) {
|
||
|
PEEKER(jint, Int, jint, swapInts);
|
||
|
}
|
||
|
|
||
|
static void Memory_peekLongArray(JNIEnv* env,
|
||
|
jclass,
|
||
|
jlong srcAddress,
|
||
|
jlongArray dst,
|
||
|
jint dstOffset,
|
||
|
jint count,
|
||
|
jboolean swap) {
|
||
|
PEEKER(jlong, Long, jlong, swapLongs);
|
||
|
}
|
||
|
|
||
|
static void Memory_peekShortArray(JNIEnv* env,
|
||
|
jclass,
|
||
|
jlong srcAddress,
|
||
|
jshortArray dst,
|
||
|
jint dstOffset,
|
||
|
jint count,
|
||
|
jboolean swap) {
|
||
|
PEEKER(jshort, Short, jshort, swapShorts);
|
||
|
}
|
||
|
|
||
|
// The remaining Memory methods are contained in libcore/luni/src/main/native/libcore_io_Memory.cpp
|
||
|
static JNINativeMethod gMethods[] = {
|
||
|
FAST_NATIVE_METHOD(Memory, peekByteArray, "(J[BII)V"),
|
||
|
FAST_NATIVE_METHOD(Memory, peekCharArray, "(J[CIIZ)V"),
|
||
|
FAST_NATIVE_METHOD(Memory, peekDoubleArray, "(J[DIIZ)V"),
|
||
|
FAST_NATIVE_METHOD(Memory, peekFloatArray, "(J[FIIZ)V"),
|
||
|
FAST_NATIVE_METHOD(Memory, peekIntArray, "(J[IIIZ)V"),
|
||
|
FAST_NATIVE_METHOD(Memory, peekLongArray, "(J[JIIZ)V"),
|
||
|
FAST_NATIVE_METHOD(Memory, peekShortArray, "(J[SIIZ)V"),
|
||
|
};
|
||
|
|
||
|
void register_libcore_io_Memory(JNIEnv* env) { REGISTER_NATIVE_METHODS("libcore/io/Memory"); }
|
||
|
|
||
|
} // namespace art
|