Class.java

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

/*
	Реализация спецификаций CLDC версии 1.1 (JSR-139), MIDP версии 2.1 (JSR-118)
	и других спецификаций для функционирования компактных приложений на языке
	Java (мидлетов) в среде программного обеспечения Малик Эмулятор.

	Copyright © 2016, 2019 Малик Разработчик

	Это свободная программа: вы можете перераспространять ее и/или изменять
	ее на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
	в каком она была опубликована Фондом свободного программного обеспечения;
	либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.

	Эта программа распространяется в надежде, что она будет полезной,
	но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
	или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
	общественной лицензии GNU.

	Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
	вместе с этой программой. Если это не так, см.
	<https://www.gnu.org/licenses/>.
*/


package java.lang;

import java.io.*;
import malik.emulator.io.jar.*;
import malik.emulator.util.*;

public final class Class extends Object
{
	static final int PUBLIC = 0x0001;
	static final int PRIVATE = 0x0002;
	static final int PROTECTED = 0x0004;
	static final int STATIC = 0x0008;
	static final int FINAL = 0x0010;
	static final int SYNCHRONIZED = 0x0020;
	static final int VOLATILE = 0x0040;
	static final int TRANSIENT = 0x0080;
	static final int NATIVE = 0x0100;
	static final int INTERFACE = 0x0200;
	static final int ABSTRACT = 0x0400;
	static final int STRICTFP = 0x0800;
	static final int SYNTHETIC = 0x1000;
	static final int PRIMITIVE = 0x00010000;

	public static Class forName(String typeName) throws ClassNotFoundException
	{
		boolean array;
		int len;
		if(typeName == null)
		{
			throw new ClassNotFoundException("Class.forName: класс с именем-нулевой ссылкой не найден.");
		}
		if((len = typeName.length()) <= 0)
		{
			throw new ClassNotFoundException("Class.forName: класс с пустым именем не найден.");
		}
		if((array = typeName.charAt(0) == '[') && len == 2)
		{
			switch(typeName.charAt(1))
			{
			default:
				break;
			case 'Z':
				return MalikSystem.getClassInstance("[Z");
			case 'C':
				return MalikSystem.getClassInstance("[C");
			case 'F':
				return MalikSystem.getClassInstance("[F");
			case 'D':
				return MalikSystem.getClassInstance("[D");
			case 'B':
				return MalikSystem.getClassInstance("[B");
			case 'S':
				return MalikSystem.getClassInstance("[S");
			case 'I':
				return MalikSystem.getClassInstance("[I");
			case 'J':
				return MalikSystem.getClassInstance("[J");
			}
		}
		for(Class current = MalikSystem.getClassInstance("Ljava/lang/Object;"); current != null; current = current.nextType)
		{
			if(typeName.equals(current.getName())) return current;
		}
		if(array)
		{
			for(int lim = len - 1, dimc = 1; dimc < 0x0100 && dimc < len; dimc++)
			{
				switch(typeName.charAt(dimc))
				{
				default:
					break;
				case 'Z':
					if(dimc == lim)
					{
						return createArrayType(MalikSystem.getClassInstance("[Z"), dimc - 1);
					}
					break;
				case 'C':
					if(dimc == lim)
					{
						return createArrayType(MalikSystem.getClassInstance("[C"), dimc - 1);
					}
					break;
				case 'F':
					if(dimc == lim)
					{
						return createArrayType(MalikSystem.getClassInstance("[F"), dimc - 1);
					}
					break;
				case 'D':
					if(dimc == lim)
					{
						return createArrayType(MalikSystem.getClassInstance("[D"), dimc - 1);
					}
					break;
				case 'B':
					if(dimc == lim)
					{
						return createArrayType(MalikSystem.getClassInstance("[B"), dimc - 1);
					}
					break;
				case 'S':
					if(dimc == lim)
					{
						return createArrayType(MalikSystem.getClassInstance("[S"), dimc - 1);
					}
					break;
				case 'I':
					if(dimc == lim)
					{
						return createArrayType(MalikSystem.getClassInstance("[I"), dimc - 1);
					}
					break;
				case 'J':
					if(dimc == lim)
					{
						return createArrayType(MalikSystem.getClassInstance("[J"), dimc - 1);
					}
					break;
				case 'L':
					if(typeName.charAt(lim) == ';' && lim - dimc > 1 && typeName.charAt(dimc + 1) != '[')
					{
						return createArrayType(forName(typeName.substring(dimc + 1, lim)), dimc);
					}
					break;
				case '[':
					continue;
				}
				break;
			}
		}
		throw new ClassNotFoundException((new StringBuilder()).append("Class.forName: класс ").append(typeName).append(" не найден.").toString());
	}

