/*
* Copyright (C) 2008 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.
*/
/*
* sun.misc.Unsafe
*/
#include "Dalvik.h"
#include "native/InternalNativePriv.h"
/*
* private static native long objectFieldOffset0(Field field);
*/
static void Dalvik_sun_misc_Unsafe_objectFieldOffset0(const u4* args,
JValue* pResult)
{
Object* fieldObject = (Object*) args[0];
InstField* field = (InstField*) dvmGetFieldFromReflectObj(fieldObject);
s8 result = ((s8) field->byteOffset);
RETURN_LONG(result);
}
/*
* private static native int arrayBaseOffset0(Class clazz);
*/
static void Dalvik_sun_misc_Unsafe_arrayBaseOffset0(const u4* args,
JValue* pResult)
{
// The base offset is not type-dependent in this vm.
UNUSED_PARAMETER(args);
RETURN_INT(offsetof(ArrayObject, contents));
}
/*
* private static native int arrayIndexScale0(Class clazz);
*/
static void Dalvik_sun_misc_Unsafe_arrayIndexScale0(const u4* args,
JValue* pResult)
{
ClassObject* clazz = (ClassObject*) args[0];
RETURN_INT(dvmArrayClassElementWidth(clazz));
}
/*
* public native boolean compareAndSwapInt(Object obj, long offset,
* int expectedValue, int newValue);
*/
static void Dalvik_sun_misc_Unsafe_compareAndSwapInt(const u4* args,
JValue* pResult)
{
// We ignore the this pointer in args[0].
Object* obj = (Object*) args[1];
s8 offset = GET_ARG_LONG(args, 2);
s4 expectedValue = args[4];
s4 newValue = args[5];
volatile int32_t* address = (volatile int32_t*) (((u1*) obj) + offset);
// Note: android_atomic_release_cas() returns 0 on success, not failure.
int result = android_atomic_release_cas(expectedValue, newValue, address);
RETURN_BOOLEAN(result == 0);
}
/*
* public native boolean compareAndSwapLong(Object obj, long offset,
* long expectedValue, long newValue);
*/
static void Dalvik_sun_misc_Unsafe_compareAndSwapLong(const u4* args,
JValue* pResult)
{
// We ignore the this pointer in args[0].
Object* obj = (Object*) args[1];
s8 offset = GET_ARG_LONG(args, 2);
s8 expectedValue = GET_ARG_LONG(args, 4);
s8 newValue = GET_ARG_LONG(args, 6);
volatile int64_t* address = (volatile int64_t*) (((u1*) obj) + offset);
// Note: android_atomic_cmpxchg() returns 0 on success, not failure.
int result =
dvmQuasiAtomicCas64(expectedValue, newValue, address);
RETURN_BOOLEAN(result == 0);
}
/*
* public native boolean compareAndSwapObject(Object obj, long offset,
* Object expectedValue, Object newValue);
*/
static void Dalvik_sun_misc_Unsafe_compareAndSwapObject(const u4* args,
JValue* pResult)
{
// We ignore the this pointer in args[0].
Object* obj = (Object*) args[1];
s8 offset = GET_ARG_LONG(args, 2);
Object* expectedValue = (Object*) args[4];
Object* newValue = (Object*) args[5];
int32_t* address = (int32_t*) (((u1*) obj) + offset);
// Note: android_atomic_cmpxchg() returns 0 on success, not failure.
int result = android_atomic_release_cas((int32_t) expectedValue,
(int32_t) newValue, address);
dvmWriteBarrierField(obj, address);
RETURN_BOOLEAN(result == 0);
}
/*
* public native int getIntVolatile(Object obj, long offset);
*/
static void Dalvik_sun_misc_Unsafe_getIntVolatile(const u4* args,
JValue* pResult)
{
// We ignore the this pointer in args[0].
Object* obj = (Object*) args[1];
s8 offset = GET_ARG_LONG(args, 2);
volatile int32_t* address = (volatile int32_t*) (((u1*) obj) + offset);
int32_t value = android_atomic_acquire_load(address);
RETURN_INT(value);
}
/*
* public native void putIntVolatile(Object obj, long offset, int newValue);
*/
static void Dalvik_sun_misc_Unsafe_putIntVolatile(const u4* args,
JValue* pResult)
{
// We ignore the this pointer in args[0].
Object* obj = (Object*) args[1];
s8 offset = GET_ARG_LONG(args, 2);
s4 value = (s4) args[4];
volatile int32_t* address = (volatile int32_t*) (((u1*) obj) + offset);
android_atomic_release_store(value, address);
RETURN_VOID();
}
/*
* public native long getLongVolatile(Object obj, long offset);
*/
static void Dalvik_sun_misc_Unsafe_getLongVolatile(const u4* args,
JValue* pResult)
{
// We ignore the this pointer in args[0].
Object* obj = (Object*) args[1];
s8 offset = GET_ARG_LONG(args, 2);
volatile int64_t* address = (volatile int64_t*) (((u1*) obj) + offset);
assert((offset & 7) == 0);
RETURN_LONG(dvmQuasiAtomicRead64(address));
}
/*
* public native void putLongVolatile(Object obj, long offset, long newValue);
*/
static void Dalvik_sun_misc_Unsafe_putLongVolatile(const u4* args,
JValue* pResult)
{
// We ignore the this pointer in args[0].
Object* obj = (Object*) args[1];
s8 offset = GET_ARG_LONG(args, 2);
s8 value = GET_ARG_LONG(args, 4);
volatile int64_t* address = (volatile int64_t*) (((u1*) obj) + offset);
assert((offset & 7) == 0);
dvmQuasiAtomicSwap64(value, address);
RETURN_VOID();
}
/*
* public native Object getObjectVolatile(Object obj, long offset);
*/
static void Dalvik_sun_misc_Unsafe_getObjectVolatile(const u4* args,
JValue* pResult)
{
// We ignore the this pointer in args[0].
Object* obj = (Object*) args[1];
s8 offset = GET_ARG_LONG(args, 2);
volatile int32_t* address = (volatile int32_t*) (((u1*) obj) + offset);
RETURN_PTR((Object*) android_atomic_acquire_load(address));
}
/*
* public native void putObjectVolatile(Object obj, long offset,
* Object newValue);
*/
static void Dalvik_sun_misc_Unsafe_putObjectVolatile(const u4* args,
JValue* pResult)
{
// We ignore the this pointer in args[0].
Object* obj = (Object*) args[1];
s8 offset = GET_ARG_LONG(args, 2);
Object* value = (Object*) args[4];
volatile int32_t* address = (volatile int32_t*) (((u1*) obj) + offset);
android_atomic_release_store((int32_t)value, address);
dvmWriteBarrierField(obj, (void *)address);
RETURN_VOID();
}
/*
* public native int getInt(Object obj, long offset);
*/
static void Dalvik_sun_misc_Unsafe_getInt(const u4* args, JValue* pResult)
{
// We ignore the this pointer in args[0].
Object* obj = (Object*) args[1];
s8 offset = GET_ARG_LONG(args, 2);
s4* address = (s4*) (((u1*) obj) + offset);
RETURN_INT(*address);
}
/*
* public native void putInt(Object obj, long offset, int newValue);
*/
static void Dalvik_sun_misc_Unsafe_putInt(const u4* args, JValue* pResult)
{
// We ignore the this pointer in args[0].
Object* obj = (Object*) args[1];
s8 offset = GET_ARG_LONG(args, 2);
s4 value = (s4) args[4];
s4* address = (s4*) (((u1*) obj) + offset);
*address = value;
RETURN_VOID();
}
/*
* public native long getLong(Object obj, long offset);
*/
static void Dalvik_sun_misc_Unsafe_getLong(const u4* args, JValue* pResult)
{
// We ignore the this pointer in args[0].
Object* obj = (Object*) args[1];
s8 offset = GET_ARG_LONG(args, 2);
s8* address = (s8*) (((u1*) obj) + offset);
RETURN_LONG(*address);
}
/*
* public native void putLong(Object obj, long offset, long newValue);
*/
static void Dalvik_sun_misc_Unsafe_putLong(const u4* args, JValue* pResult)
{
// We ignore the this pointer in args[0].
Object* obj = (Object*) args[1];
s8 offset = GET_ARG_LONG(args, 2);
s8 value = GET_ARG_LONG(args, 4);
s8* address = (s8*) (((u1*) obj) + offset);
*address = value;
RETURN_VOID();
}
/*
* public native Object getObject(Object obj, long offset);
*/
static void Dalvik_sun_misc_Unsafe_getObject(const u4* args, JValue* pResult)
{
// We ignore the this pointer in args[0].
Object* obj = (Object*) args[1];
s8 offset = GET_ARG_LONG(args, 2);
Object** address = (Object**) (((u1*) obj) + offset);
RETURN_PTR(*address);
}
/*
* public native void putObject(Object obj, long offset, Object newValue);
*/
static void Dalvik_sun_misc_Unsafe_putObject(const u4* args, JValue* pResult)
{
// We ignore the this pointer in args[0].
Object* obj = (Object*) args[1];
s8 offset = GET_ARG_LONG(args, 2);
Object* value = (Object*) args[4];
Object** address = (Object**) (((u1*) obj) + offset);
*address = value;
dvmWriteBarrierField(obj, address);
RETURN_VOID();
}
const DalvikNativeMethod dvm_sun_misc_Unsafe[] = {
{ "objectFieldOffset0", "(Ljava/lang/reflect/Field;)J",
Dalvik_sun_misc_Unsafe_objectFieldOffset0 },
{ "arrayBaseOffset0", "(Ljava/lang/Class;)I",
Dalvik_sun_misc_Unsafe_arrayBaseOffset0 },
{ "arrayIndexScale0", "(Ljava/lang/Class;)I",
Dalvik_sun_misc_Unsafe_arrayIndexScale0 },
{ "compareAndSwapInt", "(Ljava/lang/Object;JII)Z",
Dalvik_sun_misc_Unsafe_compareAndSwapInt },
{ "compareAndSwapLong", "(Ljava/lang/Object;JJJ)Z",
Dalvik_sun_misc_Unsafe_compareAndSwapLong },
{ "compareAndSwapObject",
"(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Z",
Dalvik_sun_misc_Unsafe_compareAndSwapObject },
{ "getIntVolatile", "(Ljava/lang/Object;J)I",
Dalvik_sun_misc_Unsafe_getIntVolatile },
{ "putIntVolatile", "(Ljava/lang/Object;JI)V",
Dalvik_sun_misc_Unsafe_putIntVolatile },
{ "getLongVolatile", "(Ljava/lang/Object;J)J",
Dalvik_sun_misc_Unsafe_getLongVolatile },
{ "putLongVolatile", "(Ljava/lang/Object;JJ)V",
Dalvik_sun_misc_Unsafe_putLongVolatile },
{ "getObjectVolatile", "(Ljava/lang/Object;J)Ljava/lang/Object;",
Dalvik_sun_misc_Unsafe_getObjectVolatile },
{ "putObjectVolatile", "(Ljava/lang/Object;JLjava/lang/Object;)V",
Dalvik_sun_misc_Unsafe_putObjectVolatile },
{ "getInt", "(Ljava/lang/Object;J)I",
Dalvik_sun_misc_Unsafe_getInt },
{ "putInt", "(Ljava/lang/Object;JI)V",
Dalvik_sun_misc_Unsafe_putInt },
{ "getLong", "(Ljava/lang/Object;J)J",
Dalvik_sun_misc_Unsafe_getLong },
{ "putLong", "(Ljava/lang/Object;JJ)V",
Dalvik_sun_misc_Unsafe_putLong },
{ "getObject", "(Ljava/lang/Object;J)Ljava/lang/Object;",
Dalvik_sun_misc_Unsafe_getObject },
{ "putObject", "(Ljava/lang/Object;JLjava/lang/Object;)V",
Dalvik_sun_misc_Unsafe_putObject },
{ NULL, NULL, NULL },
};