blob: 0035b3a9c6d219ec8b627609daa7d02d41b33ec1 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
package sun.misc;
import java.lang.reflect.Field;
import java.security.AccessController;
import java.security.PrivilegedAction;
import org.apache.harmony.kernel.vm.Objects;
import org.apache.harmony.kernel.vm.Threads;
import org.apache.harmony.kernel.vm.VM;
/**
* <p>The Unsafe service.</p>
*
*/
public class Unsafe {
private static final Unsafe INSTANCE = new Unsafe();
/**
* <p>
* Retrieves an instance of this service.
* </p>
*
* @return An instance of Unsafe.
*/
public static Unsafe getUnsafe() {
/* Check that the caller of this method is in system code (i.e. on the
* bootclasspath). Unsafe methods are not designed to be called directly
* by applications. We assume that system code will not reveal the instance.
*/
if (VM.callerClassLoader() != null) {
throw new SecurityException("Unsafe");
}
return AccessController.doPrivileged(new PrivilegedAction<Unsafe>() {
public Unsafe run() {
return INSTANCE;
}
});
}
private Objects objects;
private Threads threads;
private Unsafe() {
super();
this.objects = Objects.getInstance();
this.threads = Threads.getInstance();
}
/**
* <p>
* Retrieves the offset value of the {@link Field} for use by other methods
* in this class.
* </p>
*
* @param field The {@link Field} to retrieve the offset for.
* @return The offset value.
*/
public long objectFieldOffset(Field field) {
return objects.getFieldOffset(field);
}
/**
* <p>
* Compares and swaps the value of an int-typed field on an Object instance.
* </p>
*
* @param object The instance containing the field.
* @param fieldOffset The offset value of the field.
* @param expected The expected value of the field.
* @param update The new value to write to the field.
* @return <code>true</code> if the field was updated, <code>false</code>
* otherwise.
*/
public boolean compareAndSwapInt(Object object, long fieldOffset, int expected, int update) {
return objects.compareAndSwapInt(object, fieldOffset, expected, update);
}
/**
* <p>
* Compares and swaps the value of a long-typed field on an Object instance.
* </p>
*
* @param object The instance containing the field.
* @param fieldOffset The offset value of the field.
* @param expected The expected value of the field.
* @param update The new value to write to the field.
* @return <code>true</code> if the field was updated, <code>false</code>
* otherwise.
*/
public boolean compareAndSwapLong(Object object, long fieldOffset, long expected,
long update) {
return objects.compareAndSwapLong(object, fieldOffset, expected, update);
}
/**
* <p>
* Compares and swaps the value of an Object-typed field on an Object
* instance.
* </p>
*
* @param object The instance containing the field.
* @param fieldOffset The offset value of the field.
* @param expected The expected value of the field.
* @param update The new value to write to the field.
* @return <code>true</code> if the field was updated, <code>false</code>
* otherwise.
*/
public boolean compareAndSwapObject(Object object, long fieldOffset, Object expected,
Object update) {
return objects.compareAndSwapObject(object, fieldOffset, expected, update);
}
/**
* <p>
* Retrieves the base offset for the array Class given. The Class passed
* MUST me any array type, such that the method {@link Class#isArray()}
* returns <code>true</code>. For example, <code>int[].class</code>.
* </p>
*
* @param clazz The array Class object.
* @return The base offset value.
*/
public int arrayBaseOffset(Class<?> clazz) {
return objects.getArrayBaseOffset(clazz);
}
/**
* <p>
* Retrieves the array index scale for the array Class given. The index
* scale is the value used to determine the offset of a particular element
* in the array given the array's base offset and an index. The following
* code snippet illustrates the usage.
* </p>
*
* <pre>
* int base = unsafe.arrayBaseOffset(int[].class);
*
* int scale = unsafe.arrayIndexScale(int[].class);
*
* int elementIdx = 1;
*
* int[] array = { 0, 1, 2 };
*
* long offsetForIdx = base + (elementIdx * scale);
* </pre>
*
* <p>
* The Class passed MUST me any array type, such that the method
* {@link Class#isArray()} returns <code>true</code>. For example,
* <code>int[].class</code>.
* </p>
*
* @param clazz The array Class object.
* @return The index scale value.
*/
public int arrayIndexScale(Class<?> clazz) {
return objects.getArrayIndexScale(clazz);
}
/**
* Writes an int value to an Object's field using ordered
* setting. Ordered setting of a field is equivalent to the
* volatile setting of that field except that it does not ensure
* that the change is immediately available to other threads.
*
* @param object The instance containing the field to write to.
* @param fieldOffset The offset of the int field in the object.
* @param newValue The value to write.
*/
public void putOrderedInt(Object object, long fieldOffset,
int newValue) {
// should probably implement less strict implementation
putIntVolatile(object, fieldOffset, newValue);
}
/**
* <p>
* Writes an int value to an Object's field as though it were declared
* <code>volatile</code>.
* </p>
*
* @param object The instance containing the field to write to.
* @param fieldOffset The offset of the field to write to.
* @param newValue The value to write.
*/
public void putIntVolatile(Object object, long fieldOffset, int newValue) {
objects.putIntVolatile(object, fieldOffset, newValue);
}
/**
* <p>
* Reads an int value from an Object's field as though it were declared
* <code>volatile</code>.
* </p>
*
* @param object The instance containing the field to read from.
* @param fieldOffset The offset of the field to read from.
* @return The value that was read.
*/
public int getIntVolatile(Object object, long fieldOffset) {
return objects.getIntVolatile(object, fieldOffset);
}
/**
* Writes a long value to an Object's field using ordered
* setting. Ordered setting of a field is equivalent to the
* volatile setting of that field except that it does not ensure
* that the change is immediately available to other threads.
*
* @param object The instance containing the field to write to.
* @param fieldOffset The offset of the field to write to.
* @param newValue The value to write.
*/
public void putOrderedLong(Object object, long fieldOffset,
long newValue) {
// should probably implement less strict implementation
putLongVolatile(object, fieldOffset, newValue);
}
/**
* <p>
* Writes a long value to an Object's field as though it were declared
* <code>volatile</code>.
* </p>
*
* @param object The instance containing the field to write to.
* @param fieldOffset The offset of the field to write to.
* @param newValue The value to write.
*/
public void putLongVolatile(Object object, long fieldOffset, long newValue) {
objects.putLongVolatile(object, fieldOffset, newValue);
}
/**
* <p>
* Reads a long value from an Object's field as though it were declared
* <code>volatile</code>.
* </p>
*
* @param object The instance containing the field to read from.
* @param fieldOffset The offset of the field to read from.
* @return The value that was read.
*/
public long getLongVolatile(Object object, long fieldOffset) {
return objects.getLongVolatile(object, fieldOffset);
}
/**
* <p>
* Writes an Object reference value to an Object's field.
* </p>
*
* @param object The instance containing the field to write to.
* @param fieldOffset The offset of the field to write to.
* @param newValue The value to write.
*/
public void putObject(Object object, long fieldOffset,
Object newValue) {
// should probably implement less strict implementation
putOrderedObject(object, fieldOffset, newValue);
}
/**
* Writes an Object reference value to an Object's field using
* ordered setting. Ordered setting of a field is equivalent to
* the volatile setting of that field except that it does not
* ensure that the change is immediately available to other
* threads.
*
* @param object The instance containing the field to write to.
* @param fieldOffset The offset of the field to write to.
* @param newValue The value to write.
*/
public void putOrderedObject(Object object, long fieldOffset,
Object newValue) {
// should probably implement less strict implementation
putObjectVolatile(object, fieldOffset, newValue);
}
/**
* <p>
* Writes an Object reference value to an Object's field as though it were
* declared <code>volatile</code>.
* </p>
*
* @param object The instance containing the field to write to.
* @param fieldOffset The offset of the field to write to.
* @param newValue The value to write.
*/
public void putObjectVolatile(Object object, long fieldOffset, Object newValue) {
objects.putObjectVolatile(object, fieldOffset, newValue);
}
/**
* <p>
* Writes an int value to an Object's field as though it were declared
* <code>volatile</code>.
* </p>
*
* @param object The instance containing the field to write to.
* @param fieldOffset The offset of the field to write to.
* @param newValue The value to write.
*/
public Object getObjectVolatile(Object object, long fieldOffset) {
return objects.getObjectVolatile(object, fieldOffset);
}
/**
* <p>
* Writes a long value to an Object's field.
* </p>
*
* @param object The instance containing the field to write to.
* @param fieldOffset The offset of the field to write to.
* @param newValue The value to write.
*/
public void putLong(Object object, long fieldOffset, long newValue) {
objects.putLong(object, fieldOffset, newValue);
}
/**
* <p>
* Reads a long value from an Object's field.
* </p>
*
* @param object The instance containing the field to read from.
* @param fieldOffset The offset of the field to read from.
* @return The value that was read.
*/
public long getLong(Object object, long fieldOffset) {
return objects.getLong(object, fieldOffset);
}
/**
* <p>
* Unparks the {@link Thread} that's passed.
* </p>
*
* @param thread The {@link Thread} to unpark.
*/
public void unpark(Thread thread) {
threads.unpark(thread);
}
/**
* <p>
* Parks the {@link Thread#currentThread() current thread} either for a set
* number of nanoseconds or until a future point in time.
* </p>
*
* @param timestamp If <code>true</code> <code>nanosOrTimestamp</code>
* should be consider as a timestamp based on
* {@link System#currentTimeMillis()}. If <code>false</code>,
* then <code>nanosOrTimestamp</code> should be considered as a
* relative number of nanoseconds from when this method was called;
* the value <code>0L</code> can be used in conjunction with this
* to indicate that time is not a factor when parking the thread.
* @param nanosOrTimestamp Either a relative number of nanoseconds or a
* timestamp in milliseconds as defined by
* {@link System#currentTimeMillis()}.
*/
public void park(boolean timestamp, long nanosOrTimestamp) {
if (timestamp) {
threads.parkFor(nanosOrTimestamp);
} else {
threads.parkUntil(nanosOrTimestamp);
}
}
}