/* * Written by Gil Tene and Martin Thompson, and released to the public domain, * as explained at http://creativecommons.org/publicdomain/zero/1.0/ */ package org.ObjectLayout; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; /** * This class contains the intrinsifiable portions of StructuredArray behavior. JDK implementations * that choose to intrinsify StructuredArray are expected to replace the implementation of this * base class. * * @param <T> the element type in the array */ abstract class AbstractStructuredArrayBase<T> { // // // Constructor: // // /** * Optimization NOTE: Optimized JDK implementations may choose to replace the logic of this * constructor, along with the way some of the internal fields are represented (see note * in "Internal fields" section farther below. */ AbstractStructuredArrayBase() { checkConstructorMagic(); ConstructorMagic constructorMagic = getConstructorMagic(); @SuppressWarnings("unchecked") final AbstractStructuredArrayModel<AbstractStructuredArrayBase<T>, T> arrayModel = constructorMagic.getArrayModel(); final Class<T> elementClass = arrayModel._getElementClass(); final long length = arrayModel._getLength(); // Finish consuming constructMagic arguments: constructorMagic.setActive(false); if (length < 0) { throw new IllegalArgumentException("length cannot be negative"); } this.length = length; this.elementClass = elementClass; allocateInternalStorage(length); } /** * Instantiate a StructuredArray of arrayClass with the given array model, and the supplied * array constructor and arguments. * * OPTIMIZATION NOTE: Optimized JDK implementations may replace this implementation with one that * allocates room for the entire StructuredArray and all it's elements. */ static <S extends AbstractStructuredArrayBase<T>, T> S instantiateStructuredArray( AbstractStructuredArrayModel<S, T> arrayModel, Constructor<S> arrayConstructor, Object... args) { // For implementations that need the array class and the element class, // this is how // how to get them: // // Class<? extends StructuredArray<T>> arrayClass = // arrayConstructor.getDeclaringClass(); // Class<T> elementClass = arrayModel.getElementClass(); ConstructorMagic constructorMagic = getConstructorMagic(); constructorMagic.setConstructionArgs(arrayModel); try { constructorMagic.setActive(true); return arrayConstructor.newInstance(args); } catch (InstantiationException ex) { throw new RuntimeException(ex); } catch (IllegalAccessException ex) { throw new RuntimeException(ex); } catch (InvocationTargetException ex) { throw new RuntimeException(ex); } finally { constructorMagic.setActive(false); } } /** * Construct a fresh element intended to occupy a given index in the given array, using the * supplied constructor and arguments. * * OPTIMIZATION NOTE: Optimized JDK implementations may replace this implementation with a * construction-in-place call on a previously allocated memory location associated with the given index. */ void constructElementAtIndex( final long index, final Constructor<T> constructor, final Object... args) { try { T element = constructor.newInstance(args); storeElementInLocalStorageAtIndex(element, index); } catch (InstantiationException ex) { throw new RuntimeException(ex); } catch (IllegalAccessException ex) { throw new RuntimeException(ex); } catch (InvocationTargetException ex) { throw new RuntimeException(ex); } } /** * Construct a fresh primitive sub-array intended to occupy a given index in the given array, using the * supplied constructor and arguments. * * OPTIMIZATION NOTE: Optimized JDK implementations may replace this implementation with a * construction-in-place call on a previously allocated memory location associated with the given index. */ void constructPrimitiveSubArrayAtIndex( final long index, AbstractPrimitiveArrayModel primitiveSubArrayModel, final Constructor<T> constructor, final Object... args) { int length = (int) primitiveSubArrayModel._getLength(); @SuppressWarnings("unchecked") Constructor<? extends AbstractPrimitiveArray> c = (Constructor<? extends AbstractPrimitiveArray>) constructor; @SuppressWarnings("unchecked") T element = (T) AbstractPrimitiveArray._newInstance(length, c, args); storeElementInLocalStorageAtIndex(element, index); } /** * Construct a fresh sub-array intended to occupy a given index in the given array, using the * supplied constructor. * * OPTIMIZATION NOTE: Optimized JDK implementations may replace this implementation with a * construction-in-place call on a previously allocated memory location associated with the given index. */ void constructSubArrayAtIndex( long index, AbstractStructuredArrayModel subArrayModel, final Constructor<T> subArrayConstructor, final Object... args) { ConstructorMagic constructorMagic = getConstructorMagic(); constructorMagic.setConstructionArgs(subArrayModel); try { constructorMagic.setActive(true); T subArray = subArrayConstructor.newInstance(args); storeElementInLocalStorageAtIndex(subArray, index); } catch (InstantiationException ex) { throw new RuntimeException(ex); } catch (IllegalAccessException ex) { throw new RuntimeException(ex); } catch (InvocationTargetException ex) { throw new RuntimeException(ex); } finally { constructorMagic.setActive(false); } } /** * Construct a fresh StructuredArray intended to occupy a a given intrinsic field in the containing object, * at the field described by the supplied intrinsicObjectModel, using the supplied constructor and arguments. * * OPTIMIZATION NOTE: Optimized JDK implementations may replace this implementation with a * construction-in-place call on a previously allocated memory location associated with the given index. */ static <T> T constructStructuredArrayWithin( final Object containingObject, final AbstractIntrinsicObjectModel<T> intrinsicObjectModel, AbstractStructuredArrayModel subArrayModel, final Constructor<T> subArrayConstructor, final Object... args) { ConstructorMagic constructorMagic = getConstructorMagic(); constructorMagic.setConstructionArgs(subArrayModel); try { constructorMagic.setActive(true); T array = subArrayConstructor.newInstance(args); intrinsicObjectModel.directlyInitializeTargetField(containingObject, array); return array; } catch (InstantiationException ex) { throw new RuntimeException(ex); } catch (IllegalAccessException ex) { throw new RuntimeException(ex); } catch (InvocationTargetException ex) { throw new RuntimeException(ex); } finally { constructorMagic.setActive(false); } } /** * Get an element at a supplied [index] in a StructuredArray * * OPTIMIZATION NOTE: Optimized JDK implementations may replace this implementation with a * faster access form (e.g. they may be able to derive the element reference directly from the * structuredArray reference without requiring a de-reference). * * @param index of the element to retrieve. * @return a reference to the indexed element. * */ T get(final int index) { return intAddressableElements[index]; } /** * Get an element at a supplied [index] in a StructuredArray * * OPTIMIZATION NOTE: Optimized JDK implementations may replace this implementation with a * faster access form (e.g. they may be able to derive the element reference directly from the * structuredArray reference without requiring a de-reference). * * @param index of the element to retrieve. * @return a reference to the indexed element. */ T get(final long index) { if (index < Integer.MAX_VALUE) { return get((int) index); } // Calculate index into long-addressable-only partitions: final long longIndex = (index - Integer.MAX_VALUE); final int partitionIndex = (int)(longIndex >>> MAX_EXTRA_PARTITION_SIZE_POW2_EXPONENT); final int partitionOffset = (int)longIndex & PARTITION_MASK; return longAddressableElements[partitionIndex][partitionOffset]; } // // // Accessor methods for instance state: // // Class<T> getElementClass() { return elementClass; } long getLength() { return length; } // // // Internal fields: // // /** * OPTIMIZATION NOTE: Optimized JDK implementations may choose to hide these fields in non-Java-accessible * internal instance fields (much like array.length is hidden), in order to ensure that no uncontrolled * modification of the fields can be made by any Java program (not even via reflection getting at private * fields and bypassing their finality). This is an important security concern because optimization * may need to make strong assumptions about the true finality of some of these fields. */ private final Class<T> elementClass; private final long length; // // // Internal Storage support: // // /** * OPTIMIZATION NOTE: Optimized JDK implementations may choose to replace this vanilla-Java internal * storage representation with one that is more intrinsically understood by the JDK and JVM. */ static final int MAX_EXTRA_PARTITION_SIZE_POW2_EXPONENT = 30; static final int MAX_EXTRA_PARTITION_SIZE = 1 << MAX_EXTRA_PARTITION_SIZE_POW2_EXPONENT; static final int PARTITION_MASK = MAX_EXTRA_PARTITION_SIZE - 1; private T[][] longAddressableElements; // Used to store elements at indexes above Integer.MAX_VALUE private T[] intAddressableElements; @SuppressWarnings("unchecked") private void allocateInternalStorage(final long length) { // Allocate internal storage: // Size int-addressable sub arrays: final int intLength = (int) Math.min(length, Integer.MAX_VALUE); // Size Subsequent partitions hold long-addressable-only sub arrays: final long extraLength = length - intLength; final int numFullPartitions = (int) (extraLength >>> MAX_EXTRA_PARTITION_SIZE_POW2_EXPONENT); final int lastPartitionSize = (int) extraLength & PARTITION_MASK; intAddressableElements = (T[]) new Object[intLength]; longAddressableElements = (T[][]) new Object[numFullPartitions + 1][]; // full long-addressable-only partitions: for (int i = 0; i < numFullPartitions; i++) { longAddressableElements[i] = (T[]) new Object[MAX_EXTRA_PARTITION_SIZE]; } // Last partition with leftover long-addressable-only size: longAddressableElements[numFullPartitions] = (T[]) new Object[lastPartitionSize]; } private void storeElementInLocalStorageAtIndex(T element, long index0) { // place in proper internal storage location: if (index0 < Integer.MAX_VALUE) { intAddressableElements[(int) index0] = element; return; } // Calculate index into long-addressable-only partitions: final long longIndex0 = (index0 - Integer.MAX_VALUE); final int partitionIndex = (int) (longIndex0 >>> MAX_EXTRA_PARTITION_SIZE_POW2_EXPONENT); final int partitionOffset = (int) longIndex0 & PARTITION_MASK; longAddressableElements[partitionIndex][partitionOffset] = element; } // // // ConstructorMagic support: // // /** * OPTIMIZATION NOTE: The ConstructorMagic will likely not need to be modified in any way even for * optimized JDK implementations. It resides in this class for scoping reasons. */ private static class ConstructorMagic { private boolean isActive() { return active; } private void setActive(boolean active) { this.active = active; } private void setConstructionArgs(AbstractStructuredArrayModel arrayModel) { this.arrayModel = arrayModel; } private AbstractStructuredArrayModel getArrayModel() { return arrayModel; } private boolean active = false; AbstractStructuredArrayModel arrayModel; } private static final ThreadLocal<ConstructorMagic> threadLocalConstructorMagic = new ThreadLocal<ConstructorMagic>() { @Override protected ConstructorMagic initialValue() { return new ConstructorMagic(); } }; private static ConstructorMagic getConstructorMagic() { return threadLocalConstructorMagic.get(); } private static void checkConstructorMagic() { if (!getConstructorMagic().isActive()) { throw new IllegalArgumentException( "StructuredArray<> must not be directly instantiated with a constructor. Use newInstance(...) instead."); } } }