/*
Реализация среды исполнения языка программирования
Объектно-ориентированный продвинутый векторный транслятор
Copyright © 2021, 2024 Малик Разработчик
Это свободная программа: вы можете перераспространять ее и/или изменять
ее на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
в каком она была опубликована Фондом свободного программного обеспечения;
либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.
Эта программа распространяется в надежде, что она будет полезной,
но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
общественной лицензии GNU.
Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
вместе с этой программой. Если это не так, см.
<https://www.gnu.org/licenses/>.
*/
package avt.lang;
import avt.lang.array.*;
import platform.dependent.*;
public final class Class(RequiredReflectiveObject)
{
public static final int CLASS = 0x00;
public static final int SERVICE = 0x20;
public static final int STRUCT = 0x40;
public static final int INTERFACE = 0x60;
public static final int PRIMITIVE = 0x80;
public static final int TYPE_MASK = 0xe0;
public static final int VOID = 8;
public static final int BOOLEAN = 16;
public static final int CHAR = 20;
public static final int BYTE = 24;
public static final int BYTE2 = 25;
public static final int BYTE4 = 26;
public static final int BYTE8 = 27;
public static final int SHORT = 28;
public static final int SHORT2 = 29;
public static final int SHORT4 = 30;
public static final int SHORT8 = 31;
public static final int INT = 32;
public static final int INT2 = 33;
public static final int INT4 = 34;
public static final int INT8 = 35;
public static final int LONG = 36;
public static final int LONG2 = 37;
public static final int LONG4 = 38;
public static final int LONG8 = 39;
public static final int FLOAT = 40;
public static final int FLOAT2 = 41;
public static final int FLOAT4 = 42;
public static final int FLOAT8 = 43;
public static final int DOUBLE = 44;
public static final int DOUBLE2 = 45;
public static final int DOUBLE4 = 46;
public static final int DOUBLE8 = 47;
public static final int REAL = 48;
private static final int NOT_INITIALIZED = 0;
private static final int INITIALIZING = 1;
private static final int INITIALIZED = 3;
public static Class get(String canonicalName) throws ClassNotFoundException {
if(canonicalName == null || canonicalName.isEmpty())
{
throw new ClassNotFoundException(package.getResourceString("not-found.class.empty"));
}
int dotPosition = canonicalName.lastIndexOf('.');
Package parentPackage = Package.find(dotPosition < 0 ? null : canonicalName.substring(0, dotPosition));
label0: if(parentPackage != null)
{
String simpleName = canonicalName.substring(dotPosition + 1);
Class result = parentPackage.findDeclaredType(simpleName);
if(result != null) return result;
int bracketPosition = simpleName.indexOf("[]");
if(bracketPosition > 0 && (result = parentPackage.findDeclaredType(simpleName.substring(0, bracketPosition))) != null)
{
for(Class arrayType; (arrayType = parentPackage.findDeclaredType(simpleName.substring(0, bracketPosition += 2))) != null; result = arrayType)
{
if(!simpleName.startsWith("[]", bracketPosition)) break label0;
}
int nameLength = simpleName.length;
Mutex operation = Runtime.getInstance().systemOperation;
operation.lock();
try
{
for(Class arrayType; (arrayType = parentPackage.findAddedArrayType(result)) != null; bracketPosition += 2)
{
result = arrayType;
if(bracketPosition >= nameLength) return result;
if(!simpleName.startsWith("[]", bracketPosition)) break label0;
}
for(; ; bracketPosition += 2)
{
result = createArrayType(result, parentPackage);
if(bracketPosition >= nameLength) return result;
if(!simpleName.startsWith("[]", bracketPosition)) break label0;
}
} finally
{
operation.unlock();
}
}
}
throw new ClassNotFoundException(String.format(package.getResourceString("not-found.class.name"), new Object[] { canonicalName }));
}
private static native void fillArrayType(Class arrayType, Class superType, Class componentType, Package parentPackage);
private static Class createArrayType(Class componentType, Package parentPackage) {
String simpleName = componentType.simpleName;
String canonicalName = parentPackage.canonicalName;
canonicalName = String.format(canonicalName.isEmpty() ? "%1%[]" : "%0%.%1%[]", new Object[] { canonicalName, simpleName });
final Class superType = Object[].class;
final Class result = (Class) Runtime.getInstance().allocateInstance(
Class.class, Class.class.fldInstanceSize + (superType.fldVirtualsCount + superType.fldSuperServicesCount << 3 | superType.fldInstanceReferencedFieldsCount << 2), -1, false
);
fillArrayType(result, superType, componentType, parentPackage);
result.fldCanonicalName = canonicalName;
result.fldSimpleName = canonicalName.substring(canonicalName.length - simpleName.length - 2);
parentPackage.addArrayType(result);
return result;
}
private static native Measureable mapArray(Object array, long pointer);
private static native Struct mapStruct(Object struc, long pointer);
private final int fldInstanceSize;
private final int fldStructSize;
private final int fldInstanceReferencedFieldsCount;
private final int fldVirtualsCount;
private final int fldImplementorsCount;
private final int fldSuperServicesCount;
private final int fldStructReferencedFieldsCount;
private final int fldDeclaredFieldsCount;
private final int fldDeclaredMethodsCount;
private final int fldDeclaredPropertiesCount;
private final int fldInstanceReferencedFieldsOffset;
private final int fldVirtualsOffset;
private final int fldImplementorsOffset;
private final int fldSuperServicesOffset;
private final int fldStructReferencedFieldsOffset;
private final int fldDeclaredFieldsOffset;
private final int fldDeclaredMethodsOffset;
private final int fldDeclaredPropertiesOffset;
private final int fldDefaultConstructorAttributes;
private final int fldReserved74;
private final int fldReserved78;
private final int fldReserved7C;
private final long fldSuperTypeOffset;
private final long fldComponentTypeOffset;
private final long fldParentPackageOffset;
private final long fldDefaultConstructorOffset;
private final long fldReservedA0;
private final long fldReservedA8;
private final long fldSourceFileNameOffset;
private final int fldPrimitiveKind;
private final int fldRequiredReflectiveObjectSize;
private int fldReservedC0;
private int fldClinitStatus;
private Class[] fldSuperServices;
private Object fldClinitMonitor;
private Thread fldClinitThread;
private String fldSimpleName;
private String fldCanonicalName;
private String fldSourceFullFileName;
private String fldSourceSimpleFileName;
private () { }
public String toString() {
String type;
switch((fldAttributes & TYPE_MASK) >> 5)
{
case SERVICE >> 5:
type = "service ";
break;
case STRUCT >> 5:
type = "struct ";
break;
case INTERFACE >> 5:
type = "interface ";
break;
case PRIMITIVE >> 5:
type = "primitive ";
break;
default:
type = "class ";
}
return type + getCanonicalName();
}
public boolean isArray() { return fldComponentTypeOffset != 0L; }
public boolean isClass() { return (fldAttributes & TYPE_MASK) == CLASS; }
public boolean isStruct() { return (fldAttributes & TYPE_MASK) == STRUCT; }
public boolean isService() { return (fldAttributes & (SERVICE | PRIMITIVE)) == SERVICE; }
public boolean isInterface() { return (fldAttributes & TYPE_MASK) == INTERFACE; }
public boolean isPrimitive() { return (fldAttributes & TYPE_MASK) == PRIMITIVE; }
public boolean isScalar() { return (fldAttributes & TYPE_MASK) == PRIMITIVE && (fldPrimitiveKind & 3) == 0; }
public boolean isVector() { return (fldPrimitiveKind & 3) != 0; }
public boolean isAssignableFrom(Class type) {
if(type == null)
{
throw new NullPointerException(String.format(package.getResourceString("null-pointer.argument"), new Object[] { "type" }));
}
if(type == this)
{
return true;
}
int attributes = type.fldAttributes;
if((attributes & TYPE_MASK) == PRIMITIVE | ((attributes = fldAttributes) & TYPE_MASK) == PRIMITIVE)
{
/* type.isPrimitive() | this.isPrimitive() */
return false;
}
if(fldComponentTypeOffset == 0L)
{
/* !this.isArray() */
return (attributes & (SERVICE | PRIMITIVE)) == SERVICE ? type.isServiceImplements(this) : type.isInheritedFrom(this);
}
Class thisComponent = this.getComponentType();
Class typeComponent = type.getComponentType();
for(Class component = thisComponent.getComponentType(); component != null; component = component.getComponentType())
{
if(typeComponent == null)
{
return false;
}
thisComponent = component;
typeComponent = typeComponent.getComponentType();
}
return typeComponent != null && thisComponent.isAssignableFrom(typeComponent);
}
public boolean isInstance(Object instance) {
return instance != null && isAssignableFrom(instance.getClass());
}
public int getArrayDimensionsQuantity() {
int result = 0;
for(Class component = getComponentType(); component != null; component = component.getComponentType()) result++;
return result;
}
public Class getArrayCellType() {
Class result = null;
for(Class component = getComponentType(); component != null; component = component.getComponentType()) result = component;
return result;
}
public Object cast(Object instance) {
Class source;
if(instance != null && !isAssignableFrom(source = instance.getClass()))
{
throw new ClassCastException(package.getResourceString("class-cast")) { source = source, destination = this };
}
return instance;
}
public Object newInstance() throws InstantiationException, IllegalAccessException {
int attributes = fldAttributes;
int kind = attributes & TYPE_MASK;
if(fldComponentTypeOffset != 0L || kind == INTERFACE || kind == PRIMITIVE || (attributes & ABSTRACT) != 0)
{
throw new InstantiationException(package.getResourceString("instantiation.object")) { type = this };
}
if(fldDefaultConstructorOffset == 0L)
{
throw new InstantiationException(package.getResourceString("instantiation.constructor")) { type = this };
}
label0:
{
boolean isVisible = true;
switch(attributes & VISIBILITY_MASK)
{
case DEFAULT:
Class type = Thread.callerTypeTrace();
isVisible = parentPackage == type.parentPackage && sourceSimpleFileName.equals(type.sourceSimpleFileName);
break;
case PACKAGE:
Class type = Thread.callerTypeTrace();
isVisible = parentPackage == type.parentPackage;
break;
default:
break label0;
}
if(!isVisible)
{
throw new IllegalAccessException(String.format(package.getResourceString("illegal-access.type"), new Object[] { getCanonicalName() }));
}
}
attributes = fldDefaultConstructorAttributes;
label0:
{
boolean isVisible = true;
switch(attributes & VISIBILITY_MASK)
{
case PRIVATE:
Class type = Thread.callerTypeTrace();
Class parent = kind == SERVICE ? getSuperClass() : kind == STRUCT ? Struct.class : this;
isVisible = parent == type && type == this;
break;
case DEFAULT:
Class type = Thread.callerTypeTrace();
Class parent = kind == SERVICE ? getSuperClass() : kind == STRUCT ? Struct.class : this;
Object packag = type.parentPackage;
Object source = type.sourceSimpleFileName;
if(packag != parentPackage || !source.equals(sourceSimpleFileName))
{
isVisible = false;
break;
}
for(int length = fldSuperServicesCount, int index = -1, Class current = getSuperClass(); current != null; )
{
if(parent.isAssignableFrom(current) && current.isAssignableFrom(this) && (packag != current.parentPackage || !source.equals(current.sourceSimpleFileName)))
{
isVisible = false;
break;
}
if(index >= 0 || (current = current.getSuperClass()) == null) current = ++index >= length ? null : getSuperService(index);
}
break;
case PACKAGE:
Class type = Thread.callerTypeTrace();
Class parent = kind == SERVICE ? getSuperClass() : kind == STRUCT ? Struct.class : this;
Object packag = type.parentPackage;
if(packag != parentPackage)
{
isVisible = false;
break;
}
for(int length = fldSuperServicesCount, int index = -1, Class current = getSuperClass(); current != null; )
{
if(parent.isAssignableFrom(current) && current.isAssignableFrom(this) && (packag != current.parentPackage))
{
isVisible = false;
break;
}
if(index >= 0 || (current = current.getSuperClass()) == null) current = ++index >= length ? null : getSuperService(index);
}
break;
case PROTECTED:
Class type = Thread.callerTypeTrace();
Class parent = kind == SERVICE ? getSuperClass() : kind == STRUCT ? Struct.class : this;
isVisible = parent.isAssignableFrom(type) && type.isAssignableFrom(this) || parent.parentPackage == type.parentPackage;
break;
default:
break label0;
}
if(!isVisible)
{
throw new IllegalAccessException(String.format(package.getResourceString("illegal-access.constructor"), new Object[] { getCanonicalName() + "()" }));
}
}
Object result = allocateInstance();
result.defaultConstructor();
result.afterConstruction();
return result;
}
public Measureable newArray(int length) throws InstantiationException, IllegalAccessException {
if(fldComponentTypeOffset == 0L)
{
throw new InstantiationException(package.getResourceString("instantiation.array")) { type = this };
}
int attributes = fldAttributes;
label0:
{
boolean isVisible = true;
switch(attributes & VISIBILITY_MASK)
{
case DEFAULT:
Class type = Thread.callerTypeTrace();
isVisible = parentPackage == type.parentPackage && sourceSimpleFileName.equals(type.sourceSimpleFileName);
break;
case PACKAGE:
Class type = Thread.callerTypeTrace();
isVisible = parentPackage == type.parentPackage;
break;
default:
break label0;
}
if(!isVisible)
{
throw new IllegalAccessException(String.format(package.getResourceString("illegal-access.type"), new Object[] { getCanonicalName() }));
}
}
return allocateArray(length);
}
public Measureable newArray(int[] lengths) throws InstantiationException, IllegalAccessException {
int length;
long componentTypeOffset;
if(lengths == null)
{
throw new NullPointerException(String.format(package.getResourceString("null-pointer.argument"), new Object[] { "lengths" }));
}
if((length = lengths.length) < 1)
{
throw new IllegalArgumentException(String.format(package.getResourceString("illegal-argument.array-dimensions.empty"), new Object[] { "lengths" }));
}
if((componentTypeOffset = fldComponentTypeOffset) != 0L && length > getArrayDimensionsQuantity())
{
throw new IllegalArgumentException(String.format(package.getResourceString("illegal-argument.array-dimensions.too-long"), new Object[] { "lengths" }));
}
if(componentTypeOffset == 0L)
{
throw new InstantiationException(package.getResourceString("instantiation.array")) { type = this };
}
int attributes = fldAttributes;
label0:
{
boolean isVisible = true;
switch(attributes & VISIBILITY_MASK)
{
case DEFAULT:
Class type = Thread.callerTypeTrace();
isVisible = parentPackage == type.parentPackage && sourceSimpleFileName.equals(type.sourceSimpleFileName);
break;
case PACKAGE:
Class type = Thread.callerTypeTrace();
isVisible = parentPackage == type.parentPackage;
break;
default:
break label0;
}
if(!isVisible)
{
throw new IllegalAccessException(String.format(package.getResourceString("illegal-access.type"), new Object[] { getCanonicalName() }));
}
}
Array.copy(lengths, 0, lengths = new int[length], 0, length);
return allocateArray(lengths);
}
public Measureable newArrayAt(long pointer, int length) throws InstantiationException, IllegalAccessException {
Class componentType = getComponentType();
if(componentType == null)
{
throw new InstantiationException(package.getResourceString("instantiation.array")) { type = this };
}
if((componentType.fldAttributes & TYPE_MASK) != PRIMITIVE)
{
throw new InstantiationException(package.getResourceString("instantiation.primitive")) { type = this };
}
int attributes = fldAttributes;
label0:
{
boolean isVisible = true;
switch(attributes & VISIBILITY_MASK)
{
case DEFAULT:
Class type = Thread.callerTypeTrace();
isVisible = parentPackage == type.parentPackage && sourceSimpleFileName.equals(type.sourceSimpleFileName);
break;
case PACKAGE:
Class type = Thread.callerTypeTrace();
isVisible = parentPackage == type.parentPackage;
break;
default:
break label0;
}
if(!isVisible)
{
throw new IllegalAccessException(String.format(package.getResourceString("illegal-access.type"), new Object[] { getCanonicalName() }));
}
}
if(length < 0)
{
throw new NegativeArrayLengthException(package.getResourceString("negative-array-length"));
}
long limit = pointer + componentType.fldInstanceSize * (long) length;
Runtime runtime = Runtime.getInstance();
if(!runtime.isCanonicalPointer(pointer))
{
throw new SecurityException(String.format(package.getResourceString("security.pointer"), new Object[] { Long.toHexString(pointer) }));
}
if(!runtime.isCanonicalPointer(limit - 1))
{
throw new SecurityException(String.format(package.getResourceString("security.pointer"), new Object[] { Long.toHexString(limit - 1) }));
}
if(runtime.isProtectedMemory(new long2 { pointer, limit }))
{
throw new SecurityException(String.format(package.getResourceString("security.memory"), new Object[] { Long.toHexString(pointer), Long.toHexString(limit) }));
}
return mapArray(runtime.allocateInstance(this, fldInstanceSize, length, false), pointer);
}
public Struct newStructAt(long pointer) throws InstantiationException, IllegalAccessException {
int attributes = fldAttributes;
if((attributes & TYPE_MASK) != STRUCT)
{
throw new InstantiationException(package.getResourceString("instantiation.struct")) { type = this };
}
label0:
{
boolean isVisible = true;
switch(attributes & VISIBILITY_MASK)
{
case DEFAULT:
Class type = Thread.callerTypeTrace();
isVisible = parentPackage == type.parentPackage && sourceSimpleFileName.equals(type.sourceSimpleFileName);
break;
case PACKAGE:
Class type = Thread.callerTypeTrace();
isVisible = parentPackage == type.parentPackage;
break;
default:
break label0;
}
if(!isVisible)
{
throw new IllegalAccessException(String.format(package.getResourceString("illegal-access.type"), new Object[] { getCanonicalName() }));
}
}
long limit = pointer + fldStructSize;
Runtime runtime = Runtime.getInstance();
if(!runtime.isCanonicalPointer(pointer))
{
throw new SecurityException(String.format(package.getResourceString("security.pointer"), new Object[] { Long.toHexString(pointer) }));
}
if(limit - pointer > 1 && !runtime.isCanonicalPointer(limit - 1))
{
throw new SecurityException(String.format(package.getResourceString("security.pointer"), new Object[] { Long.toHexString(limit - 1) }));
}
if(runtime.isProtectedMemory(new long2 { pointer, limit }))
{
throw new SecurityException(String.format(package.getResourceString("security.memory"), new Object[] { Long.toHexString(pointer), Long.toHexString(limit) }));
}
Struct result = mapStruct(runtime.allocateInstance(this, fldInstanceSize, -1, false), pointer);
result.afterConstruction();
return result;
}
public String simpleName { read = getSimpleName }
public String canonicalName { read = getCanonicalName }
public int structSize { read = fldStructSize }
public int instanceSize { read = fldInstanceSize }
public int vectorLength { read = getVectorLength }
public int primitiveKind { read = fldPrimitiveKind }
public Class[] superServices { read = getSuperServices }
public Class superClass { read = getSuperClass }
public Class vectorBase { read = getVectorBase }
public Class componentType { read = getComponentType }
public String sourceFullFileName { read = getSourceFullFileName }
public String sourceSimpleFileName { read = getSourceSimpleFileName }
public Package parentPackage { read = getParentPackage }
package native int4 getStructReferencedFieldInfo(int index);
package native Class getStructReferencedFieldType(int index);
package int structReferencedFieldsCount { read = fldStructReferencedFieldsCount }
private void clinitUnlock() {
Runtime runtime = Runtime.getInstance();
if(!runtime.multiThreaded)
{
fldClinitStatus = INITIALIZED;
fldClinitMonitor = null;
fldClinitThread = null;
return;
}
Object monitor = null;
Mutex operation = runtime.systemOperation;
operation.lock();
try
{
monitor = fldClinitMonitor;
fldClinitStatus = INITIALIZED;
fldClinitMonitor = null;
fldClinitThread = null;
} finally
{
operation.unlock();
}
if(monitor != null) synchronized(monitor)
{
monitor.notifyAll();
}
}
private boolean clinitTryLock() {
if(fldClinitStatus == INITIALIZED) return false;
Runtime runtime = Runtime.getInstance();
if(!runtime.multiThreaded)
{
if(fldClinitStatus == INITIALIZING)
{
return false;
}
fldClinitStatus = INITIALIZING;
return true;
}
int result = 0;
Object monitor = null;
Mutex operation = runtime.systemOperation;
operation.lock();
try
{
switch(fldClinitStatus)
{
case NOT_INITIALIZED:
fldClinitThread = Thread.current();
fldClinitStatus = INITIALIZING;
break;
case INITIALIZING:
if(fldClinitThread != Thread.current())
{
if((monitor = fldClinitMonitor) == null) fldClinitMonitor = monitor = new Object();
result = 1;
break;
}
/* падение через */
default:
result = -1;
}
} finally
{
operation.unlock();
}
if(result == 1) synchronized(monitor)
{
do
{
try
{
monitor.wait(10);
}
catch(InterruptedException exception)
{
exception.printStackTrace();
}
} while(fldClinitStatus < INITIALIZED);
}
return result == 0;
}
private boolean isInheritedFrom(Class type) {
for(Class current = getSuperClass(); current != null; current = current.getSuperClass()) if(current == type) return true;
return false;
}
private boolean isServiceImplements(Class type) {
for(int index = fldSuperServicesCount; index-- > 0; ) if(getSuperService(index) == type) return true;
return false;
}
private int getVectorLength() {
int kind = fldPrimitiveKind;
return kind <= VOID ? 0 : 1 << (kind & 3);
}
private native long getSourceFileNamePointer();
private native long getServiceMethodEntryPoint(Class type, int offset);
private Class[] getSuperServices() {
Class[] result = fldSuperServices;
if(result == null)
{
int length = fldSuperServicesCount;
result = new Class[length];
for(int index = length; index-- > 0; ) result[index] = getSuperService(index);
result.finalize();
fldSuperServices = result;
}
return result;
}
private native Class getSuperService(int index);
private native Class getSuperClass();
private Class getVectorBase() {
switch(fldPrimitiveKind >> 2)
{
case VOID >> 2:
return void.class;
case BOOLEAN >> 2:
return boolean.class;
case CHAR >> 2:
return char.class;
case BYTE >> 2:
return byte.class;
case SHORT >> 2:
return short.class;
case INT >> 2:
return int.class;
case LONG >> 2:
return long.class;
case FLOAT >> 2:
return float.class;
case DOUBLE >> 2:
return double.class;
case REAL >> 2:
return real.class;
default:
return null;
}
}
private native Class getComponentType();
private String getSimpleName() {
String result = fldSimpleName;
return result != null ? result : fldSimpleName = String.getConstant(fldNameIndex);
}
private String getCanonicalName() {
String result = fldCanonicalName;
if(result != null) return result;
String canonicalName = getParentPackage().canonicalName;
return fldCanonicalName = String.format(canonicalName == null || canonicalName.isEmpty() ? "%1%" : "%0%.%1%", new Object[] { canonicalName, String.getConstant(fldNameIndex) });
}
private String getSourceFullFileName() {
String result = fldSourceFullFileName;
if(result != null) return result;
long sourceFileNamePointer = getSourceFileNamePointer();
return fldSourceFullFileName = sourceFileNamePointer == 0L ? "" : DebugInfo.getSourceFileNameString(sourceFileNamePointer);
}
private String getSourceSimpleFileName() {
String result = fldSourceSimpleFileName;
return result != null ? result : fldSourceSimpleFileName = (result = getSourceFullFileName()).substring(result.lastIndexOf('/') + 1);
}
private native Package getParentPackage();
private Object allocateInstance() {
return Runtime.getInstance().allocateInstance(this, (fldAttributes & TYPE_MASK) == STRUCT ? fldInstanceSize + (long) fldStructSize : fldInstanceSize, -1, false);
}
private Measureable allocateArray(int length) {
if(length < 0)
{
throw new NegativeArrayLengthException(package.getResourceString("negative-array-length"));
}
Runtime runtime = Runtime.getInstance();
Class componentType = getComponentType();
return (Measureable) runtime.allocateInstance(
this, fldInstanceSize + ((componentType.fldAttributes & TYPE_MASK) == PRIMITIVE ? componentType.fldInstanceSize : runtime.processorCodeBits >> 3) * (long) length, length, false
);
}
private Measureable allocateArray(int[] lengths) {
for(int index = lengths.length; index-- > 0; ) if(lengths[index] < 0)
{
throw new NegativeArrayLengthException(package.getResourceString("negative-array-length"));
}
return allocateSubarray(lengths, 0);
}
private Measureable allocateSubarray(int[] lengths, int index) {
int length = lengths[index++];
Measureable result = allocateArray(length);
if(index < lengths.length) for(Object[] subarray = (Object[]) result, Class subtype = getComponentType(), int sai = length; sai-- > 0; )
{
subarray[sai] = subtype.allocateSubarray(lengths, index);
}
return result;
}
}