Class.avt

Переключить прокрутку окна
Загрузить этот исходный код

/*
    Исходный код среды исполнения ПВТ-ОО.

    Этот исходный код является частью проекта ПВТ-ОО.

    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();
}