1/*
2 * Copyright (C) 2007 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
17package sun.misc;
18
19import dalvik.system.VMStack;
20
21import org.apache.harmony.kernel.vm.LangAccess;
22
23import java.lang.reflect.Field;
24import java.lang.reflect.Modifier;
25
26/**
27 * The package name notwithstanding, this class is the quasi-standard
28 * way for Java code to gain access to and use functionality which,
29 * when unsupervised, would allow one to break the pointer/type safety
30 * of Java.
31 */
32public final class Unsafe {
33    /** non-null; unique instance of this class */
34    private static final Unsafe THE_ONE = new Unsafe();
35
36    /** non-null; the lang-access utility instance */
37    private final LangAccess lang;
38
39    /**
40     * This class is only privately instantiable.
41     */
42    private Unsafe() {
43        lang = LangAccess.getInstance();
44    }
45
46    /**
47     * Gets the unique instance of this class. This is only allowed in
48     * very limited situations.
49     */
50    public static Unsafe getUnsafe() {
51        /*
52         * Only code on the bootclasspath is allowed to get at the
53         * Unsafe instance.
54         */
55        ClassLoader calling = VMStack.getCallingClassLoader2();
56        ClassLoader current = Unsafe.class.getClassLoader();
57
58        if ((calling != null) && (calling != Unsafe.class.getClassLoader())) {
59            throw new SecurityException("Unsafe access denied");
60        }
61
62        return THE_ONE;
63    }
64
65    /**
66     * Gets the raw byte offset from the start of an object's memory to
67     * the memory used to store the indicated instance field.
68     *
69     * @param field non-null; the field in question, which must be an
70     * instance field
71     * @return the offset to the field
72     */
73    public long objectFieldOffset(Field field) {
74        if (Modifier.isStatic(field.getModifiers())) {
75            throw new IllegalArgumentException(
76                    "valid for instance fields only");
77        }
78
79        return objectFieldOffset0(field);
80    }
81
82    /**
83     * Helper for {@link #objectFieldOffset}, which does all the work,
84     * assuming the parameter is deemed valid.
85     *
86     * @param field non-null; the instance field
87     * @return the offset to the field
88     */
89    private static native long objectFieldOffset0(Field field);
90
91    /**
92     * Gets the offset from the start of an array object's memory to
93     * the memory used to store its initial (zeroeth) element.
94     *
95     * @param clazz non-null; class in question; must be an array class
96     * @return the offset to the initial element
97     */
98    public int arrayBaseOffset(Class clazz) {
99        if (! clazz.isArray()) {
100            throw new IllegalArgumentException(
101                    "valid for array classes only");
102        }
103
104        return arrayBaseOffset0(clazz);
105    }
106
107    /**
108     * Helper for {@link #arrayBaseOffset}, which does all the work,
109     * assuming the parameter is deemed valid.
110     *
111     * @param field non-null; the instance field
112     * @return the offset to the field
113     */
114    private static native int arrayBaseOffset0(Class clazz);
115
116    /**
117     * Gets the size of each element of the given array class.
118     *
119     * @param clazz non-null; class in question; must be an array class
120     * @return > 0; the size of each element of the array
121     */
122    public int arrayIndexScale(Class clazz) {
123        if (! clazz.isArray()) {
124            throw new IllegalArgumentException(
125                    "valid for array classes only");
126        }
127
128        return arrayIndexScale0(clazz);
129    }
130
131    /**
132     * Helper for {@link #arrayIndexScale}, which does all the work,
133     * assuming the parameter is deemed valid.
134     *
135     * @param field non-null; the instance field
136     * @return the offset to the field
137     */
138    private static native int arrayIndexScale0(Class clazz);
139
140    /**
141     * Performs a compare-and-set operation on an <code>int</code>
142     * field within the given object.
143     *
144     * @param obj non-null; object containing the field
145     * @param offset offset to the field within <code>obj</code>
146     * @param expectedValue expected value of the field
147     * @param newValue new value to store in the field if the contents are
148     * as expected
149     * @return <code>true</code> if the new value was in fact stored, and
150     * <code>false</code> if not
151     */
152    public native boolean compareAndSwapInt(Object obj, long offset,
153            int expectedValue, int newValue);
154
155    /**
156     * Performs a compare-and-set operation on a <code>long</code>
157     * field within the given object.
158     *
159     * @param obj non-null; object containing the field
160     * @param offset offset to the field within <code>obj</code>
161     * @param expectedValue expected value of the field
162     * @param newValue new value to store in the field if the contents are
163     * as expected
164     * @return <code>true</code> if the new value was in fact stored, and
165     * <code>false</code> if not
166     */
167    public native boolean compareAndSwapLong(Object obj, long offset,
168            long expectedValue, long newValue);
169
170    /**
171     * Performs a compare-and-set operation on an <code>Object</code>
172     * field (that is, a reference field) within the given object.
173     *
174     * @param obj non-null; object containing the field
175     * @param offset offset to the field within <code>obj</code>
176     * @param expectedValue expected value of the field
177     * @param newValue new value to store in the field if the contents are
178     * as expected
179     * @return <code>true</code> if the new value was in fact stored, and
180     * <code>false</code> if not
181     */
182    public native boolean compareAndSwapObject(Object obj, long offset,
183            Object expectedValue, Object newValue);
184
185    /**
186     * Gets an <code>int</code> field from the given object,
187     * using <code>volatile</code> semantics.
188     *
189     * @param obj non-null; object containing the field
190     * @param offset offset to the field within <code>obj</code>
191     * @return the retrieved value
192     */
193    public native int getIntVolatile(Object obj, long offset);
194
195    /**
196     * Stores an <code>int</code> field into the given object,
197     * using <code>volatile</code> semantics.
198     *
199     * @param obj non-null; object containing the field
200     * @param offset offset to the field within <code>obj</code>
201     * @param newValue the value to store
202     */
203    public native void putIntVolatile(Object obj, long offset, int newValue);
204
205    /**
206     * Gets a <code>long</code> field from the given object,
207     * using <code>volatile</code> semantics.
208     *
209     * @param obj non-null; object containing the field
210     * @param offset offset to the field within <code>obj</code>
211     * @return the retrieved value
212     */
213    public native long getLongVolatile(Object obj, long offset);
214
215    /**
216     * Stores a <code>long</code> field into the given object,
217     * using <code>volatile</code> semantics.
218     *
219     * @param obj non-null; object containing the field
220     * @param offset offset to the field within <code>obj</code>
221     * @param newValue the value to store
222     */
223    public native void putLongVolatile(Object obj, long offset, long newValue);
224
225    /**
226     * Gets an <code>Object</code> field from the given object,
227     * using <code>volatile</code> semantics.
228     *
229     * @param obj non-null; object containing the field
230     * @param offset offset to the field within <code>obj</code>
231     * @return the retrieved value
232     */
233    public native Object getObjectVolatile(Object obj, long offset);
234
235    /**
236     * Stores an <code>Object</code> field into the given object,
237     * using <code>volatile</code> semantics.
238     *
239     * @param obj non-null; object containing the field
240     * @param offset offset to the field within <code>obj</code>
241     * @param newValue the value to store
242     */
243    public native void putObjectVolatile(Object obj, long offset,
244            Object newValue);
245
246    /**
247     * Gets an <code>int</code> field from the given object.
248     *
249     * @param obj non-null; object containing the field
250     * @param offset offset to the field within <code>obj</code>
251     * @return the retrieved value
252     */
253    public native int getInt(Object obj, long offset);
254
255    /**
256     * Stores an <code>int</code> field into the given object.
257     *
258     * @param obj non-null; object containing the field
259     * @param offset offset to the field within <code>obj</code>
260     * @param newValue the value to store
261     */
262    public native void putInt(Object obj, long offset, int newValue);
263
264    /**
265     * Gets a <code>long</code> field from the given object.
266     *
267     * @param obj non-null; object containing the field
268     * @param offset offset to the field within <code>obj</code>
269     * @return the retrieved value
270     */
271    public native long getLong(Object obj, long offset);
272
273    /**
274     * Stores a <code>long</code> field into the given object.
275     *
276     * @param obj non-null; object containing the field
277     * @param offset offset to the field within <code>obj</code>
278     * @param newValue the value to store
279     */
280    public native void putLong(Object obj, long offset, long newValue);
281
282    /**
283     * Gets an <code>Object</code> field from the given object.
284     *
285     * @param obj non-null; object containing the field
286     * @param offset offset to the field within <code>obj</code>
287     * @return the retrieved value
288     */
289    public native Object getObject(Object obj, long offset);
290
291    /**
292     * Stores an <code>Object</code> field into the given object.
293     *
294     * @param obj non-null; object containing the field
295     * @param offset offset to the field within <code>obj</code>
296     * @param newValue the value to store
297     */
298    public native void putObject(Object obj, long offset, Object newValue);
299
300    /**
301     * Parks the calling thread for the specified amount of time,
302     * unless the "permit" for the thread is already available (due to
303     * a previous call to {@link #unpark}. This method may also return
304     * spuriously (that is, without the thread being told to unpark
305     * and without the indicated amount of time elapsing).
306     *
307     * <p>See {@link java.util.concurrent.locks.LockSupport} for more
308     * in-depth information of the behavior of this method.</p>
309     *
310     * @param absolute whether the given time value is absolute
311     * milliseconds-since-the-epoch (<code>true</code>) or relative
312     * nanoseconds-from-now (<code>false</code>)
313     * @param time the (absolute millis or relative nanos) time value
314     */
315    public void park(boolean absolute, long time) {
316        if (absolute) {
317            lang.parkUntil(time);
318        } else {
319            lang.parkFor(time);
320        }
321    }
322
323    /**
324     * Unparks the given object, which must be a {@link Thread}.
325     *
326     * <p>See {@link java.util.concurrent.locks.LockSupport} for more
327     * in-depth information of the behavior of this method.</p>
328     *
329     * @param obj non-null; the object to unpark
330     */
331    public void unpark(Object obj) {
332        if (obj instanceof Thread) {
333            lang.unpark((Thread) obj);
334        } else {
335            throw new IllegalArgumentException("valid for Threads only");
336        }
337    }
338
339    // TODO(danfuzz): Stuff goes here.
340}
341