/*
Исходный код среды исполнения ПВТ-ОО.
Этот исходный код является частью проекта ПВТ-ОО.
Copyright © 2021 Малик Разработчик
Это свободная программа: вы можете перераспространять её и/или
изменять её на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
в каком она была опубликована Фондом свободного программного обеспечения;
либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.
Эта программа распространяется в надежде, что она может быть полезна,
но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЁННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
общественной лицензии GNU.
Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
вместе с этой программой. Если это не так, см.
<http://www.gnu.org/licenses/>.
*/
package avt.lang;
import avt.lang.array.*;
import platform.dependent.*;
public final class Class(/*Reflective*/Object)
{
public static final int SOURCE = 0x00000002;
public static final int PACKAGE = 0x00000004;
public static final int PUBLIC = 0x00000006;
public static final int PUBLISHED = 0x00000007;
public static final int VISIBILITY_MASK = 0x00000007;
public static final int ABSTRACT = 0x00000008;
public static final int FINAL = 0x00000010;
public static final int SERVICE = 0x00000020;
public static final int STRUCT = 0x00000040;
public static final int INTERFACE = 0x00000060;
public static final int PRIMITIVE = 0x00000080;
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("тип с пустым именем не найден");
}
int dotPosition = canonicalName.lastIndexOf('.');
Package ownedPackage = Package.find(dotPosition < 0 ? null : canonicalName.substring(0, dotPosition));
label0: if(ownedPackage != null)
{
String simpleName = canonicalName.substring(dotPosition + 1);
Class result = ownedPackage.findType(simpleName);
if(result != null) return result;
int bracketPosition = simpleName.indexOf("[]");
if(bracketPosition > 0 && (result = ownedPackage.findType(simpleName.substring(0, bracketPosition))) != null)
{
for(Class arrayType; (arrayType = ownedPackage.findType(simpleName.substring(0, bracketPosition += 2))) != null; result = arrayType)
{
if(!simpleName.startsWith("[]", bracketPosition)) break label0;
}
int simpleNameLength = simpleName.length;
Mutex sysmutex = Runtime.getInstance().systemMutex;
sysmutex.lock();
try
{
for(Class arrayType; (arrayType = ownedPackage.getAddedArrayType(result)) != null; bracketPosition += 2)
{
result = arrayType;
if(bracketPosition >= simpleNameLength) return result;
if(!simpleName.startsWith("[]", bracketPosition)) break label0;
}
for(; ; bracketPosition += 2)
{
result = createArrayType(result, ownedPackage);
if(bracketPosition >= simpleNameLength) return result;
if(!simpleName.startsWith("[]", bracketPosition)) break label0;
}
}
finally
{
sysmutex.unlock();
}
}
}
throw new ClassNotFoundException("тип не найден");
}
private static Class createArrayType(Class componentType, Package ownedPackage) {
Runtime runtime = Runtime.getInstance();
String simpleName = componentType.getSimpleName();
String canonicalName = ownedPackage.canonicalName;
canonicalName = String.format(canonicalName.isEmpty() ? "%1%[]" : "%0%.%1%[]", new Object[] { canonicalName, simpleName });
Class superType = Object[].class;
Class result = (Class) runtime.allocateInstance(Class.class, (long) superType.fldServicesOffset + (long) superType.fldServicesCount * (runtime.processorCodeBits >> 3), -1, false);
fillClass(result, superType, componentType, ownedPackage);
result.fldSourceName = "";
result.fldSimpleName = canonicalName.substring(canonicalName.length - simpleName.length - 2);
result.fldCanonicalName = canonicalName;
ownedPackage.addType(result);
return result;
}
private static native void fillClass(Class type, Class superType, Class componentType, Package ownedPackage);
private final int fldModifiers;
private final int fldSimpleNameIndex;
private final int fldInstanceSize;
private final int fldStructSize;
private final int fldReferencedFieldsCount;
private final int fldVirtualsCount;
private final int fldImplementorsCount;
private final int fldServicesCount;
private final int fldStructReferencedFieldsCount;
private final int fldDeclaredFieldsCount;
private final int fldDeclaredMethodsCount;
private final int fldDeclaredPropertiesCount;
private final int fldReferencedFieldsOffset;
private final int fldVirtualsOffset;
private final int fldImplementorsOffset;
private final int fldServicesOffset;
private final int fldStructReferencedFieldsOffset;
private final int fldDeclaredFieldsOffset;
private final int fldDeclaredMethodsOffset;
private final int fldDeclaredPropertiesOffset;
private final long fldSuperTypeOffset;
private final long fldComponentTypeOffset;
private final long fldOwnedPackageOffset;
private final long fldMainConstructorOffset;
private final int fldSourceNameOffset;
private int fldClinitStatus;
private Thread fldClinitThread;
private Object fldClinitMonitor;
private String fldSourceName;
private String fldSimpleName;
private String fldCanonicalName;
private () { }
public String toString() {
int modifiers = fldModifiers;
String type;
if((modifiers & (INTERFACE | PRIMITIVE)) == PRIMITIVE)
{
type = "primitive ";
}
else if((modifiers & (INTERFACE | PRIMITIVE)) == INTERFACE)
{
type = "interface ";
}
else if((modifiers & (SERVICE | PRIMITIVE)) == SERVICE)
{
type = "service ";
}
else if((modifiers & (INTERFACE | PRIMITIVE)) == STRUCT)
{
type = "struct ";
}
else
{
type = "class ";
}
return type + getCanonicalName();
}
public boolean isArray() { return fldComponentTypeOffset != 0L; }
public boolean isClass() { return (fldModifiers & (INTERFACE | PRIMITIVE)) == 0; }
public boolean isStruct() { return (fldModifiers & (INTERFACE | PRIMITIVE)) == STRUCT; }
public boolean isService() { return (fldModifiers & (SERVICE | PRIMITIVE)) == SERVICE; }
public boolean isInterface() { return (fldModifiers & (INTERFACE | PRIMITIVE)) == INTERFACE; }
public boolean isPrimitive() { return (fldModifiers & (INTERFACE | PRIMITIVE)) == PRIMITIVE; }
public boolean isCompound() { return (getPrimitiveKind() & 3) != 0; }
public boolean isAbstract() { return (fldModifiers & ABSTRACT) != 0; }
public boolean isFinal() { return (fldModifiers & FINAL) != 0; }
public boolean isAssignableFrom(Class type) {
if(type == null)
{
throw new NullPointerException("аргумент type равен нулевой ссылке");
}
if(type == this)
{
return true;
}
int modifiers = type.fldModifiers;
if((modifiers & (INTERFACE | PRIMITIVE)) == PRIMITIVE | ((modifiers = fldModifiers) & (INTERFACE | PRIMITIVE)) == PRIMITIVE)
{
/* type.isPrimitive() | this.isPrimitive() */
return false;
}
if(fldComponentTypeOffset == 0L)
{
/* !this.isArray() */
return (modifiers & (SERVICE | PRIMITIVE)) == SERVICE ? type.isServiceImplements(this) : type.isInheritedFrom(this);
}
int thisDimensions = this.getArrayDimensionsQuantity();
int typeDimensions = type.getArrayDimensionsQuantity();
return thisDimensions <= typeDimensions && getArrayCellType().isAssignableFrom(thisDimensions < typeDimensions ? Object[].class : type.getArrayCellType());
}
public boolean isInstance(Object instance) { return instance != null && isAssignableFrom(instance.getClass()); }
public int getArrayDimensionsQuantity() {
int result = 0;
for(Class current = getComponentType(); current != null; current = current.getComponentType()) result++;
return result;
}
public Class getArrayCellType() {
Class result = null;
for(Class current = getComponentType(); current != null; current = current.getComponentType()) result = current;
return result;
}
public Object cast(Object instance) {
Class source;
if(instance != null && !isAssignableFrom(source = instance.getClass()))
{
throw new ClassCastException("приведение к типу невозможно") { source = source, destination = this };
}
return instance;
}
public Object newInstance() throws InstantiationException, IllegalAccessException {
int modifiers = fldModifiers;
if(fldComponentTypeOffset != 0L || (modifiers & INTERFACE) == INTERFACE || (modifiers & PRIMITIVE) == PRIMITIVE || (modifiers & ABSTRACT) == ABSTRACT)
{
throw new InstantiationException("тип не является размещаемым методом Class.newInstance") { type = this };
}
if(fldMainConstructorOffset == 0L)
{
throw new InstantiationException("тип не имеет открытого конструктора без аргументов") { type = this };
}
label0:
{
boolean isVisible = false;
StackTraceElement caller = Thread.callerTrace();
switch(modifiers & VISIBILITY_MASK)
{
case SOURCE:
isVisible = ownedPackage == caller.typeRef.ownedPackage && sourceName.equals(caller.sourceName);
break;
case PACKAGE:
isVisible = ownedPackage == caller.typeRef.ownedPackage;
break;
case PUBLIC:
case PUBLISHED:
break label0;
}
if(!isVisible)
{
throw new IllegalAccessException((new StringBuilder() + "тип " + getCanonicalName() + " не является видимым для вызвавшего метода").toString());
}
}
Object result = allocateInstance();
invokeMainConstructor(result);
result.afterConstruction();
return result;
}
public Measureable newArray(int length) throws InstantiationException, IllegalAccessException {
if(fldComponentTypeOffset == 0L)
{
throw new InstantiationException("тип не является массивом") { type = this };
}
label0:
{
boolean isVisible = false;
StackTraceElement caller = Thread.callerTrace();
switch(fldModifiers & VISIBILITY_MASK)
{
case SOURCE:
isVisible = ownedPackage == caller.typeRef.ownedPackage && sourceName.equals(caller.sourceName);
break;
case PACKAGE:
isVisible = ownedPackage == caller.typeRef.ownedPackage;
break;
case PUBLIC:
case PUBLISHED:
break label0;
}
if(!isVisible)
{
throw new IllegalAccessException((new StringBuilder() + "тип " + getCanonicalName() + " не является видимым для вызвавшего метода").toString());
}
}
return allocateArray(length);
}
public Measureable newArray(int[] lengths) throws InstantiationException, IllegalAccessException {
int length;
long componentTypeOffset;
if(lengths == null)
{
throw new NullPointerException("аргумент lengths равен нулевой ссылке");
}
if((length = lengths.length) < 1)
{
throw new IllegalArgumentException("аргумент lengths не должен быть пустым");
}
if((componentTypeOffset = fldComponentTypeOffset) != 0L && length > getArrayDimensionsQuantity())
{
throw new IllegalArgumentException("аргумент lengths не должен быть длиннее количества измерений массива");
}
if(componentTypeOffset == 0L)
{
throw new InstantiationException("тип не является массивом") { type = this };
}
label0:
{
boolean isVisible = false;
StackTraceElement caller = Thread.callerTrace();
switch(fldModifiers & VISIBILITY_MASK)
{
case SOURCE:
isVisible = ownedPackage == caller.typeRef.ownedPackage && sourceName.equals(caller.sourceName);
break;
case PACKAGE:
isVisible = ownedPackage == caller.typeRef.ownedPackage;
break;
case PUBLIC:
case PUBLISHED:
break label0;
}
if(!isVisible)
{
throw new IllegalAccessException((new StringBuilder() + "тип " + getCanonicalName() + " не является видимым для вызвавшего метода").toString());
}
}
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("тип не является массивом") { type = this };
}
if((componentType.fldModifiers & (INTERFACE | PRIMITIVE)) != PRIMITIVE)
{
throw new InstantiationException("тип элементов массива не является примитивом") { type = this };
}
if((fldModifiers & VISIBILITY_MASK) < PUBLIC)
{
throw new IllegalAccessException((new StringBuilder() + "тип " + getCanonicalName() + " не является видимым для вызвавшего метода").toString());
}
if(length < 0)
{
throw new NegativeArrayLengthException("невозможно создать массив отрицательной длины");
}
Runtime runtime = Runtime.getInstance();
if(runtime.isProtectedMemory(pointer, pointer + (long) componentType.fldInstanceSize * (long) length))
{
throw new SecurityException((new StringBuilder() + "память по указателю 0x" + Long.toHexString(pointer) + "защищена от случайных модификаций").toString());
}
return mapArray(runtime.allocateInstance(this, fldInstanceSize, length, false), pointer);
}
public Struct newStructAt(long pointer) throws InstantiationException, IllegalAccessException {
int modifiers = fldModifiers;
if((modifiers & (INTERFACE | PRIMITIVE)) != STRUCT)
{
throw new InstantiationException("тип не является структурой") { type = this };
}
label0:
{
boolean isVisible = false;
StackTraceElement caller = Thread.callerTrace();
switch(modifiers & VISIBILITY_MASK)
{
case SOURCE:
isVisible = ownedPackage == caller.typeRef.ownedPackage && sourceName.equals(caller.sourceName);
break;
case PACKAGE:
isVisible = ownedPackage == caller.typeRef.ownedPackage;
break;
case PUBLIC:
case PUBLISHED:
break label0;
}
if(!isVisible)
{
throw new IllegalAccessException((new StringBuilder() + "тип " + getCanonicalName() + " не является видимым для вызвавшего метода").toString());
}
}
Runtime runtime = Runtime.getInstance();
if(runtime.isProtectedMemory(pointer, pointer + fldStructSize))
{
throw new SecurityException((new StringBuilder() + "память по указателю 0x" + Long.toHexString(pointer) + "защищена от случайных модификаций").toString());
}
Struct result = mapStruct(runtime.allocateInstance(this, fldInstanceSize, -1, false), pointer);
result.afterConstruction();
return result;
}
public int modifiers { read = fldModifiers }
public int visibility { read = getVisibility }
public int structSize { read = getStructSize }
public int instanceSize { read = fldInstanceSize }
public int primitiveKind { read = getPrimitiveKind }
public int compoundLength { read = getCompoundLength }
public Class compoundBase { read = getCompoundBase }
public Class componentType { read = getComponentType }
public Class superType { read = getSuperType }
public Class[] superServices { read = getSuperServices }
public String sourceName { read = getSourceName }
public String simpleName { read = getSimpleName }
public String canonicalName { read = getCanonicalName }
public Package ownedPackage { read = getOwnedPackage }
package native int4 getStructReferencedFieldInfo(int index);
package native Class getStructReferencedFieldType(int index);
package int structReferencedFieldsCount { read = fldStructReferencedFieldsCount }
private native void invokeMainConstructor(Object instance);
private void clinitUnlock() {
Object clinitmon = null;
Mutex sysmutex = Runtime.getInstance().systemMutex;
sysmutex.lock();
try
{
clinitmon = fldClinitMonitor;
fldClinitStatus = INITIALIZED;
fldClinitMonitor = null;
fldClinitThread = null;
}
finally
{
sysmutex.unlock();
}
if(clinitmon != null) synchronized(clinitmon)
{
clinitmon.notifyAll();
}
}
private boolean clinitTryLock() {
int result = 0;
Object clinitmon = null;
Mutex sysmutex = Runtime.getInstance().systemMutex;
sysmutex.lock();
try
{
switch(fldClinitStatus)
{
case NOT_INITIALIZED:
fldClinitThread = Thread.current();
fldClinitStatus = INITIALIZING;
break;
case INITIALIZING:
if(fldClinitThread != Thread.current())
{
if((clinitmon = fldClinitMonitor) == null) fldClinitMonitor = clinitmon = new Object();
result = 1;
break;
}
default:
result = -1;
}
}
finally
{
sysmutex.unlock();
}
if(result == 1) synchronized(clinitmon)
{
do
{
try
{
clinitmon.wait();
}
catch(InterruptedException e)
{
e.printStackTrace();
}
} while(fldClinitStatus < INITIALIZED);
}
return result == 0;
}
private boolean isInheritedFrom(Class type) {
for(Class current = getSuperType(); current != null; current = current.getSuperType())
{
if(current == type) return true;
}
return false;
}
private boolean isServiceImplements(Class type) {
for(int i = fldServicesCount; i-- > 0; )
{
if(getSuperService(i) == type) return true;
}
return false;
}
private int getVisibility() { return fldModifiers & VISIBILITY_MASK; }
private int getStructSize() { return (fldModifiers & (INTERFACE | PRIMITIVE)) == PRIMITIVE ? -1 : fldStructSize; }
private int getPrimitiveKind() {
if((fldModifiers & (INTERFACE | PRIMITIVE)) != PRIMITIVE) return -1;
int result = fldStructSize;
switch(result)
{
case 20:
return VOID;
case 21:
return BOOLEAN;
case 22:
return CHAR;
case 23:
return REAL;
default:
return result;
}
}
private int getCompoundLength() {
int kind = getPrimitiveKind();
return kind <= VOID ? 0 : 1 << (kind & 3);
}
private native long getSourceNamePointer();
private native long getImplementorOf(Class type);
private long getServiceMethodEntryPoint(Class type, int offset) {
long impl = getImplementorOf(type);
if(impl == 0L)
{
throw new ServiceNotImplementedError("сервис не реализован");
}
return impl + (long) offset;
}
private Object allocateInstance() { return Runtime.getInstance().allocateInstance(this, (fldModifiers & (INTERFACE | PRIMITIVE)) == STRUCT ? fldInstanceSize + fldStructSize : fldInstanceSize, -1, false); }
private Measureable allocateArray(int length) {
if(length < 0)
{
throw new NegativeArrayLengthException("невозможно создать массив отрицательной длины");
}
Runtime runtime = Runtime.getInstance();
Class componentType = getComponentType();
return (Measureable) runtime.allocateInstance(this, ((componentType.fldModifiers & (INTERFACE | PRIMITIVE)) == PRIMITIVE ? componentType.fldInstanceSize : runtime.processorCodeBits >> 3) * (long) length + 0x40L, length, false);
}
private Measureable allocateArray(int[] lengths) {
for(int i = lengths.length; i-- > 0; ) if(lengths[i] < 0)
{
throw new NegativeArrayLengthException("невозможно создать массив отрицательной длины");
}
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 i = length; i-- > 0; )
{
subarray[i] = subtype.allocateSubArray(lengths, index);
}
return result;
}
private native Measureable mapArray(Object array, long pointer);
private native Struct mapStruct(Object struc, long pointer);
private Class getCompoundBase() {
switch(getPrimitiveKind() >> 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 native Class getSuperType();
private native Class getSuperService(int index);
private Class[] getSuperServices() {
int length = fldServicesCount;
Class[] result = new Class[length];
for(int i = length; i-- > 0; ) result[i] = getSuperService(i);
return result;
}
private String getSourceName() {
String result = fldSourceName;
if(result == null) try
{
long sourceNamePointer = getSourceNamePointer();
result = sourceNamePointer == 0L ? "" : new String((char[]) char[].class.newArrayAt(sourceNamePointer, DebugInfo.getSourceNameLength(sourceNamePointer)));
}
catch(Exception e) { }
return result;
}
private String getSimpleName() {
String result = fldSimpleName;
return result != null ? result : fldSimpleName = String.getConstant(fldSimpleNameIndex);
}
private String getCanonicalName() {
String result = fldCanonicalName;
if(result != null) return result;
Package ownedPackage = getOwnedPackage();
String canonicalName = ownedPackage == null ? null : ownedPackage.canonicalName;
return fldCanonicalName = String.format(canonicalName == null || canonicalName.isEmpty() ? "%1%" : "%0%.%1%", new Object[] { canonicalName, String.getConstant(fldSimpleNameIndex) });
}
private native Package getOwnedPackage();
}