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_MEMBER(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    RETURN_INT(dvmArrayClassElementWidth(clazz));
56}
57
58/*
59 * public native boolean compareAndSwapInt(Object obj, long offset,
60 *         int expectedValue, int newValue);
61 */
62static void Dalvik_sun_misc_Unsafe_compareAndSwapInt(const u4* args,
63    JValue* pResult)
64{
65    // We ignore the this pointer in args[0].
66    Object* obj = (Object*) args[1];
67    s8 offset = GET_ARG_LONG(args, 2);
68    s4 expectedValue = args[4];
69    s4 newValue = args[5];
70    volatile int32_t* address = (volatile int32_t*) (((u1*) obj) + offset);
71
72    // Note: android_atomic_release_cas() returns 0 on success, not failure.
73    int result = android_atomic_release_cas(expectedValue, newValue, address);
74
75    RETURN_BOOLEAN(result == 0);
76}
77
78/*
79 * public native boolean compareAndSwapLong(Object obj, long offset,
80 *         long expectedValue, long newValue);
81 */
82static void Dalvik_sun_misc_Unsafe_compareAndSwapLong(const u4* args,
83    JValue* pResult)
84{
85    // We ignore the this pointer in args[0].
86    Object* obj = (Object*) args[1];
87    s8 offset = GET_ARG_LONG(args, 2);
88    s8 expectedValue = GET_ARG_LONG(args, 4);
89    s8 newValue = GET_ARG_LONG(args, 6);
90    volatile int64_t* address = (volatile int64_t*) (((u1*) obj) + offset);
91
92    // Note: android_atomic_cmpxchg() returns 0 on success, not failure.
93    int result =
94        dvmQuasiAtomicCas64(expectedValue, newValue, address);
95
96    RETURN_BOOLEAN(result == 0);
97}
98
99/*
100 * public native boolean compareAndSwapObject(Object obj, long offset,
101 *         Object expectedValue, Object newValue);
102 */
103static void Dalvik_sun_misc_Unsafe_compareAndSwapObject(const u4* args,
104    JValue* pResult)
105{
106    // We ignore the this pointer in args[0].
107    Object* obj = (Object*) args[1];
108    s8 offset = GET_ARG_LONG(args, 2);
109    Object* expectedValue = (Object*) args[4];
110    Object* newValue = (Object*) args[5];
111    int32_t* address = (int32_t*) (((u1*) obj) + offset);
112
113    // Note: android_atomic_cmpxchg() returns 0 on success, not failure.
114    int result = android_atomic_release_cas((int32_t) expectedValue,
115            (int32_t) newValue, address);
116    dvmWriteBarrierField(obj, address);
117    RETURN_BOOLEAN(result == 0);
118}
119
120/*
121 * public native int getIntVolatile(Object obj, long offset);
122 */
123static void Dalvik_sun_misc_Unsafe_getIntVolatile(const u4* args,
124    JValue* pResult)
125{
126    // We ignore the this pointer in args[0].
127    Object* obj = (Object*) args[1];
128    s8 offset = GET_ARG_LONG(args, 2);
129    volatile int32_t* address = (volatile int32_t*) (((u1*) obj) + offset);
130
131    int32_t value = android_atomic_acquire_load(address);
132    RETURN_INT(value);
133}
134
135/*
136 * public native void putIntVolatile(Object obj, long offset, int newValue);
137 */
138static void Dalvik_sun_misc_Unsafe_putIntVolatile(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    s4 value = (s4) args[4];
145    volatile int32_t* address = (volatile int32_t*) (((u1*) obj) + offset);
146
147    android_atomic_release_store(value, address);
148    RETURN_VOID();
149}
150
151/*
152 * public native long getLongVolatile(Object obj, long offset);
153 */
154static void Dalvik_sun_misc_Unsafe_getLongVolatile(const u4* args,
155    JValue* pResult)
156{
157    // We ignore the this pointer in args[0].
158    Object* obj = (Object*) args[1];
159    s8 offset = GET_ARG_LONG(args, 2);
160    volatile int64_t* address = (volatile int64_t*) (((u1*) obj) + offset);
161
162    assert((offset & 7) == 0);
163    RETURN_LONG(dvmQuasiAtomicRead64(address));
164}
165
166/*
167 * public native void putLongVolatile(Object obj, long offset, long newValue);
168 */
169static void Dalvik_sun_misc_Unsafe_putLongVolatile(const u4* args,
170    JValue* pResult)
171{
172    // We ignore the this pointer in args[0].
173    Object* obj = (Object*) args[1];
174    s8 offset = GET_ARG_LONG(args, 2);
175    s8 value = GET_ARG_LONG(args, 4);
176    volatile int64_t* address = (volatile int64_t*) (((u1*) obj) + offset);
177
178    assert((offset & 7) == 0);
179    dvmQuasiAtomicSwap64(value, address);
180    RETURN_VOID();
181}
182
183/*
184 * public native Object getObjectVolatile(Object obj, long offset);
185 */
186static void Dalvik_sun_misc_Unsafe_getObjectVolatile(const u4* args,
187    JValue* pResult)
188{
189    // We ignore the this pointer in args[0].
190    Object* obj = (Object*) args[1];
191    s8 offset = GET_ARG_LONG(args, 2);
192    volatile int32_t* address = (volatile int32_t*) (((u1*) obj) + offset);
193
194    RETURN_PTR((Object*) android_atomic_acquire_load(address));
195}
196
197/*
198 * public native void putObjectVolatile(Object obj, long offset,
199 *         Object newValue);
200 */
201static void Dalvik_sun_misc_Unsafe_putObjectVolatile(const u4* args,
202    JValue* pResult)
203{
204    // We ignore the this pointer in args[0].
205    Object* obj = (Object*) args[1];
206    s8 offset = GET_ARG_LONG(args, 2);
207    Object* value = (Object*) args[4];
208    volatile int32_t* address = (volatile int32_t*) (((u1*) obj) + offset);
209
210    android_atomic_release_store((int32_t)value, address);
211    dvmWriteBarrierField(obj, (void *)address);
212    RETURN_VOID();
213}
214
215/*
216 * public native int getInt(Object obj, long offset);
217 */
218static void Dalvik_sun_misc_Unsafe_getInt(const u4* args, JValue* pResult)
219{
220    // We ignore the this pointer in args[0].
221    Object* obj = (Object*) args[1];
222    s8 offset = GET_ARG_LONG(args, 2);
223    s4* address = (s4*) (((u1*) obj) + offset);
224
225    RETURN_INT(*address);
226}
227
228/*
229 * public native void putInt(Object obj, long offset, int newValue);
230 */
231static void Dalvik_sun_misc_Unsafe_putInt(const u4* args, JValue* pResult)
232{
233    // We ignore the this pointer in args[0].
234    Object* obj = (Object*) args[1];
235    s8 offset = GET_ARG_LONG(args, 2);
236    s4 value = (s4) args[4];
237    s4* address = (s4*) (((u1*) obj) + offset);
238
239    *address = value;
240    RETURN_VOID();
241}
242
243/*
244 * public native void putOrderedInt(Object obj, long offset, int newValue);
245 */
246static void Dalvik_sun_misc_Unsafe_putOrderedInt(const u4* args,
247    JValue* pResult)
248{
249    // We ignore the this pointer in args[0].
250    Object* obj = (Object*) args[1];
251    s8 offset = GET_ARG_LONG(args, 2);
252    s4 value = (s4) args[4];
253    s4* address = (s4*) (((u1*) obj) + offset);
254
255    ANDROID_MEMBAR_STORE();
256    *address = value;
257    RETURN_VOID();
258}
259
260/*
261 * public native long getLong(Object obj, long offset);
262 */
263static void Dalvik_sun_misc_Unsafe_getLong(const u4* args, JValue* pResult)
264{
265    // We ignore the this pointer in args[0].
266    Object* obj = (Object*) args[1];
267    s8 offset = GET_ARG_LONG(args, 2);
268    s8* address = (s8*) (((u1*) obj) + offset);
269
270    RETURN_LONG(*address);
271}
272
273/*
274 * public native void putLong(Object obj, long offset, long newValue);
275 */
276static void Dalvik_sun_misc_Unsafe_putLong(const u4* args, JValue* pResult)
277{
278    // We ignore the this pointer in args[0].
279    Object* obj = (Object*) args[1];
280    s8 offset = GET_ARG_LONG(args, 2);
281    s8 value = GET_ARG_LONG(args, 4);
282    s8* address = (s8*) (((u1*) obj) + offset);
283
284    *address = value;
285    RETURN_VOID();
286}
287
288/*
289 * public native void putOrderedLong(Object obj, long offset, long newValue);
290 */
291static void Dalvik_sun_misc_Unsafe_putOrderedLong(const u4* args,
292    JValue* pResult)
293{
294    // We ignore the this pointer in args[0].
295    Object* obj = (Object*) args[1];
296    s8 offset = GET_ARG_LONG(args, 2);
297    s8 value = GET_ARG_LONG(args, 4);
298    s8* address = (s8*) (((u1*) obj) + offset);
299
300    ANDROID_MEMBAR_STORE();
301    *address = value;
302    RETURN_VOID();
303}
304
305/*
306 * public native Object getObject(Object obj, long offset);
307 */
308static void Dalvik_sun_misc_Unsafe_getObject(const u4* args, JValue* pResult)
309{
310    // We ignore the this pointer in args[0].
311    Object* obj = (Object*) args[1];
312    s8 offset = GET_ARG_LONG(args, 2);
313    Object** address = (Object**) (((u1*) obj) + offset);
314
315    RETURN_PTR(*address);
316}
317
318/*
319 * public native void putObject(Object obj, long offset, Object newValue);
320 */
321static void Dalvik_sun_misc_Unsafe_putObject(const u4* args, JValue* pResult)
322{
323    // We ignore the this pointer in args[0].
324    Object* obj = (Object*) args[1];
325    s8 offset = GET_ARG_LONG(args, 2);
326    Object* value = (Object*) args[4];
327    Object** address = (Object**) (((u1*) obj) + offset);
328
329    *address = value;
330    dvmWriteBarrierField(obj, address);
331    RETURN_VOID();
332}
333
334/*
335 * public native void putOrderedObject(Object obj, long offset,
336 *      Object newValue);
337 */
338static void Dalvik_sun_misc_Unsafe_putOrderedObject(const u4* args,
339    JValue* pResult)
340{
341    // We ignore the this pointer in args[0].
342    Object* obj = (Object*) args[1];
343    s8 offset = GET_ARG_LONG(args, 2);
344    Object* value = (Object*) args[4];
345    Object** address = (Object**) (((u1*) obj) + offset);
346
347    ANDROID_MEMBAR_STORE();
348    *address = value;
349    dvmWriteBarrierField(obj, address);
350    RETURN_VOID();
351}
352
353const DalvikNativeMethod dvm_sun_misc_Unsafe[] = {
354    { "objectFieldOffset0", "(Ljava/lang/reflect/Field;)J",
355      Dalvik_sun_misc_Unsafe_objectFieldOffset0 },
356    { "arrayBaseOffset0", "(Ljava/lang/Class;)I",
357      Dalvik_sun_misc_Unsafe_arrayBaseOffset0 },
358    { "arrayIndexScale0", "(Ljava/lang/Class;)I",
359      Dalvik_sun_misc_Unsafe_arrayIndexScale0 },
360    { "compareAndSwapInt", "(Ljava/lang/Object;JII)Z",
361      Dalvik_sun_misc_Unsafe_compareAndSwapInt },
362    { "compareAndSwapLong", "(Ljava/lang/Object;JJJ)Z",
363      Dalvik_sun_misc_Unsafe_compareAndSwapLong },
364    { "compareAndSwapObject",
365      "(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Z",
366      Dalvik_sun_misc_Unsafe_compareAndSwapObject },
367    { "getIntVolatile", "(Ljava/lang/Object;J)I",
368      Dalvik_sun_misc_Unsafe_getIntVolatile },
369    { "putIntVolatile", "(Ljava/lang/Object;JI)V",
370      Dalvik_sun_misc_Unsafe_putIntVolatile },
371    { "getLongVolatile", "(Ljava/lang/Object;J)J",
372      Dalvik_sun_misc_Unsafe_getLongVolatile },
373    { "putLongVolatile", "(Ljava/lang/Object;JJ)V",
374      Dalvik_sun_misc_Unsafe_putLongVolatile },
375    { "getObjectVolatile", "(Ljava/lang/Object;J)Ljava/lang/Object;",
376      Dalvik_sun_misc_Unsafe_getObjectVolatile },
377    { "putObjectVolatile", "(Ljava/lang/Object;JLjava/lang/Object;)V",
378      Dalvik_sun_misc_Unsafe_putObjectVolatile },
379    { "getInt", "(Ljava/lang/Object;J)I",
380      Dalvik_sun_misc_Unsafe_getInt },
381    { "putInt", "(Ljava/lang/Object;JI)V",
382      Dalvik_sun_misc_Unsafe_putInt },
383    { "putOrderedInt", "(Ljava/lang/Object;JI)V",
384      Dalvik_sun_misc_Unsafe_putOrderedInt },
385    { "getLong", "(Ljava/lang/Object;J)J",
386      Dalvik_sun_misc_Unsafe_getLong },
387    { "putLong", "(Ljava/lang/Object;JJ)V",
388      Dalvik_sun_misc_Unsafe_putLong },
389    { "putOrderedLong", "(Ljava/lang/Object;JJ)V",
390      Dalvik_sun_misc_Unsafe_putOrderedLong },
391    { "getObject", "(Ljava/lang/Object;J)Ljava/lang/Object;",
392      Dalvik_sun_misc_Unsafe_getObject },
393    { "putObject", "(Ljava/lang/Object;JLjava/lang/Object;)V",
394      Dalvik_sun_misc_Unsafe_putObject },
395    { "putOrderedObject", "(Ljava/lang/Object;JLjava/lang/Object;)V",
396      Dalvik_sun_misc_Unsafe_putOrderedObject },
397    { NULL, NULL, NULL },
398};
399