1/*
2 * Copyright (C) 2008 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/*
18 * sun.misc.Unsafe
19 */
20#include "Dalvik.h"
21#include "native/InternalNativePriv.h"
22
23
24/*
25 * private static native long objectFieldOffset0(Field field);
26 */
27static void Dalvik_sun_misc_Unsafe_objectFieldOffset0(const u4* args,
28    JValue* pResult)
29{
30    Object* fieldObject = (Object*) args[0];
31    InstField* field = (InstField*) dvmGetFieldFromReflectObj(fieldObject);
32    s8 result = ((s8) field->byteOffset);
33
34    RETURN_LONG(result);
35}
36
37/*
38 * private static native int arrayBaseOffset0(Class clazz);
39 */
40static void Dalvik_sun_misc_Unsafe_arrayBaseOffset0(const u4* args,
41    JValue* pResult)
42{
43    // The base offset is not type-dependent in this vm.
44    UNUSED_PARAMETER(args);
45    RETURN_INT(offsetof(ArrayObject, contents));
46}
47
48/*
49 * private static native int arrayIndexScale0(Class clazz);
50 */
51static void Dalvik_sun_misc_Unsafe_arrayIndexScale0(const u4* args,
52    JValue* pResult)
53{
54    ClassObject* clazz = (ClassObject*) args[0];
55    int result;
56
57    if ((clazz == gDvm.classArrayBoolean) ||
58            (clazz == gDvm.classArrayByte)) {
59        result = sizeof(u1);
60    } else if ((clazz == gDvm.classArrayChar) ||
61            (clazz == gDvm.classArrayShort)) {
62        result = sizeof(u2);
63    } else if ((clazz == gDvm.classArrayLong) ||
64            (clazz == gDvm.classArrayDouble)) {
65        result = sizeof(u8);
66    } else {
67        result = sizeof(u4);
68    }
69
70    RETURN_INT(result);
71}
72
73/*
74 * public native boolean compareAndSwapInt(Object obj, long offset,
75 *         int expectedValue, int newValue);
76 */
77static void Dalvik_sun_misc_Unsafe_compareAndSwapInt(const u4* args,
78    JValue* pResult)
79{
80    // We ignore the this pointer in args[0].
81    Object* obj = (Object*) args[1];
82    s8 offset = GET_ARG_LONG(args, 2);
83    s4 expectedValue = args[4];
84    s4 newValue = args[5];
85    volatile int32_t* address = (volatile int32_t*) (((u1*) obj) + offset);
86
87    // Note: android_atomic_cmpxchg() returns 0 on success, not failure.
88    int result = android_atomic_cmpxchg(expectedValue, newValue, address);
89
90    RETURN_BOOLEAN(result == 0);
91}
92
93/*
94 * public native boolean compareAndSwapLong(Object obj, long offset,
95 *         long expectedValue, long newValue);
96 */
97static void Dalvik_sun_misc_Unsafe_compareAndSwapLong(const u4* args,
98    JValue* pResult)
99{
100    // We ignore the this pointer in args[0].
101    Object* obj = (Object*) args[1];
102    s8 offset = GET_ARG_LONG(args, 2);
103    s8 expectedValue = GET_ARG_LONG(args, 4);
104    s8 newValue = GET_ARG_LONG(args, 6);
105    volatile int64_t* address = (volatile int64_t*) (((u1*) obj) + offset);
106
107    // Note: android_atomic_cmpxchg() returns 0 on success, not failure.
108    int result =
109        android_quasiatomic_cmpxchg_64(expectedValue, newValue, address);
110
111    RETURN_BOOLEAN(result == 0);
112}
113
114/*
115 * public native boolean compareAndSwapObject(Object obj, long offset,
116 *         Object expectedValue, Object newValue);
117 */
118static void Dalvik_sun_misc_Unsafe_compareAndSwapObject(const u4* args,
119    JValue* pResult)
120{
121    // We ignore the this pointer in args[0].
122    Object* obj = (Object*) args[1];
123    s8 offset = GET_ARG_LONG(args, 2);
124    Object* expectedValue = (Object*) args[4];
125    Object* newValue = (Object*) args[5];
126    int32_t* address = (int32_t*) (((u1*) obj) + offset);
127
128    // Note: android_atomic_cmpxchg() returns 0 on success, not failure.
129    int result = android_atomic_cmpxchg((int32_t) expectedValue,
130            (int32_t) newValue, address);
131
132    RETURN_BOOLEAN(result == 0);
133}
134
135/*
136 * public native int getIntVolatile(Object obj, long offset);
137 */
138static void Dalvik_sun_misc_Unsafe_getIntVolatile(const u4* args,
139    JValue* pResult)
140{
141    // We ignore the this pointer in args[0].
142    Object* obj = (Object*) args[1];
143    s8 offset = GET_ARG_LONG(args, 2);
144    volatile s4* address = (volatile s4*) (((u1*) obj) + offset);
145
146    RETURN_INT(*address);
147}
148
149/*
150 * public native void putIntVolatile(Object obj, long offset, int newValue);
151 */
152static void Dalvik_sun_misc_Unsafe_putIntVolatile(const u4* args,
153    JValue* pResult)
154{
155    // We ignore the this pointer in args[0].
156    Object* obj = (Object*) args[1];
157    s8 offset = GET_ARG_LONG(args, 2);
158    s4 value = (s4) args[4];
159    volatile s4* address = (volatile s4*) (((u1*) obj) + offset);
160
161    *address = value;
162    RETURN_VOID();
163}
164
165/*
166 * public native long getLongVolatile(Object obj, long offset);
167 */
168static void Dalvik_sun_misc_Unsafe_getLongVolatile(const u4* args,
169    JValue* pResult)
170{
171    // We ignore the this pointer in args[0].
172    Object* obj = (Object*) args[1];
173    s8 offset = GET_ARG_LONG(args, 2);
174    volatile s8* address = (volatile s8*) (((u1*) obj) + offset);
175
176    RETURN_LONG(android_quasiatomic_read_64(address));
177}
178
179/*
180 * public native void putLongVolatile(Object obj, long offset, long newValue);
181 */
182static void Dalvik_sun_misc_Unsafe_putLongVolatile(const u4* args,
183    JValue* pResult)
184{
185    // We ignore the this pointer in args[0].
186    Object* obj = (Object*) args[1];
187    s8 offset = GET_ARG_LONG(args, 2);
188    s8 value = GET_ARG_LONG(args, 4);
189    volatile s8* address = (volatile s8*) (((u1*) obj) + offset);
190
191    android_quasiatomic_swap_64(value, address);
192    RETURN_VOID();
193}
194
195/*
196 * public native Object getObjectVolatile(Object obj, long offset);
197 */
198static void Dalvik_sun_misc_Unsafe_getObjectVolatile(const u4* args,
199    JValue* pResult)
200{
201    // We ignore the this pointer in args[0].
202    Object* obj = (Object*) args[1];
203    s8 offset = GET_ARG_LONG(args, 2);
204    volatile Object** address = (volatile Object**) (((u1*) obj) + offset);
205
206    RETURN_PTR((void*) *address);
207}
208
209/*
210 * public native void putObjectVolatile(Object obj, long offset,
211 *         Object newValue);
212 */
213static void Dalvik_sun_misc_Unsafe_putObjectVolatile(const u4* args,
214    JValue* pResult)
215{
216    // We ignore the this pointer in args[0].
217    Object* obj = (Object*) args[1];
218    s8 offset = GET_ARG_LONG(args, 2);
219    Object* value = (Object*) args[4];
220    volatile Object** address = (volatile Object**) (((u1*) obj) + offset);
221
222    *address = value;
223    RETURN_VOID();
224}
225
226/*
227 * public native int getInt(Object obj, long offset);
228 */
229static void Dalvik_sun_misc_Unsafe_getInt(const u4* args, JValue* pResult)
230{
231    // We ignore the this pointer in args[0].
232    Object* obj = (Object*) args[1];
233    s8 offset = GET_ARG_LONG(args, 2);
234    s4* address = (s4*) (((u1*) obj) + offset);
235
236    RETURN_INT(*address);
237}
238
239/*
240 * public native void putInt(Object obj, long offset, int newValue);
241 */
242static void Dalvik_sun_misc_Unsafe_putInt(const u4* args, JValue* pResult)
243{
244    // We ignore the this pointer in args[0].
245    Object* obj = (Object*) args[1];
246    s8 offset = GET_ARG_LONG(args, 2);
247    s4 value = (s4) args[4];
248    s4* address = (s4*) (((u1*) obj) + offset);
249
250    *address = value;
251    RETURN_VOID();
252}
253
254/*
255 * public native long getLong(Object obj, long offset);
256 */
257static void Dalvik_sun_misc_Unsafe_getLong(const u4* args, JValue* pResult)
258{
259    // We ignore the this pointer in args[0].
260    Object* obj = (Object*) args[1];
261    s8 offset = GET_ARG_LONG(args, 2);
262    s8* address = (s8*) (((u1*) obj) + offset);
263
264    RETURN_LONG(*address);
265}
266
267/*
268 * public native void putLong(Object obj, long offset, long newValue);
269 */
270static void Dalvik_sun_misc_Unsafe_putLong(const u4* args, JValue* pResult)
271{
272    // We ignore the this pointer in args[0].
273    Object* obj = (Object*) args[1];
274    s8 offset = GET_ARG_LONG(args, 2);
275    s8 value = GET_ARG_LONG(args, 4);
276    s8* address = (s8*) (((u1*) obj) + offset);
277
278    *address = value;
279    RETURN_VOID();
280}
281
282/*
283 * public native Object getObject(Object obj, long offset);
284 */
285static void Dalvik_sun_misc_Unsafe_getObject(const u4* args, JValue* pResult)
286{
287    // We ignore the this pointer in args[0].
288    Object* obj = (Object*) args[1];
289    s8 offset = GET_ARG_LONG(args, 2);
290    Object** address = (Object**) (((u1*) obj) + offset);
291
292    RETURN_PTR(*address);
293}
294
295/*
296 * public native void putObject(Object obj, long offset, Object newValue);
297 */
298static void Dalvik_sun_misc_Unsafe_putObject(const u4* args, JValue* pResult)
299{
300    // We ignore the this pointer in args[0].
301    Object* obj = (Object*) args[1];
302    s8 offset = GET_ARG_LONG(args, 2);
303    Object* value = (Object*) args[4];
304    Object** address = (Object**) (((u1*) obj) + offset);
305
306    *address = value;
307    RETURN_VOID();
308}
309
310const DalvikNativeMethod dvm_sun_misc_Unsafe[] = {
311    { "objectFieldOffset0", "(Ljava/lang/reflect/Field;)J",
312      Dalvik_sun_misc_Unsafe_objectFieldOffset0 },
313    { "arrayBaseOffset0", "(Ljava/lang/Class;)I",
314      Dalvik_sun_misc_Unsafe_arrayBaseOffset0 },
315    { "arrayIndexScale0", "(Ljava/lang/Class;)I",
316      Dalvik_sun_misc_Unsafe_arrayIndexScale0 },
317    { "compareAndSwapInt", "(Ljava/lang/Object;JII)Z",
318      Dalvik_sun_misc_Unsafe_compareAndSwapInt },
319    { "compareAndSwapLong", "(Ljava/lang/Object;JJJ)Z",
320      Dalvik_sun_misc_Unsafe_compareAndSwapLong },
321    { "compareAndSwapObject",
322      "(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Z",
323      Dalvik_sun_misc_Unsafe_compareAndSwapObject },
324    { "getIntVolatile", "(Ljava/lang/Object;J)I",
325      Dalvik_sun_misc_Unsafe_getIntVolatile },
326    { "putIntVolatile", "(Ljava/lang/Object;JI)V",
327      Dalvik_sun_misc_Unsafe_putIntVolatile },
328    { "getLongVolatile", "(Ljava/lang/Object;J)J",
329      Dalvik_sun_misc_Unsafe_getLongVolatile },
330    { "putLongVolatile", "(Ljava/lang/Object;JJ)V",
331      Dalvik_sun_misc_Unsafe_putLongVolatile },
332    { "getObjectVolatile", "(Ljava/lang/Object;J)Ljava/lang/Object;",
333      Dalvik_sun_misc_Unsafe_getObjectVolatile },
334    { "putObjectVolatile", "(Ljava/lang/Object;JLjava/lang/Object;)V",
335      Dalvik_sun_misc_Unsafe_putObjectVolatile },
336    { "getInt", "(Ljava/lang/Object;J)I",
337      Dalvik_sun_misc_Unsafe_getInt },
338    { "putInt", "(Ljava/lang/Object;JI)V",
339      Dalvik_sun_misc_Unsafe_putInt },
340    { "getLong", "(Ljava/lang/Object;J)J",
341      Dalvik_sun_misc_Unsafe_getLong },
342    { "putLong", "(Ljava/lang/Object;JJ)V",
343      Dalvik_sun_misc_Unsafe_putLong },
344    { "getObject", "(Ljava/lang/Object;J)Ljava/lang/Object;",
345      Dalvik_sun_misc_Unsafe_getObject },
346    { "putObject", "(Ljava/lang/Object;JLjava/lang/Object;)V",
347      Dalvik_sun_misc_Unsafe_putObject },
348    { NULL, NULL, NULL },
349};
350
351