	private static Class findArrayType(Class componentType, int dimensionsMaximum)
	{
		int dimensionsResult = componentType.getArrayDimensionsQuantity();
		Class result = componentType;
		if(dimensionsResult > 0)
		{
			dimensionsMaximum += dimensionsResult;
			componentType = componentType.getCellType();
		}
		for(Class current = MalikSystem.getClassInstance("["); current != null; current = current.nextType)
		{
			int dimensionsCurrent;
			if(current.getCellType() == componentType && (dimensionsCurrent = current.getArrayDimensionsQuantity()) > dimensionsResult && dimensionsCurrent <= dimensionsMaximum)
			{
				dimensionsResult = dimensionsCurrent;
				result = current;
			}
		}
		return result;
	}

	private static Class createArrayType(Class componentType, int dimensionsQuantity)
	{
		boolean status;
		Class result;
		status = MalikSystem.enterMonopolyAccess();
		try
		{
			result = findArrayType(componentType, dimensionsQuantity);
			dimensionsQuantity -= result.getArrayDimensionsQuantity() - componentType.getArrayDimensionsQuantity();
			for(; dimensionsQuantity-- > 0; result = new Class(result));
		}
		finally
		{
			MalikSystem.leaveMonopolyAccess(status);
		}
		return result;
	}


	/* Нельзя менять порядок полей здесь, можно добавлять новые поля в конец списка. */
	final int modifiers;
	private final int instanceSize;
	private final int nameIndex;
	final int[] referenceOffsets;
	private final int[] virtualAddresses;
	private final long[] dynamicIndexesAndAddresses;
	private final InterfaceEntry[] interfaceEntries;
	final Class superType;
	final Class componentType;
	private Class nextType;
	Thread initializingThread;

	/* Новые поля можно добавлять только после этого комментария. Поля типов boolean, char, byte и short не добавлять. */
	private String name;
	private String canonicalName;

	private Class(Class componentType)
	{
		int len;
		int[] thisVirtuals;
		int[] objectVirtuals;
		Class firstArray = MalikSystem.getClassInstance("[");
		Class object = MalikSystem.getClassInstance("Ljava/lang/Object;");
		this.modifiers = FINAL | componentType.modifiers & (PUBLIC | PROTECTED | PRIVATE);
		this.instanceSize = 0x10;
		this.nameIndex = -1;
		this.referenceOffsets = object.referenceOffsets;
		this.virtualAddresses = thisVirtuals = new int[len = (objectVirtuals = object.virtualAddresses).length];
		this.dynamicIndexesAndAddresses = object.dynamicIndexesAndAddresses;
		this.interfaceEntries = new InterfaceEntry[0];
		this.superType = object;
		this.componentType = componentType;
		this.nextType = firstArray.nextType;
		this.name = (componentType.isArray() ? (new StringBuilder()).append('[').append(componentType.getName()) : (new StringBuilder()).append("[L").append(componentType.getName()).append(';')).toString();
		MalikSystem.arraycopyf_int(objectVirtuals, 1, thisVirtuals, 1, len - 1);
		firstArray.nextType = this;
	}

