Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 2013 Christopher Pheby
*
* 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.
*/
package org.jadira.reflection.access.unsafe;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Deque;
import java.util.IdentityHashMap;
import org.jadira.reflection.access.api.ClassAccess;
import org.jadira.reflection.access.api.FieldAccess;
import org.jadira.reflection.core.misc.ClassUtils;
/**
* A set of utility methods for working with sun.misc.Unsafe. Address shallow and deep copying,
* field access and field manipulation.
*/
@SuppressWarnings("restriction")
public final class UnsafeOperations {
private static final int REFERENCE_STACK_LIMIT = 150;
private static final int SIZE_BYTES_BOOLEAN = 1;
private static final int SIZE_BYTES_BYTE = 1;
private static final int SIZE_BYTES_CHAR = 2;
private static final int SIZE_BYTES_SHORT = 2;
private static final int SIZE_BYTES_INT = 4;
private static final int SIZE_BYTES_LONG = 8;
private static final int SIZE_BYTES_FLOAT = 4;
private static final int SIZE_BYTES_DOUBLE = 8;
/**
* The size of a page that an object will be placed in (always 8 bytes currently) (NB for
* HotSpot can be retrieved using ObjectAlignmentInBytes in HotSpotDiagnosticMXBean, but
* as this is always 8 for existing JVMs this is hardcoded).
*/
private static final int SIZE_BYTES_PAGE_FOR_OBJECT_ALIGNMENT = 8;
private static final int MIN_SIZE = 16;
private static final sun.misc.Unsafe THE_UNSAFE;
private static final boolean IS_UNSAFE_AVAILABLE;
private static final UnsafeOperations INSTANCE = new UnsafeOperations();
static {
boolean isUnsafeAvailable = true;
sun.misc.Unsafe theUnsafe = null;
try {
Class.forName("android.os.Process");
isUnsafeAvailable = false;
} catch (ClassNotFoundException e) {
// Ignored
} finally {
if (isUnsafeAvailable) {
try {
Field f = Class.forName("sun.misc.Unsafe").getDeclaredField("theUnsafe");
f.setAccessible(true);
theUnsafe = (sun.misc.Unsafe) f.get(null);
} catch (ClassNotFoundException e) {
isUnsafeAvailable = false;
} catch (IllegalArgumentException e) {
isUnsafeAvailable = false;
} catch (IllegalAccessException e) {
isUnsafeAvailable = false;
} catch (NoSuchFieldException e) {
isUnsafeAvailable = false;
} catch (SecurityException e) {
isUnsafeAvailable = false;
}
}
}
IS_UNSAFE_AVAILABLE = isUnsafeAvailable;
THE_UNSAFE = theUnsafe;
}
private UnsafeOperations() {
}
/**
* Returns the (singleton) UnsafeOperations instance
* @return UnsafeOperations
*/
public static final UnsafeOperations getUnsafeOperations() {
if (isUnsafeAvailable()) {
return INSTANCE;
} else {
throw new IllegalStateException("Unsafe is not available");
}
}
/**
* Check whether the Unsafe API is accessible
* @return True if available
*/
public static boolean isUnsafeAvailable() {
return IS_UNSAFE_AVAILABLE;
}
/**
* Construct and allocate on the heap an instant of the given class, without calling the class constructor
* @param clazz Class to create instant for
* @param Type of the instance to be constructed
* @return The new instance
* @throws IllegalStateException Indicates a problem occurred
*/
public final T allocateInstance(Class clazz) throws IllegalStateException {
try {
@SuppressWarnings("unchecked")
final T result = (T) THE_UNSAFE.allocateInstance(clazz);
return result;
} catch (InstantiationException e) {
throw new IllegalStateException("Cannot allocate instance: " + e.getMessage(), e);
}
}
/**
* Gets an offset for the given field relative to the field base. Any particular field will always have the
* same offset, and no two distinct fields of the same class will ever have the same offset.
* @param f The Field to determine the offset for
* @return The offset represented as a long
*/
public final long getObjectFieldOffset(Field f) {
return THE_UNSAFE.objectFieldOffset(f);
}
/**
* Performs a shallow copy of the given object - a new instance is allocated with the same contents. Any object
* references inside the copy will be the same as the original object.
* @param obj Object to copy
* @param The type being copied
* @return A new instance, identical to the original
*/
public final T shallowCopy(T obj) {
long size = shallowSizeOf(obj);
long address = THE_UNSAFE.allocateMemory(size);
long start = toAddress(obj);
THE_UNSAFE.copyMemory(start, address, size);
@SuppressWarnings("unchecked")
final T result = (T) fromAddress(address);
return result;
}
/**
* Convert the object reference to a memory address represented as a signed long
* @param obj The object
* @return A long representing the address of the object
*/
public final long toAddress(Object obj) {
Object[] array = new Object[] { obj };
long baseOffset = THE_UNSAFE.arrayBaseOffset(Object[].class);
return normalize(THE_UNSAFE.getInt(array, baseOffset));
}
/**
* Returns the object located at the given memory address
* @param address The address (a signed long) for the object
* @return The Object at the given address
*/
public final Object fromAddress(long address) {
Object[] array = new Object[] { null };
long baseOffset = THE_UNSAFE.arrayBaseOffset(Object[].class);
THE_UNSAFE.putLong(array, baseOffset, address);
return array[0];
}
/**
* Copy the value from the given field from the source into the target.
* The field specified must contain a primitive
* @param source The object to copy from
* @param copy The target object
* @param field Field to be copied
*/
public final void copyPrimitiveField(Object source, Object copy, Field field) {
copyPrimitiveAtOffset(source, copy, field.getType(), getObjectFieldOffset(field));
}
/**
* Copies the primitive of the specified type from the given field offset in the source object
* to the same location in the copy
* @param source The object to copy from
* @param copy The target object
* @param type The type of primitive at the given offset - e.g. java.lang.Boolean.TYPE
* @param offset The offset to copy from
*/
public final void copyPrimitiveAtOffset(Object source, Object copy, Class> type, long offset) {
if (java.lang.Boolean.TYPE == type) {
boolean origFieldValue = THE_UNSAFE.getBoolean(source, offset);
THE_UNSAFE.putBoolean(copy, offset, origFieldValue);
} else if (java.lang.Byte.TYPE == type) {
byte origFieldValue = THE_UNSAFE.getByte(source, offset);
THE_UNSAFE.putByte(copy, offset, origFieldValue);
} else if (java.lang.Character.TYPE == type) {
char origFieldValue = THE_UNSAFE.getChar(source, offset);
THE_UNSAFE.putChar(copy, offset, origFieldValue);
} else if (java.lang.Short.TYPE == type) {
short origFieldValue = THE_UNSAFE.getShort(source, offset);
THE_UNSAFE.putShort(copy, offset, origFieldValue);
} else if (java.lang.Integer.TYPE == type) {
int origFieldValue = THE_UNSAFE.getInt(source, offset);
THE_UNSAFE.putInt(copy, offset, origFieldValue);
} else if (java.lang.Long.TYPE == type) {
long origFieldValue = THE_UNSAFE.getLong(source, offset);
THE_UNSAFE.putLong(copy, offset, origFieldValue);
} else if (java.lang.Float.TYPE == type) {
float origFieldValue = THE_UNSAFE.getFloat(source, offset);
THE_UNSAFE.putFloat(copy, offset, origFieldValue);
} else if (java.lang.Double.TYPE == type) {
double origFieldValue = THE_UNSAFE.getDouble(source, offset);
THE_UNSAFE.putDouble(copy, offset, origFieldValue);
}
}
/**
* Restores the primitive at the given field to its default value. Default value is defined as the
* value that the field would hold if it was a new, uninitialised value (e.g. false for a boolean).
* @param copy The target object
* @param type The type of primitive at the given offset - e.g. java.lang.Boolean.TYPE
* @param offset The offset to reset to its default value
*/
public final void putPrimitiveDefaultAtOffset(Object copy, Class> type, long offset) {
if (java.lang.Boolean.TYPE == type) {
THE_UNSAFE.putBoolean(copy, offset, false);
} else if (java.lang.Byte.TYPE == type) {
THE_UNSAFE.putByte(copy, offset, (byte) 0);
} else if (java.lang.Character.TYPE == type) {
THE_UNSAFE.putChar(copy, offset, '\u0000');
} else if (java.lang.Short.TYPE == type) {
THE_UNSAFE.putShort(copy, offset, (short) 0);
} else if (java.lang.Integer.TYPE == type) {
THE_UNSAFE.putInt(copy, offset, 0);
} else if (java.lang.Long.TYPE == type) {
THE_UNSAFE.putLong(copy, offset, 0L);
} else if (java.lang.Float.TYPE == type) {
THE_UNSAFE.putFloat(copy, offset, 0.0f);
} else if (java.lang.Double.TYPE == type) {
THE_UNSAFE.putDouble(copy, offset, 0.0d);
}
}
/**
* Performs a deep copy of the object. With a deep copy all references from the object are also copied.
* The identity of referenced objects is preserved, so, for example, if the object graph contains two
* references to the same object, the cloned object will preserve this structure.
* @param obj The object to perform a deep copy for.
* @param The type being copied
* @return A deep copy of the original object.
*/
public T deepCopy(final T obj) {
return deepCopy(obj, new IdentityHashMap