	public String toString()
	{
		return (modifiers & PRIMITIVE) != 0 ? getName() : ((modifiers & INTERFACE) != 0 ? "interface " : "class ").concat(getName());
	}

	public boolean isArray()
	{
		return componentType != null;
	}

	public boolean isInterface()
	{
		return (modifiers & INTERFACE) != 0;
	}

	public boolean isInstance(Object reference)
	{
		return reference != null && isAssignableFrom(reference.getClass());
	}

	public boolean isAssignableFrom(Class type)
	{
		int modifiers;
		int thisDimensions;
		int typeDimensions;
		if(type == null)
		{
			throw new NullPointerException("Class.isAssignableFrom: аргумент type равен нулевой ссылке.");
		}
		if(type == this)
		{
			return true;
		}
		if(((modifiers = type.modifiers) & PRIMITIVE) != 0)
		{
			return false;
		}
		if((modifiers & INTERFACE) != 0 || type.componentType == null)
		{
			return ((modifiers = this.modifiers) & INTERFACE) != 0 && type.isInterfaceImplements(this) || (modifiers & PRIMITIVE) == 0 && type.isInheritedFrom(this);
		}
		if((thisDimensions = this.getArrayDimensionsQuantity()) <= 0)
		{
			return this == MalikSystem.getClassInstance("Ljava/lang/Object;");
		}
		if((typeDimensions = type.getArrayDimensionsQuantity()) == thisDimensions)
		{
			return this.getCellType().isAssignableFrom(type.getCellType());
		}
		if(thisDimensions < typeDimensions)
		{
			return this.getCellType() == MalikSystem.getClassInstance("Ljava/lang/Object;");
		}
		return false;
	}

	public String getName()
	{
		String result;
		if((result = name) == null)
		{
			result = name = StringPool.getString(nameIndex);
		}
		return result;
	}

	public String getCanonicalName()
	{
		int len;
		String result;
		StringBuilder buffer;
		if((result = canonicalName) != null)
		{
			return result;
		}
		if((len = (buffer = new StringBuilder()).append(getName()).length()) > 0 && buffer.get(0) == '[')
		{
			int dimc;
			for(dimc = 1; dimc < len && buffer.get(dimc) == '['; dimc++);
			if(dimc < len)
			{
				buffer.delete(0, dimc);
				len -= dimc;
				switch(buffer.get(0))
				{
				default:
					break;
				case 'Z':
					buffer.delete(0).append("boolean");
					break;
				case 'C':
					buffer.delete(0).append("char");
					break;
				case 'F':
					buffer.delete(0).append("float");
					break;
				case 'D':
					buffer.delete(0).append("delete");
					break;
				case 'B':
					buffer.delete(0).append("byte");
					break;
				case 'S':
					buffer.delete(0).append("short");
					break;
				case 'I':
					buffer.delete(0).append("int");
					break;
				case 'J':
					buffer.delete(0).append("long");
					break;
				case 'L':
					buffer.delete(0);
					if(--len > 0 && buffer.get(--len) == ';')
					{
						buffer.delete(len);
					}
					break;
				}
				for(int i = dimc; i-- > 0; buffer.append("[]"));
			}
		}
		return canonicalName = buffer.toString().replace('$', '.');
	}

	public InputStream getResourceAsStream(String resourceName)
	{
		int i;
		String className;
		ResourceStream result;
		if(resourceName == null)
		{
			return null;
		}
		if(resourceName.length() > 0 && resourceName.charAt(0) == '/')
		{
			resourceName = resourceName.substring(1);
		}
		else if((i = (className = getName()).lastIndexOf('.')) >= 0)
		{
			resourceName = className.substring(0, i + 1).replace('.', '/').concat(resourceName);
		}
		return (result = new ResourceStream("/res/".concat(resourceName), "/".concat(resourceName))).hasOpenError() ? null : result;
	}

	public Object cast(Object reference)
	{
		Class type;
		if(reference != null && !isAssignableFrom(type = reference.getClass()))
		{
			throw new ClassCastException((new StringBuilder()).append("Class.cast: нельзя привести экземпляр типа ").append(type.getCanonicalName()).append(" к типу ").append(this.getCanonicalName()).append('.').toString());
		}
		return reference;
	}

	public Object newInstance() throws InstantiationException, IllegalAccessException
	{
		Object result;
		MalikSystem.invokeDefaultConstructor(result = allocateInstance(true));
		return result;
	}

	boolean isInheritedFrom(Class type)
	{
		for(Class current = superType; current != null; current = current.superType)
		{
			if(current == type) return true;
		}
		return false;
	}

	boolean isInterfaceImplements(Class type)
	{
		Class current = this;
		do
		{
			InterfaceEntry[] entries;
			for(int i = (entries = current.interfaceEntries).length; i-- > 0; )
			{
				if(entries[i].implementedInterface == type) return true;
			}
		} while((current = current.superType) != null);
		return false;
	}

	int getArrayDimensionsQuantity()
	{
		int result = 0;
		for(Class current = componentType; current != null; current = current.componentType) result++;
		return result;
	}

	int getInterfaceMethodEntryPoint(Class type, int offset)
	{
		return getInterfaceEntry(type).interfaceMethodTableAddress + offset;
	}

	Class getCellType()
	{
		Class result;
		if((result = componentType) != null)
		{
			for(Class current; (current = result.componentType) != null; result = current);
		}
		return result;
	}

	Object allocateInstance()
	{
		Object result;
		try
		{
			result = allocateInstance(false);
		}
		catch(Exception e)
		{
			throw new InstantiationError(e.getMessage());
		}
		return result;
	}

	Object allocateInstance(boolean useDefaultConstructor) throws InstantiationException, IllegalAccessException
	{
		int modifiers;
		if(componentType != null)
		{
			throw new InstantiationException((new StringBuilder()).append("Class.newInstance: тип ").append(getCanonicalName()).append(" является массивом.").toString());
		}
		if(((modifiers = this.modifiers) & (ABSTRACT | INTERFACE | PRIMITIVE)) != 0)
		{
			if((modifiers & (ABSTRACT | INTERFACE)) != 0)
			{
				throw new InstantiationException((new StringBuilder()).append("Class.newInstance: тип ").append(getCanonicalName()).append(" является абстрактным.").toString());
			}
			if((modifiers & PRIMITIVE) != 0)
			{
				throw new InstantiationException((new StringBuilder()).append("Class.newInstance: тип ").append(getCanonicalName()).append(" является примитивным.").toString());
			}
		}
		if(useDefaultConstructor)
		{
			if((modifiers & PUBLIC) == 0)
			{
				throw new IllegalAccessException((new StringBuilder()).append("Class.newInstance: тип ").append(getCanonicalName()).append(" не является открытым (public).").toString());
			}
			if(virtualAddresses[0] == 0)
			{
				throw new IllegalAccessException((new StringBuilder()).append("Class.newInstance: класс ").append(getCanonicalName()).append(" не имеет открытого (public) конструктора без аргументов.").toString());
			}
		}
		return Memory.allocateInstanceOf(this, instanceSize, -1);
	}

	private InterfaceEntry getInterfaceEntry(Class type)
	{
		Class current = this;
		do
		{
			InterfaceEntry[] entries;
			for(int i = (entries = current.interfaceEntries).length; i-- > 0; )
			{
				InterfaceEntry entry;
				if((entry = entries[i]).implementedInterface == type) return entry;
			}
		} while((current = current.superType) != null);
		return null;
	}
}

final class InterfaceEntry extends Object
{
	/* Нельзя менять порядок полей здесь, нельзя добавлять новые поля сюда. */
	final int interfaceMethodTableAddress;
	final Class implementedInterface;

	public InterfaceEntry(int interfaceMethodTableAddress, Class implementedInterface)
	{
		this.interfaceMethodTableAddress = interfaceMethodTableAddress;
		this.implementedInterface = implementedInterface;
	}
}