{
JavaRecompiler реализует статический рекомпилятор для языка Java.
Этот исходный текст является частью Малик Эмулятора.
Copyright © 2016–2017, 2019–2023 Малик Разработчик
Малик Эмулятор – свободная программа: вы можете перераспространять её и/или
изменять её на условиях Стандартной общественной лицензии GNU в том виде,
в каком она была опубликована Фондом свободного программного обеспечения;
либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.
Малик Эмулятор распространяется в надежде, что он может быть полезен,
но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЁННЫХ ЦЕЛЕЙ. Подробнее см. в Стандартной
общественной лицензии GNU.
Вы должны были получить копию Стандартной общественной лицензии GNU
вместе с этой программой. Если это не так, см.
<http://www.gnu.org/licenses/>.
}
unit JavaRecompiler;
{$MODE DELPHI}
interface
uses
Classes,
SysUtils,
Graphics,
Lang,
IOStreams,
FileIO,
Zlib,
ReadZIP,
Manifests,
EmulMalik,
EmulConstants,
StaticRecompilers,
StringPools;
{%region public }
const
ATTRIBUTE_CONTAINER_GUID = '{74C86B60-AC5B-4E8D-8ACD-29A50B5C1517}';
CONSTANT_POOL_CONTAINER_GUID = '{74C86B60-AC5B-4E8D-8ACD-29A50B5C1518}';
type
AttributeContainer = interface;
ConstantPoolContainer = interface;
ClassNotFoundException = class;
ClassMemberNotFoundException = class;
ClassFileInvalidFormatException = class;
UnsupportedClassVersionException = class;
UnsupportedBytecodeException = class;
ManifestNotFoundException = class;
ManifestPropertyNotFoundException = class;
ConstantPoolEntry = class;
StringEntry = class;
IntegerEntry = class;
LongEntry = class;
FloatEntry = class;
DoubleEntry = class;
SingleIndexedEntry = class;
DoubleIndexedEntry = class;
ExceptionCatch = class;
ExceptionHandler = class;
InterfaceMethodImplements = class;
InterfaceImplementsInfo = class;
JavaAttribute = class;
JavaConstantValue = class;
JavaLineNumberTable = class;
JavaCode = class;
JavaClassMember = class;
JavaField = class;
JavaMethod = class;
JavaClass = class;
JavaArray = class;
JavaStaticRecompiler = class;
JavaAttribute_Class = class of JavaAttribute;
ConstantPoolEntry_Array1d = packed array of ConstantPoolEntry;
ExceptionCatch_Array1d = packed array of ExceptionCatch;
ExceptionHandler_Array1d = packed array of ExceptionHandler;
InterfaceMethodImplements_Array1d = packed array of InterfaceMethodImplements;
InterfaceImplementsInfo_Array1d = packed array of InterfaceImplementsInfo;
JavaField_Array1d = packed array of JavaField;
JavaMethod_Array1d = packed array of JavaMethod;
JavaClass_Array1d = packed array of JavaClass;
JavaArray_Array1d = packed array of JavaArray;
AttributeContainer = interface(_Interface) [ATTRIBUTE_CONTAINER_GUID]
procedure onAddAttribute(attribute: JavaAttribute);
function getAttributeClass(const name: AnsiString): JavaAttribute_Class;
end;
ConstantPoolContainer = interface(_Interface) [CONSTANT_POOL_CONTAINER_GUID]
function getLongIndex(value: long): int;
function getDoubleIndex(value: double): int;
function getStringIndex(const value: AnsiString): int;
function getConstantPoolLength(): int;
function getConstantPoolEntry(index: int): ConstantPoolEntry;
function getConstantPoolMember(index, memberType: int): JavaClassMember; overload;
function getConstantPoolMember(classNameIndex, memberNameIndex, memberSignatureIndex, memberType: int): JavaClassMember; overload;
end;
ClassNotFoundException = class(Exception)
public
constructor create(); overload;
constructor create(const message: AnsiString); overload;
end;
ClassMemberNotFoundException = class(Exception)
public
constructor create(); overload;
constructor create(const message: AnsiString); overload;
end;
NativeMethodNotFoundException = class(Exception)
public
constructor create(); overload;
constructor create(const message: AnsiString); overload;
end;
ClassFileInvalidFormatException = class(Exception)
public
constructor create(); overload;
constructor create(const message: AnsiString); overload;
end;
UnsupportedClassVersionException = class(Exception)
public
constructor create(); overload;
constructor create(const message: AnsiString); overload;
end;
UnsupportedBytecodeException = class(Exception)
public
constructor create(); overload;
constructor create(const message: AnsiString); overload;
end;
ManifestNotFoundException = class(Exception)
public
constructor create(); overload;
constructor create(const message: AnsiString); overload;
end;
ManifestPropertyNotFoundException = class(Exception)
public
constructor create(); overload;
constructor create(const message: AnsiString); overload;
end;
ConstantPoolEntry = class(_Object)
public
constructor create();
end;
StringEntry = class(ConstantPoolEntry)
strict private
value: AnsiString;
public
constructor create(const value: AnsiString);
function stringValue(): AnsiString;
end;
IntegerEntry = class(ConstantPoolEntry)
strict private
value: int;
public
constructor create(value: int);
function intValue(): int;
end;
LongEntry = class(ConstantPoolEntry)
strict private
value: long;
public
constructor create(value: long);
function longValue(): long;
end;
FloatEntry = class(ConstantPoolEntry)
strict private
value: float;
public
constructor create(value: float);
function floatValue(): float;
end;
DoubleEntry = class(ConstantPoolEntry)
strict private
value: double;
public
constructor create(value: double);
function doubleValue(): double;
end;
SingleIndexedEntry = class(ConstantPoolEntry)
strict private
entryType: int;
index1: int;
public
constructor create(entryType, index1: int);
function getEntryType(): int;
function getIndex1(): int;
end;
DoubleIndexedEntry = class(SingleIndexedEntry)
strict private
index2: int;
public
constructor create(entryType, index1, index2: int);
function getIndex2(): int;
end;
ExceptionCatch = class(_Object)
strict private
catchOffset: int;
classIndex: int;
commandIndex: int;
private
function getCommandIndex(): int;
procedure setCommandIndex(commandIndex: int);
public
constructor create(catchOffset, classIndex: int);
function getCatchOffset(): int;
function getClassIndex(): int;
end;
ExceptionHandler = class(_Object)
strict private
tryStart: int;
tryFinish: int;
catchesLength: int;
catches: ExceptionCatch_Array1d;
public
constructor create(tryStart, tryFinish: int);
destructor destroy; override;
function getTryStart(): int;
function getTryFinish(): int;
function getCatchesLength(): int;
function getCatch(index: int): ExceptionCatch;
procedure addCatch(catchOffset, classIndex: int);
end;
InterfaceMethodImplements = class(_Object)
strict private
interfaceMethod: JavaMethod;
classMethod: JavaMethod;
private
procedure setClassMethod(classMethod: JavaMethod);
public
constructor create(interfaceMethod: JavaMethod);
function getMethodName(): AnsiString;
function getMethodSignature(): AnsiString;
function getInterfaceMethod(): JavaMethod;
function getClassMethod(): JavaMethod;
end;
InterfaceImplementsInfo = class(_Object)
strict private
name: AnsiString;
intf: JavaClass;
imtOffset: int;
methods: InterfaceMethodImplements_Array1d;
private
procedure setInterface(intf: JavaClass);
procedure setIMTOffset(imtOffset: int);
public
constructor create(const interfaceName: AnsiString); overload;
constructor create(intf: JavaClass); overload;
destructor destroy; override;
function getInterfaceName(): AnsiString;
function getInterface(): JavaClass;
function getIMTOffset(): int;
function getMethodsCount(): int;
function getMethodImplements(index: int): InterfaceMethodImplements;
end;
JavaAttribute = class(_Object)
strict private
owner: AttributeContainer;
content: byte_Array1d;
name: AnsiString;
private
function byteAt(offset: int): int;
function shortAt(offset: int): int;
function intAt(offset: int): int;
function unsignedByteAt(offset: int): int;
function unsignedShortAt(offset: int): int;
public
constructor create(owner: AttributeContainer; const name: AnsiString; const content: byte_Array1d; const constantPool: ConstantPoolEntry_Array1d); virtual;
function getOwner(): AttributeContainer;
function getSize(): int;
function getName(): AnsiString;
public
class procedure readAttributes(container: AttributeContainer; stream: DataInput; const constantPool: ConstantPoolEntry_Array1d);
end;
JavaConstantValue = class(JavaAttribute)
strict private
constantPoolIndex: int;
public
constructor create(owner: AttributeContainer; const name: AnsiString; const content: byte_Array1d; const constantPool: ConstantPoolEntry_Array1d); override;
function getConstantPoolIndex(): int;
end;
JavaLineNumberTable = class(JavaAttribute)
strict private
linesCount: int;
public
constructor create(owner: AttributeContainer; const name: AnsiString; const content: byte_Array1d; const constantPool: ConstantPoolEntry_Array1d); override;
function getLinesCount(): int;
function getLineNumber(lineIndex: int): int;
function getCodeOffsetAt(lineIndex: int): int;
end;
JavaCode = class(JavaAttribute, AttributeContainer)
strict private
registersCount: int;
variablesCount: int;
exceptionHandlersCount: int;
exceptionHandlers: ExceptionHandler_Array1d;
instructionOffsets: int_Array1d;
trueRegistersIndices: int_Array1d;
lineNumberTable: JavaLineNumberTable;
procedure addExceptionHandler(tryStart, tryFinish, catchOffset, classIndex: int);
procedure sortHandlers();
procedure fillInstructionOffsets();
procedure fillTrueRegistersIndices();
function getRegisterSize(registerIndex: int): int;
public
constructor create(owner: AttributeContainer; const name: AnsiString; const content: byte_Array1d; const constantPool: ConstantPoolEntry_Array1d); override;
destructor destroy; override;
procedure onAddAttribute(attribute: JavaAttribute);
function getAttributeClass(const name: AnsiString): JavaAttribute_Class;
function getInstructionsCount(): int;
function getInstructionOffset(instructionIndex: int): int;
function getTrueRegisterIndex(javaRegisterIndex: int): int;
function getExceptionHandlersCount(): int;
function getExceptionHandler(index: int): ExceptionHandler;
function getVariablesCount(): int;
function getLineNumberTable(): JavaLineNumberTable;
function indexOfInstruction(instructionOffset: int): int;
strict private
class function extractCode(const content: byte_Array1d): byte_Array1d;
end;
JavaClassMember = class(_Object, AttributeContainer)
strict private
owner: JavaClass;
offset: int;
flags: int;
name: AnsiString;
signature: AnsiString;
private
procedure setOffset(offset: int);
public
constructor create(owner: JavaClass; flags: int; const name, signature: AnsiString);
procedure onAddAttribute(attribute: JavaAttribute); virtual; abstract;
function getAttributeClass(const name: AnsiString): JavaAttribute_Class; virtual; abstract;
function getCompiler(): JavaStaticRecompiler; virtual;
function getOwner(): JavaClass;
function getOffset(): int;
function getFlags(): int;
function getName(): AnsiString;
function getSignature(): AnsiString;
function getAccess(): int;
function isStatic(): boolean;
function isFinal(): boolean;
end;
JavaField = class(JavaClassMember)
strict private
constantValue: JavaConstantValue;
outToExecutable: boolean;
public
constructor create(owner: JavaClass; flags: int; const name, signature: AnsiString);
destructor destroy; override;
procedure onAddAttribute(attribute: JavaAttribute); override;
function getAttributeClass(const name: AnsiString): JavaAttribute_Class; override;
function getConstantPoolIndex(): int;
function isOutToExecutable(): boolean;
end;
JavaMethod = class(JavaClassMember)
strict private
parametersCount: int;
virtualStatus: int;
virtualIndex: int;
commandIndices: int_Array1d;
commandsCount: int;
commands: long_Array1d;
overridden: JavaMethod;
sourceCode: JavaCode;
procedure generateSyscall();
procedure generateGetVariableAddress();
procedure generateVoidInterrupt();
procedure generateIntInterrupt();
procedure generateLongInterrupt();
procedure generateObjectInterrupt();
procedure generateRunExcept();
procedure generateGetFloatAt();
procedure generateGetDoubleAt();
procedure generateGetByteAt();
procedure generateGetShortAt();
procedure generateGetIntAt();
procedure generateGetLongAt();
procedure generateGetObjectAt();
procedure generateSetFloatAt();
procedure generateSetDoubleAt();
procedure generateSetByteAt();
procedure generateSetShortAt();
procedure generateSetIntAt();
procedure generateSetLongAt();
procedure generateSetObjectAt();
procedure generateGetCurrentThreadID();
procedure generateGetReturnAddress();
procedure generateConvertToReference();
procedure generateConvertToObject();
procedure generateGetMethodAddress();
procedure generateGetClassInstance();
procedure generateArrayCopy(direction: boolean; dataType: int);
procedure generateArrayFind(direction: boolean; dataType: int);
procedure generateArrayFill(dataType: int);
procedure generateFind(direction, zero: boolean);
procedure generateGetObjectRefs();
procedure generateGetArrayRefs();
procedure generateBlockFindF();
procedure generateBlockFindB();
procedure generateInvokeDefaultConstructor();
procedure generateIntPart();
procedure generateFracPart();
procedure generateSqrt();
procedure generateArctan();
procedure generateSin();
procedure generateCos();
procedure generatePow2();
procedure generateLog2();
procedure generateFloor();
procedure generateCeil();
procedure generateRound();
procedure defineVirtualStatus();
procedure addCommandFull(cmd: long);
procedure addCommand(); overload;
procedure addCommand(opcode: int); overload;
procedure addCommand(opcode, data: int); overload;
procedure addCommand(opcode, classIndex, nameIndex, signatureIndex: int); overload;
procedure transformParameters(const signature: AnsiString);
procedure transformReturnValue(const signature: AnsiString);
procedure insertNativeCode(nativeIndex: int); overload;
procedure insertNativeCode(nativeIndex, parameter: int); overload;
function getNativeMethodIndex(pc: int): int;
function getVariableOffset(javaRegisterIndex: int): int;
private
procedure setVirtualIndex(virtualIndex: int);
procedure prepareCompile();
procedure fillStringPool();
procedure writeCode(stream: DataOutput);
function reduceSizeofJumps(): boolean;
function reduceSizeofCalls(): boolean;
function getRelativeOffset(javaInstructionOffset: int): int;
public
constructor create(owner: JavaClass; flags: int; const name, signature: AnsiString);
destructor destroy; override;
procedure onAddAttribute(attribute: JavaAttribute); override;
function getAttributeClass(const name: AnsiString): JavaAttribute_Class; override;
function getCodeSize(): int;
function getParametersCount(): int;
function getVirtualIndex(): int;
function getOverridden(): JavaMethod;
function getLineNumberTable(): JavaLineNumberTable;
function isSynchronized(): boolean;
function isStrictfp(): boolean;
function isAbstract(): boolean;
function isVirtual(): boolean;
function isNative(): boolean;
strict private const
VIRTUAL_STATUS_NOT_DEFINED = int(0);
VIRTUAL_STATUS_HAS_VIRTUAL = int(1);
VIRTUAL_STATUS_NOT_VIRTUAL = int(2);
end;
JavaClass = class(JavaClassMember, ConstantPoolContainer)
strict private
owner: JavaStaticRecompiler;
packageName: AnsiString;
outputName: AnsiString;
ancestorName: AnsiString;
ancestor: JavaClass;
next: JavaClass;
constantPoolLength: int;
constantPool: ConstantPoolEntry_Array1d;
interfacesCount: int;
interfaces: InterfaceImplementsInfo_Array1d;
fieldsCount: int;
fields: JavaField_Array1d;
methodsCount: int;
methods: JavaMethod_Array1d;
sourceFile: JavaConstantValue;
instanceSize: int;
virtualsCount: int;
nameIndex: int;
procedure addMethod(method: JavaMethod);
procedure addInterface(intf: JavaClass);
function findVirtualMethod(virtualIndex: int): JavaMethod;
function getRefFieldsOffsets(): int_Array1d;
private
procedure findAncestors();
procedure defineImplementedMethods();
procedure defineVirtualMethods();
procedure defineFieldOffsets();
procedure writeIMTs(stream: DataOutput);
procedure writeData(stream: DataOutput);
procedure setMembers(const fields: JavaField_Array1d; const methods: JavaMethod_Array1d);
procedure setNameIndex(nameIndex: int);
procedure setNextClass(next: JavaClass);
procedure setIMTOffset(interfaceIndex, imtOffset: int);
function getIMTOffset(interfaceIndex: int): int;
function findMember(const name, signature: AnsiString): JavaClassMember;
function findMemberInternal(const name, signature: AnsiString): JavaClassMember;
public
constructor create(owner: JavaStaticRecompiler; const constantPool: ConstantPoolEntry_Array1d; flags: int; const name, ancestor: AnsiString; const interfaces: AnsiString_Array1d); overload;
constructor create(owner: JavaStaticRecompiler; nameIndex: int); overload;
destructor destroy; override;
procedure onAddAttribute(attribute: JavaAttribute); override;
function getAttributeClass(const name: AnsiString): JavaAttribute_Class; override;
function getCompiler(): JavaStaticRecompiler; override;
function getComponentClass(): JavaClass; virtual;
function getInstanceSize(): int; virtual;
function getLongIndex(value: long): int;
function getDoubleIndex(value: double): int;
function getStringIndex(const value: AnsiString): int;
function getConstantPoolLength(): int;
function getConstantPoolEntry(index: int): ConstantPoolEntry;
function getConstantPoolMember(index, memberType: int): JavaClassMember; overload;
function getConstantPoolMember(classNameIndex, memberNameIndex, memberSignatureIndex, memberType: int): JavaClassMember; overload;
function getPackageName(): AnsiString;
function getOutputName(): AnsiString;
function getAncestor(): JavaClass;
function getInterfacesCount(): int;
function getInterfaceImplements(index: int): InterfaceImplementsInfo;
function getInterface(index: int): JavaClass;
function getAbstractMethodsCount(): int;
function getMethodsCount(): int;
function getMethod(index: int): JavaMethod;
function getFieldsCount(): int;
function getField(index: int): JavaField;
function getSourceFile(): AnsiString;
function getDataSize(): int;
function isDirectSuperClass(ancestor: JavaClass): boolean;
function isInheritedFrom(cls: JavaClass): boolean;
function isPrimitive(): boolean;
function isInterface(): boolean;
function isAbstract(): boolean;
private
class procedure writeClassReference(stream: DataOutput; cls: JavaClass);
class function getClassSignature(const name: AnsiString): AnsiString;
end;
JavaArray = class(JavaClass)
strict private
componentClass: JavaClass;
cellClass: JavaClass;
dimensionsCount: int;
public
constructor create(owner: JavaStaticRecompiler; componentClass: JavaClass);
function getComponentClass(): JavaClass; override;
function getInstanceSize(): int; override;
function getCellClass(): JavaClass;
function getDimensionsCount(): int;
end;
JavaStaticRecompiler = class(RefCountInterfacedObject, StaticRecompiler, AdjustableRecompiler, ConstantPoolContainer)
strict private
coreDirectory: AnsiString;
platformName: AnsiString;
primitives: JavaClass_Array1d;
fdconst: ConstantPoolEntry_Array1d;
strict private
classesCount: int;
classes: JavaClass_Array1d;
arraysCount: int;
arrays: JavaArray_Array1d;
entryCommands: long_Array1d;
initOrder: StringPool;
strings: StringPool;
strict private
imageBeginOffset: int;
methodsOffset: int;
entryOffset: int;
stringsOffset: int;
imageEndOffset: int;
availableMemoryInMB: int;
strict private
outStrings: boolean;
alignment: boolean;
compressionLevel: int;
stackSizeInMB: int;
heapSize: int;
descSize: int;
executableFileName: AnsiString;
strict private
procedure init();
procedure loadClassesFrom(archive: ZIPArchiveReader);
procedure loadClass(source: Input);
procedure addArray(arr: JavaArray);
procedure findAncestors();
procedure findSystemMembers();
procedure sortClasses();
procedure preferenceForClassMembers();
procedure prepareMethods();
procedure prepareEntry();
procedure linkClasses();
procedure extractStrings();
procedure assignOffsets();
procedure reduceCodeSize();
procedure computeAvailableMemory();
procedure createExecutableFile(const fileName: AnsiString);
procedure createTextDebugInfoFile(const fileName: AnsiString);
procedure createBinDebugInfoFile(const fileName: AnsiString);
procedure createStringPoolFile(const fileName: AnsiString);
procedure buildMalikManifest(const outputDirectory: AnsiString; javaManifest, malikManifest: ProgrammeManifest);
procedure clear();
function isJarArchiveForEmulator(archive: ZIPArchiveReader): boolean;
function indexOfArray(const name: AnsiString): int;
function getArray(const name: AnsiString): JavaArray;
function findSystemMember(desriptor: _Object): JavaClassMember;
private
classObject: JavaClass;
classClass: JavaClass;
classInterfaceEntry: JavaClass;
classMalikSystem: JavaClass;
classMath: JavaClass;
interfaceInterrupt: JavaClass;
methodDefaultConstructor: JavaClassMember;
methodGetString: JavaClassMember;
methodCheckObjectArrayAssignable: JavaClassMember;
methodGetInterfaceMethodEntryPoint: JavaClassMember;
methodAllocateInstance: JavaClassMember;
methodArrayCreateOneDim: JavaClassMember;
methodArrayCreateMultiDim: JavaClassMember;
methodCast: JavaClassMember;
methodIsInstance: JavaClassMember;
methodMonitorEnter: JavaClassMember;
methodMonitorExit: JavaClassMember;
methodThrowAbstractMethodError: JavaClassMember;
methodMain: JavaClassMember;
procedure writeCode(stream: DataOutput; const commands: long_Array1d; commandsCount: int; offset: int; owner: ConstantPoolContainer);
function reduceSizeofJumps(const commands: long_Array1d; commandsCount: int): boolean;
function reduceSizeofCalls(const commands: long_Array1d; commandsCount: int; offset: int; owner: ConstantPoolContainer): boolean;
function getStringPoolStringIndex(const str: AnsiString): int;
function getClassesCount(): int;
function getClass(index: int): JavaClass; overload;
function getTypeSize(const signature: AnsiString): int; overload;
function getTypeSize(const signature: AnsiString; alignment: boolean): int; overload;
function findClassByName(const name: AnsiString): JavaClass;
function findClassBySignature(const signature: AnsiString): JavaClass;
public
constructor create(); overload;
constructor create(const coreDirectory, platformName: AnsiString); overload;
destructor destroy; override;
{ StaticRecompiler }
function createInstance(): StaticRecompiler;
function install(const archive, destinationDirectory: AnsiString): AnsiString;
function getPlatformName(): AnsiString;
function getArchiveTypeName(): AnsiString;
function getArchiveExtension(): AnsiString;
{ AdjustableRecompiler }
function getAlignment(): boolean;
function getCompressionLevel(): int;
function getStackSize(): int;
function getHeapSize(): int;
function getDescriptorsSize(): int;
function getOutputExecutableFileName(): AnsiString;
procedure setDefaults();
procedure setAlignment(alignment: boolean);
procedure setCompressionLevel(compressionLevel: int);
procedure setStackSize(sizeInMB: int);
procedure setHeapSize(sizeInKB: int);
procedure setDescriptorsSize(sizeInKB: int);
procedure setOutputExecutableFileName(const relativeFileName: AnsiString);
{ ConstantPoolContainer }
function getLongIndex(value: long): int;
function getDoubleIndex(value: double): int;
function getStringIndex(const value: AnsiString): int;
function getConstantPoolLength(): int;
function getConstantPoolEntry(index: int): ConstantPoolEntry;
function getConstantPoolMember(index, memberType: int): JavaClassMember; overload;
function getConstantPoolMember(classNameIndex, memberNameIndex, memberSignatureIndex, memberType: int): JavaClassMember; overload;
strict private
procedure writeToTextDebugInfoFile(stream: DataOutput; cls: JavaClass);
end;
{%endregion}
implementation
{%region private }
const
ENTRY_UTF8 = 1;
ENTRY_INTEGER = 3;
ENTRY_FLOAT = 4;
ENTRY_LONG = 5;
ENTRY_DOUBLE = 6;
ENTRY_CLASS = 7;
ENTRY_STRING = 8;
ENTRY_FIELD_REF = 9;
ENTRY_CLASS_METHOD_REF = 10;
ENTRY_INTERFACE_METHOD_REF = 11;
ENTRY_NAME_AND_SIGNATURE = 12;
const
ACCESS_PRIVATE = int(0);
ACCESS_PACKAGED = int(1);
ACCESS_PROTECTED = int(2);
ACCESS_PUBLIC = int(3);
const
FLAG_PUBLIC = int($0001);
FLAG_PRIVATE = int($0002);
FLAG_PROTECTED = int($0004);
FLAG_STATIC = int($0008);
FLAG_FINAL = int($0010);
FLAG_SYNCHRONIZED = int($0020);
{ FLAG_VOLATILE = int($0040); // не используется }
{ FLAG_TRANSIENT = int($0080); // не используется }
FLAG_NATIVE = int($0100);
FLAG_INTERFACE = int($0200);
FLAG_ABSTRACT = int($0400);
FLAG_STRICTFP = int($0800);
FLAG_PRIMITIVE = int($00010000);
const
PREFIX_VOID = 'V';
PREFIX_BOOLEAN = 'Z';
PREFIX_CHAR = 'C';
PREFIX_FLOAT = 'F';
PREFIX_DOUBLE = 'D';
PREFIX_BYTE = 'B';
PREFIX_SHORT = 'S';
PREFIX_INT = 'I';
PREFIX_LONG = 'J';
PREFIX_ARRAY = '[';
PREFIX_OBJECT = 'L';
SUFFIX_OBJECT = ';';
HEADER_PREFIX = '(';
HEADER_SUFFIX = ')';
const
SEPARATOR_PACKAGES = '/';
SEPARATOR_CANONICAL = '.';
const
MEMBER_TYPE_STATIC_FIELD = int(0);
MEMBER_TYPE_INSTANCE_FIELD = int(1);
MEMBER_TYPE_STATIC_METHOD = int(2);
MEMBER_TYPE_INSTANCE_METHOD = int(3);
MEMBER_TYPE_INTERFACE_METHOD = int(4);
const
IMT_ENTRY_SIZE = int($10);
const
CLASS_FILE_EXTENSION = '.class';
MANIFEST_DIRECTORY = 'META-INF';
MANIFEST_FILE_NAME = MANIFEST_DIRECTORY + '/MANIFEST.MF';
MANIFEST_FILE_PLATFORM_NAME = MANIFEST_DIRECTORY + DIRECTORY_SEPARATOR + 'MANIFEST.MF';
PACKAGE_CORE = 'java' + SEPARATOR_PACKAGES + 'lang' + SEPARATOR_PACKAGES;
PACKAGE_MAIN = 'malik' + SEPARATOR_PACKAGES + 'emulator' + SEPARATOR_PACKAGES + 'application' + SEPARATOR_PACKAGES;
CLASS_OBJECT = PACKAGE_CORE + 'Object';
CLASS_CLASS = PACKAGE_CORE + 'Class';
CLASS_INTERFACE_ENTRY = PACKAGE_CORE + 'InterfaceEntry';
CLASS_MALIK_SYSTEM = PACKAGE_CORE + 'MalikSystem';
CLASS_MATH = PACKAGE_CORE + 'Math';
CLASS_MEMORY = PACKAGE_CORE + 'Memory';
CLASS_ARRAY = PACKAGE_CORE + 'Array';
CLASS_STRING = PACKAGE_CORE + 'String';
CLASS_STRING_POOL = PACKAGE_CORE + 'StringPool';
CLASS_SYSTEM = PACKAGE_CORE + 'System';
CLASS_RUNTIME = PACKAGE_CORE + 'Runtime';
CLASS_THREAD = PACKAGE_CORE + 'Thread';
CLASS_THROWABLE = PACKAGE_CORE + 'Throwable';
INTERFACE_INTERRUPT = PACKAGE_CORE + 'Interrupt';
CLASS_RUN = PACKAGE_MAIN + 'Run';
const
PROGRAMME_ENTRY = 'programme entry';
UNKNOWN_SOURCE = 'Unknown Source';
NAME_INITIALIZATION = '<clinit>';
NAME_CONSTRUCTOR = '<init>';
NAME_FINALIZE = '$finalize$';
NAME_INTERRUPT = 'interrupt';
NAME_CURRENT_THREAD = 'currentThread';
SIGNATURE_NO_PARAMETERS = HEADER_PREFIX + HEADER_SUFFIX + PREFIX_VOID;
type
ClassMemberDescriptor = class;
ClassMemberDescriptor_Array1d = packed array of ClassMemberDescriptor;
ClassMemberDescriptor = class(_Object)
strict private
className: AnsiString;
memberName: AnsiString;
signature: AnsiString;
public
constructor create(const className, memberName, signature: AnsiString);
function getClassName(): AnsiString;
function getMemberName(): AnsiString;
function getSignature(): AnsiString;
function equals(member: JavaClassMember): boolean; overload;
end;
var
PRIMITIVES_NAMES: AnsiString_Array1d;
PRIMITIVES_PREFIXES: AnsiString_Array1d;
MEMBER_TYPES: AnsiString_Array1d;
MEMBER_DEFAULT_CONSTRUCTOR: ClassMemberDescriptor;
MEMBER_STRING_POOL_OFFSET: ClassMemberDescriptor;
MEMBER_DESCRIPTORS_SIZE: ClassMemberDescriptor;
MEMBER_HEAP_LIMIT: ClassMemberDescriptor;
MEMBER_MONITOR_ENTER: ClassMemberDescriptor;
MEMBER_MONITOR_EXIT: ClassMemberDescriptor;
MEMBER_CHECK_OBJECT_ARRAY_ASSIGNABLE: ClassMemberDescriptor;
MEMBER_GET_INTERFACE_METHOD_ENTRY_POINT: ClassMemberDescriptor;
MEMBER_ALLOCATE_INSTANCE: ClassMemberDescriptor;
MEMBER_IS_INSTANCE: ClassMemberDescriptor;
MEMBER_CAST: ClassMemberDescriptor;
MEMBER_GET_STRING: ClassMemberDescriptor;
MEMBER_ARRAY_CREATE_ONE_DIM: ClassMemberDescriptor;
MEMBER_ARRAY_CREATE_MULTI_DIM: ClassMemberDescriptor;
MEMBER_THROW_ABSTRACT: ClassMemberDescriptor;
MEMBER_MAIN_PROCEDURE: ClassMemberDescriptor;
NATIVE_METHODS: ClassMemberDescriptor_Array1d;
{%endregion}
{%region routine }
function ConstantPoolEntry_Array1d_create(length: int): ConstantPoolEntry_Array1d;
begin
setLength(result, length);
end;
function toConstantPoolEntryArray1d(const arr: array of ConstantPoolEntry): ConstantPoolEntry_Array1d;
begin
setLength(result, length(arr));
move(arr[0], result[0], length(result) * sizeof(_Object));
end;
procedure arraycopy(const src: ConstantPoolEntry_Array1d; srcOffset: int; const dst: ConstantPoolEntry_Array1d; dstOffset: int; length: int); overload;
var
lim: int;
len: int;
begin
lim := srcOffset + length;
len := System.length(src);
if (lim > len) or (lim < srcOffset) or (srcOffset < 0) or (srcOffset > len) then begin
raise ArrayIndexOutOfBoundsException.create('arraycopy: индекс элемента массива выходит из диапазона.');
end;
lim := dstOffset + length;
len := System.length(dst);
if (lim > len) or (lim < dstOffset) or (dstOffset < 0) or (dstOffset > len) then begin
raise ArrayIndexOutOfBoundsException.create('arraycopy: индекс элемента массива выходит из диапазона.');
end;
move(src[srcOffset], dst[dstOffset], length * sizeof(_Object));
end;
function ExceptionCatch_Array1d_create(length: int): ExceptionCatch_Array1d;
begin
setLength(result, length);
end;
function toExceptionCatchArray1d(const arr: array of ExceptionCatch): ExceptionCatch_Array1d;
begin
setLength(result, length(arr));
move(arr[0], result[0], length(result) * sizeof(_Object));
end;
procedure arraycopy(const src: ExceptionCatch_Array1d; srcOffset: int; const dst: ExceptionCatch_Array1d; dstOffset: int; length: int); overload;
var
lim: int;
len: int;
begin
lim := srcOffset + length;
len := System.length(src);
if (lim > len) or (lim < srcOffset) or (srcOffset < 0) or (srcOffset > len) then begin
raise ArrayIndexOutOfBoundsException.create('arraycopy: индекс элемента массива выходит из диапазона.');
end;
lim := dstOffset + length;
len := System.length(dst);
if (lim > len) or (lim < dstOffset) or (dstOffset < 0) or (dstOffset > len) then begin
raise ArrayIndexOutOfBoundsException.create('arraycopy: индекс элемента массива выходит из диапазона.');
end;
move(src[srcOffset], dst[dstOffset], length * sizeof(_Object));
end;
function ExceptionHandler_Array1d_create(length: int): ExceptionHandler_Array1d;
begin
setLength(result, length);
end;
function toExceptionHandlerArray1d(const arr: array of ExceptionHandler): ExceptionHandler_Array1d;
begin
setLength(result, length(arr));
move(arr[0], result[0], length(result) * sizeof(_Object));
end;
procedure arraycopy(const src: ExceptionHandler_Array1d; srcOffset: int; const dst: ExceptionHandler_Array1d; dstOffset: int; length: int); overload;
var
lim: int;
len: int;
begin
lim := srcOffset + length;
len := System.length(src);
if (lim > len) or (lim < srcOffset) or (srcOffset < 0) or (srcOffset > len) then begin
raise ArrayIndexOutOfBoundsException.create('arraycopy: индекс элемента массива выходит из диапазона.');
end;
lim := dstOffset + length;
len := System.length(dst);
if (lim > len) or (lim < dstOffset) or (dstOffset < 0) or (dstOffset > len) then begin
raise ArrayIndexOutOfBoundsException.create('arraycopy: индекс элемента массива выходит из диапазона.');
end;
move(src[srcOffset], dst[dstOffset], length * sizeof(_Object));
end;
function InterfaceMethodImplements_Array1d_create(length: int): InterfaceMethodImplements_Array1d;
begin
setLength(result, length);
end;
function toInterfaceMethodImplementsArray1d(const arr: array of InterfaceMethodImplements): InterfaceMethodImplements_Array1d;
begin
setLength(result, length(arr));
move(arr[0], result[0], length(result) * sizeof(_Object));
end;
procedure arraycopy(const src: InterfaceMethodImplements_Array1d; srcOffset: int; const dst: InterfaceMethodImplements_Array1d; dstOffset: int; length: int); overload;
var
lim: int;
len: int;
begin
lim := srcOffset + length;
len := System.length(src);
if (lim > len) or (lim < srcOffset) or (srcOffset < 0) or (srcOffset > len) then begin
raise ArrayIndexOutOfBoundsException.create('arraycopy: индекс элемента массива выходит из диапазона.');
end;
lim := dstOffset + length;
len := System.length(dst);
if (lim > len) or (lim < dstOffset) or (dstOffset < 0) or (dstOffset > len) then begin
raise ArrayIndexOutOfBoundsException.create('arraycopy: индекс элемента массива выходит из диапазона.');
end;
move(src[srcOffset], dst[dstOffset], length * sizeof(_Object));
end;
function InterfaceImplementsInfo_Array1d_create(length: int): InterfaceImplementsInfo_Array1d;
begin
setLength(result, length);
end;
function toInterfaceImplementsInfoArray1d(const arr: array of InterfaceImplementsInfo): InterfaceImplementsInfo_Array1d;
begin
setLength(result, length(arr));
move(arr[0], result[0], length(result) * sizeof(_Object));
end;
procedure arraycopy(const src: InterfaceImplementsInfo_Array1d; srcOffset: int; const dst: InterfaceImplementsInfo_Array1d; dstOffset: int; length: int); overload;
var
lim: int;
len: int;
begin
lim := srcOffset + length;
len := System.length(src);
if (lim > len) or (lim < srcOffset) or (srcOffset < 0) or (srcOffset > len) then begin
raise ArrayIndexOutOfBoundsException.create('arraycopy: индекс элемента массива выходит из диапазона.');
end;
lim := dstOffset + length;
len := System.length(dst);
if (lim > len) or (lim < dstOffset) or (dstOffset < 0) or (dstOffset > len) then begin
raise ArrayIndexOutOfBoundsException.create('arraycopy: индекс элемента массива выходит из диапазона.');
end;
move(src[srcOffset], dst[dstOffset], length * sizeof(_Object));
end;
function JavaField_Array1d_create(length: int): JavaField_Array1d;
begin
setLength(result, length);
end;
function toJavaFieldArray1d(const arr: array of JavaField): JavaField_Array1d;
begin
setLength(result, length(arr));
move(arr[0], result[0], length(result) * sizeof(_Object));
end;
procedure arraycopy(const src: JavaField_Array1d; srcOffset: int; const dst: JavaField_Array1d; dstOffset: int; length: int); overload;
var
lim: int;
len: int;
begin
lim := srcOffset + length;
len := System.length(src);
if (lim > len) or (lim < srcOffset) or (srcOffset < 0) or (srcOffset > len) then begin
raise ArrayIndexOutOfBoundsException.create('arraycopy: индекс элемента массива выходит из диапазона.');
end;
lim := dstOffset + length;
len := System.length(dst);
if (lim > len) or (lim < dstOffset) or (dstOffset < 0) or (dstOffset > len) then begin
raise ArrayIndexOutOfBoundsException.create('arraycopy: индекс элемента массива выходит из диапазона.');
end;
move(src[srcOffset], dst[dstOffset], length * sizeof(_Object));
end;
function JavaMethod_Array1d_create(length: int): JavaMethod_Array1d;
begin
setLength(result, length);
end;
function toJavaMethodArray1d(const arr: array of JavaMethod): JavaMethod_Array1d;
begin
setLength(result, length(arr));
move(arr[0], result[0], length(result) * sizeof(_Object));
end;
procedure arraycopy(const src: JavaMethod_Array1d; srcOffset: int; const dst: JavaMethod_Array1d; dstOffset: int; length: int); overload;
var
lim: int;
len: int;
begin
lim := srcOffset + length;
len := System.length(src);
if (lim > len) or (lim < srcOffset) or (srcOffset < 0) or (srcOffset > len) then begin
raise ArrayIndexOutOfBoundsException.create('arraycopy: индекс элемента массива выходит из диапазона.');
end;
lim := dstOffset + length;
len := System.length(dst);
if (lim > len) or (lim < dstOffset) or (dstOffset < 0) or (dstOffset > len) then begin
raise ArrayIndexOutOfBoundsException.create('arraycopy: индекс элемента массива выходит из диапазона.');
end;
move(src[srcOffset], dst[dstOffset], length * sizeof(_Object));
end;
function JavaClass_Array1d_create(length: int): JavaClass_Array1d;
begin
setLength(result, length);
end;
function toJavaClassArray1d(const arr: array of JavaClass): JavaClass_Array1d;
begin
setLength(result, length(arr));
move(arr[0], result[0], length(result) * sizeof(_Object));
end;
procedure arraycopy(const src: JavaClass_Array1d; srcOffset: int; const dst: JavaClass_Array1d; dstOffset: int; length: int); overload;
var
lim: int;
len: int;
begin
lim := srcOffset + length;
len := System.length(src);
if (lim > len) or (lim < srcOffset) or (srcOffset < 0) or (srcOffset > len) then begin
raise ArrayIndexOutOfBoundsException.create('arraycopy: индекс элемента массива выходит из диапазона.');
end;
lim := dstOffset + length;
len := System.length(dst);
if (lim > len) or (lim < dstOffset) or (dstOffset < 0) or (dstOffset > len) then begin
raise ArrayIndexOutOfBoundsException.create('arraycopy: индекс элемента массива выходит из диапазона.');
end;
move(src[srcOffset], dst[dstOffset], length * sizeof(_Object));
end;
function JavaArray_Array1d_create(length: int): JavaArray_Array1d;
begin
setLength(result, length);
end;
function toJavaArrayArray1d(const arr: array of JavaArray): JavaArray_Array1d;
begin
setLength(result, length(arr));
move(arr[0], result[0], length(result) * sizeof(_Object));
end;
procedure arraycopy(const src: JavaArray_Array1d; srcOffset: int; const dst: JavaArray_Array1d; dstOffset: int; length: int); overload;
var
lim: int;
len: int;
begin
lim := srcOffset + length;
len := System.length(src);
if (lim > len) or (lim < srcOffset) or (srcOffset < 0) or (srcOffset > len) then begin
raise ArrayIndexOutOfBoundsException.create('arraycopy: индекс элемента массива выходит из диапазона.');
end;
lim := dstOffset + length;
len := System.length(dst);
if (lim > len) or (lim < dstOffset) or (dstOffset < 0) or (dstOffset > len) then begin
raise ArrayIndexOutOfBoundsException.create('arraycopy: индекс элемента массива выходит из диапазона.');
end;
move(src[srcOffset], dst[dstOffset], length * sizeof(_Object));
end;
function ClassMemberDescriptor_Array1d_create(length: int): ClassMemberDescriptor_Array1d;
begin
setLength(result, length);
end;
function toClassMemberDescriptorArray1d(const arr: array of ClassMemberDescriptor): ClassMemberDescriptor_Array1d;
begin
setLength(result, length(arr));
move(arr[0], result[0], length(result) * sizeof(_Object));
end;
procedure freeClassMemberDescriptors(const descriptors: ClassMemberDescriptor_Array1d);
var
i: int;
begin
for i := length(descriptors) - 1 downto 0 do begin
descriptors[i].free();
end;
end;
function computeParametersCount(staticMethod: boolean; const signature: AnsiString): int;
var
i: int;
len: int;
begin
if staticMethod then begin
result := 0;
end else begin
result := 1;
end;
len := length(signature);
if (len > 0) and (signature[1] = HEADER_PREFIX) then begin
i := 2;
while i <= len do begin
case signature[i] of
HEADER_SUFFIX: begin
break;
end;
PREFIX_BOOLEAN, PREFIX_CHAR, PREFIX_FLOAT, PREFIX_DOUBLE, PREFIX_BYTE, PREFIX_SHORT, PREFIX_INT, PREFIX_LONG: begin
inc(result);
end;
PREFIX_OBJECT: begin
repeat
inc(i);
until (i >= len) or (signature[i] = SUFFIX_OBJECT);
inc(result);
end;
PREFIX_ARRAY: begin
repeat
inc(i);
until (i >= len) or (signature[i] <> PREFIX_ARRAY);
if i > len then begin
break;
end;
if signature[i] = PREFIX_OBJECT then begin
repeat
inc(i);
until (i >= len) or (signature[i] = SUFFIX_OBJECT);
end;
inc(result);
end;
end;
inc(i);
end;
end;
end;
function computeCodeSize(const commands: long_Array1d; offset, count: int): int;
var
i: int;
f: boolean;
begin
f := false;
if count < 0 then begin
inc(offset, count);
count := -count;
f := true;
end;
result := 0;
for i := offset to offset + count - 1 do begin
inc(result, (int(commands[i]) shr 12) and $0f);
end;
if f then begin
result := -result;
end;
end;
function localOffsetToString(offset: int): AnsiString;
begin
if offset >= 0 then begin
result := '+' + toHexString(offset, 1);
end else begin
result := '-' + toHexString(-offset, 1);
end;
end;
function globalOffsetToString(offset: int): AnsiString;
begin
result := toHexString(offset, 8);
end;
{%endregion}
{%region ClassNotFoundException }
constructor ClassNotFoundException.create();
begin
inherited create();
end;
constructor ClassNotFoundException.create(const message: AnsiString);
begin
inherited create(message);
end;
{%endregion}
{%region ClassMemberNotFoundException }
constructor ClassMemberNotFoundException.create();
begin
inherited create();
end;
constructor ClassMemberNotFoundException.create(const message: AnsiString);
begin
inherited create(message);
end;
{%endregion}
{%region NativeMethodNotFoundException }
constructor NativeMethodNotFoundException.create();
begin
inherited create();
end;
constructor NativeMethodNotFoundException.create(const message: AnsiString);
begin
inherited create(message);
end;
{%endregion}
{%region ClassFileInvalidFormatException }
constructor ClassFileInvalidFormatException.create();
begin
inherited create();
end;
constructor ClassFileInvalidFormatException.create(const message: AnsiString);
begin
inherited create(message);
end;
{%endregion}
{%region UnsupportedClassVersionException }
constructor UnsupportedClassVersionException.create();
begin
inherited create();
end;
constructor UnsupportedClassVersionException.create(const message: AnsiString);
begin
inherited create(message);
end;
{%endregion}
{%region UnsupportedBytecodeException }
constructor UnsupportedBytecodeException.create();
begin
inherited create();
end;
constructor UnsupportedBytecodeException.create(const message: AnsiString);
begin
inherited create(message);
end;
{%endregion}
{%region ManifestNotFoundException }
constructor ManifestNotFoundException.create();
begin
inherited create();
end;
constructor ManifestNotFoundException.create(const message: AnsiString);
begin
inherited create(message);
end;
{%endregion}
{%region ManifestPropertyNotFoundException }
constructor ManifestPropertyNotFoundException.create();
begin
inherited create();
end;
constructor ManifestPropertyNotFoundException.create(const message: AnsiString);
begin
inherited create(message);
end;
{%endregion}
{%region ConstantPoolEntry }
constructor ConstantPoolEntry.create();
begin
inherited create();
end;
{%endregion}
{%region StringEntry }
constructor StringEntry.create(const value: AnsiString);
begin
inherited create();
self.value := value;
end;
function StringEntry.stringValue(): AnsiString;
begin
result := value;
end;
{%endregion}
{%region IntegerEntry }
constructor IntegerEntry.create(value: int);
begin
inherited create();
self.value := value;
end;
function IntegerEntry.intValue(): int;
begin
result := value;
end;
{%endregion}
{%region LongEntry }
constructor LongEntry.create(value: long);
begin
inherited create();
self.value := value;
end;
function LongEntry.longValue(): long;
begin
result := value;
end;
{%endregion}
{%region FloatEntry }
constructor FloatEntry.create(value: float);
begin
inherited create();
self.value := value;
end;
function FloatEntry.floatValue(): float;
begin
result := value;
end;
{%endregion}
{%region DoubleEntry }
constructor DoubleEntry.create(value: double);
begin
inherited create();
self.value := value;
end;
function DoubleEntry.doubleValue(): double;
begin
result := value;
end;
{%endregion}
{%region SingleIndexedEntry }
constructor SingleIndexedEntry.create(entryType, index1: int);
begin
inherited create();
self.entryType := entryType;
self.index1 := index1;
end;
function SingleIndexedEntry.getEntryType(): int;
begin
result := entryType;
end;
function SingleIndexedEntry.getIndex1(): int;
begin
result := index1;
end;
{%endregion}
{%region DoubleIndexedEntry }
constructor DoubleIndexedEntry.create(entryType, index1, index2: int);
begin
inherited create(entryType, index1);
self.index2 := index2;
end;
function DoubleIndexedEntry.getIndex2(): int;
begin
result := index2;
end;
{%endregion}
{%region ExceptionCatch }
constructor ExceptionCatch.create(catchOffset, classIndex: int);
begin
inherited create();
self.catchOffset := catchOffset;
self.classIndex := classIndex;
end;
function ExceptionCatch.getCommandIndex(): int;
begin
result := commandIndex;
end;
procedure ExceptionCatch.setCommandIndex(commandIndex: int);
begin
self.commandIndex := commandIndex;
end;
function ExceptionCatch.getCatchOffset(): int;
begin
result := catchOffset;
end;
function ExceptionCatch.getClassIndex(): int;
begin
result := classIndex;
end;
{%endregion}
{%region ExceptionHandler }
constructor ExceptionHandler.create(tryStart, tryFinish: int);
begin
inherited create();
self.tryStart := tryStart;
self.tryFinish := tryFinish;
end;
destructor ExceptionHandler.destroy;
var
c: ExceptionCatch_Array1d;
i: int;
begin
c := catches;
for i := catchesLength - 1 downto 0 do begin
c[i].free();
end;
inherited destroy;
end;
function ExceptionHandler.getTryStart(): int;
begin
result := tryStart;
end;
function ExceptionHandler.getTryFinish(): int;
begin
result := tryFinish;
end;
function ExceptionHandler.getCatchesLength(): int;
begin
result := catchesLength;
end;
function ExceptionHandler.getCatch(index: int): ExceptionCatch;
begin
if (index < 0) or (index >= catchesLength) then begin
raise ArrayIndexOutOfBoundsException.create(index);
end;
result := catches[index];
end;
procedure ExceptionHandler.addCatch(catchOffset, classIndex: int);
var
c: ExceptionCatch_Array1d;
i: int;
begin
c := catches;
i := catchesLength;
if i = length(c) then begin
c := ExceptionCatch_Array1d_create(i * 2 + 1);
arraycopy(catches, 0, c, 0, i);
catches := c;
end;
c[i] := ExceptionCatch.create(catchOffset, classIndex);
catchesLength := i + 1;
end;
{%endregion}
{%region InterfaceMethodImplements }
constructor InterfaceMethodImplements.create(interfaceMethod: JavaMethod);
begin
inherited create();
self.interfaceMethod := interfaceMethod;
self.classMethod := nil;
end;
procedure InterfaceMethodImplements.setClassMethod(classMethod: JavaMethod);
begin
self.classMethod := classMethod;
end;
function InterfaceMethodImplements.getMethodName(): AnsiString;
begin
result := interfaceMethod.getName();
end;
function InterfaceMethodImplements.getMethodSignature(): AnsiString;
begin
result := interfaceMethod.getSignature();
end;
function InterfaceMethodImplements.getInterfaceMethod(): JavaMethod;
begin
result := interfaceMethod;
end;
function InterfaceMethodImplements.getClassMethod(): JavaMethod;
begin
result := classMethod;
end;
{%endregion}
{%region InterfaceImplementsInfo }
constructor InterfaceImplementsInfo.create(const interfaceName: AnsiString);
begin
inherited create();
self.name := interfaceName;
end;
constructor InterfaceImplementsInfo.create(intf: JavaClass);
begin
inherited create();
self.name := intf.getName();
setInterface(intf);
end;
destructor InterfaceImplementsInfo.destroy;
var
i: int;
a: InterfaceMethodImplements_Array1d;
begin
a := methods;
for i := length(a) - 1 downto 0 do begin
a[i].free();
a[i] := nil;
end;
inherited destroy;
end;
procedure InterfaceImplementsInfo.setInterface(intf: JavaClass);
var
a: InterfaceMethodImplements_Array1d;
c: int;
i: int;
j: int;
m: JavaMethod;
begin
self.intf := intf;
a := InterfaceMethodImplements_Array1d_create(intf.getAbstractMethodsCount());
c := intf.getMethodsCount();
j := 0;
for i := 0 to c - 1 do begin
m := intf.getMethod(i);
if m.isAbstract() then begin
a[j] := InterfaceMethodImplements.create(m);
inc(j);
end;
end;
methods := a;
end;
procedure InterfaceImplementsInfo.setIMTOffset(imtOffset: int);
begin
self.imtOffset := imtOffset;
end;
function InterfaceImplementsInfo.getInterfaceName(): AnsiString;
begin
result := name;
end;
function InterfaceImplementsInfo.getInterface(): JavaClass;
begin
result := intf;
end;
function InterfaceImplementsInfo.getIMTOffset(): int;
begin
result := imtOffset;
end;
function InterfaceImplementsInfo.getMethodsCount(): int;
begin
result := length(methods);
end;
function InterfaceImplementsInfo.getMethodImplements(index: int): InterfaceMethodImplements;
var
a: InterfaceMethodImplements_Array1d;
begin
a := methods;
if (index < 0) or (index >= length(a)) then begin
raise ArrayIndexOutOfBoundsException.create(index);
end;
result := a[index];
end;
{%endregion}
{%region JavaAttribute }
class procedure JavaAttribute.readAttributes(container: AttributeContainer; stream: DataInput; const constantPool: ConstantPoolEntry_Array1d);
var
i: int;
j: int;
name: AnsiString;
content: byte_Array1d;
attributeClass: JavaAttribute_Class;
begin
for i := stream.readUnsignedShort() downto 1 do begin
j := stream.readUnsignedShort();
if (j >= length(constantPool)) or (not (constantPool[j] is StringEntry)) then begin
raise ClassFileInvalidFormatException.create('Неправильный формат class-файла: нельзя определить имя атрибута.');
end;
name := StringEntry(constantPool[j]).stringValue();
j := stream.readInt();
attributeClass := container.getAttributeClass(name);
if attributeClass = nil then begin
stream.skipBytes(j);
continue;
end;
content := byte_Array1d_create(j);
stream.readFully(content);
container.onAddAttribute(attributeClass.create(container, name, content, constantPool));
end;
end;
constructor JavaAttribute.create(owner: AttributeContainer; const name: AnsiString; const content: byte_Array1d; const constantPool: ConstantPoolEntry_Array1d);
begin
inherited create();
self.owner := owner;
self.content := content;
self.name := name;
end;
function JavaAttribute.byteAt(offset: int): int;
var
c: byte_Array1d;
begin
c := content;
if (offset < 0) or (offset >= length(c)) then begin
raise ArrayIndexOutOfBoundsException.create(offset);
end;
result := c[offset];
end;
function JavaAttribute.shortAt(offset: int): int;
var
c: byte_Array1d;
b1: int;
b2: int;
begin
c := content;
if (offset < 0) or (offset >= length(c) - 1) then begin
raise ArrayIndexOutOfBoundsException.create(offset);
end;
b1 := c[offset];
b2 := c[offset + 1] and $ff;
result := (b1 shl 8) or b2;
end;
function JavaAttribute.intAt(offset: int): int;
var
c: byte_Array1d;
b1: int;
b2: int;
b3: int;
b4: int;
begin
c := content;
if (offset < 0) or (offset >= length(c) - 3) then begin
raise ArrayIndexOutOfBoundsException.create(offset);
end;
b1 := c[offset];
b2 := c[offset + 1] and $ff;
b3 := c[offset + 2] and $ff;
b4 := c[offset + 3] and $ff;
result := (b1 shl 24) or (b2 shl 16) or (b3 shl 8) or b4;
end;
function JavaAttribute.unsignedByteAt(offset: int): int;
var
c: byte_Array1d;
begin
c := content;
if (offset < 0) or (offset >= length(c)) then begin
raise ArrayIndexOutOfBoundsException.create(offset);
end;
result := c[offset] and $ff;
end;
function JavaAttribute.unsignedShortAt(offset: int): int;
var
c: byte_Array1d;
b1: int;
b2: int;
begin
c := content;
if (offset < 0) or (offset >= length(c) - 1) then begin
raise ArrayIndexOutOfBoundsException.create(offset);
end;
b1 := c[offset] and $ff;
b2 := c[offset + 1] and $ff;
result := (b1 shl 8) or b2;
end;
function JavaAttribute.getOwner(): AttributeContainer;
begin
result := owner;
end;
function JavaAttribute.getSize(): int;
begin
result := length(content);
end;
function JavaAttribute.getName(): AnsiString;
begin
result := name;
end;
{%endregion}
{%region JavaConstantValue }
constructor JavaConstantValue.create(owner: AttributeContainer; const name: AnsiString; const content: byte_Array1d; const constantPool: ConstantPoolEntry_Array1d);
begin
inherited create(owner, name, content, constantPool);
case int(length(content)) of
1: begin
constantPoolIndex := unsignedByteAt(0);
end;
2..MAX_INT: begin
constantPoolIndex := unsignedShortAt(0);
end;
else
constantPoolIndex := 0;
end;
end;
function JavaConstantValue.getConstantPoolIndex(): int;
begin
result := constantPoolIndex;
end;
{%endregion}
{%region JavaLineNumberTable }
constructor JavaLineNumberTable.create(owner: AttributeContainer; const name: AnsiString; const content: byte_Array1d; const constantPool: ConstantPoolEntry_Array1d);
begin
inherited create(owner, name, content, constantPool);
linesCount := (length(content) - 2) div 4;
end;
function JavaLineNumberTable.getLinesCount(): int;
begin
result := linesCount;
end;
function JavaLineNumberTable.getLineNumber(lineIndex: int): int;
begin
if (lineIndex < 0) or (lineIndex >= linesCount) then begin
raise IndexOutOfBoundsException.create(lineIndex);
end;
result := unsignedShortAt(lineIndex * 4 + 4);
end;
function JavaLineNumberTable.getCodeOffsetAt(lineIndex: int): int;
begin
if (lineIndex < 0) or (lineIndex >= linesCount) then begin
raise IndexOutOfBoundsException.create(lineIndex);
end;
result := unsignedShortAt(lineIndex * 4 + 2);
end;
{%endregion}
{%region JavaCode }
class function JavaCode.extractCode(const content: byte_Array1d): byte_Array1d;
var
len: int;
b1: int;
b2: int;
b3: int;
b4: int;
begin
if length(content) < 8 then begin
result := nil;
exit;
end;
b1 := content[4];
b2 := content[5] and $ff;
b3 := content[6] and $ff;
b4 := content[7] and $ff;
len := (b1 shl 24) or (b2 shl 16) or (b3 shl 8) or b4;
if len < 0 then begin
result := nil;
exit;
end;
result := byte_Array1d_create(len);
arraycopy(content, 8, result, 0, len);
end;
constructor JavaCode.create(owner: AttributeContainer; const name: AnsiString; const content: byte_Array1d; const constantPool: ConstantPoolEntry_Array1d);
var
i: int;
tryStart: int;
tryFinish: int;
catchOffset: int;
classIndex: int;
stream: DataInput;
begin
inherited create(owner, name, extractCode(content), constantPool);
stream := DataInputStream.create(ByteArrayInputStream.create(content));
stream.skipBytes(2);
registersCount := stream.readUnsignedShort();
stream.skipBytes(stream.readInt());
for i := stream.readUnsignedShort() downto 1 do begin
tryStart := stream.readUnsignedShort();
tryFinish := stream.readUnsignedShort();
catchOffset := stream.readUnsignedShort();
classIndex := stream.readUnsignedShort();
addExceptionHandler(tryStart, tryFinish, catchOffset, classIndex);
end;
JavaAttribute.readAttributes(self, stream, constantPool);
sortHandlers();
fillInstructionOffsets();
fillTrueRegistersIndices();
end;
destructor JavaCode.destroy;
var
i: int;
e: ExceptionHandler_Array1d;
begin
e := exceptionHandlers;
for i := exceptionHandlersCount - 1 downto 0 do begin
e[i].free();
end;
lineNumberTable.free();
inherited destroy;
end;
procedure JavaCode.addExceptionHandler(tryStart, tryFinish, catchOffset, classIndex: int);
var
c: int;
i: int;
e: ExceptionHandler_Array1d;
h: ExceptionHandler;
begin
c := exceptionHandlersCount;
e := exceptionHandlers;
for i := c - 1 downto 0 do begin
h := e[i];
if (h.getTryStart() = tryStart) and (h.getTryFinish() = tryFinish) then begin
h.addCatch(catchOffset, classIndex);
exit;
end;
end;
if c = length(e) then begin
e := ExceptionHandler_Array1d_create(c * 2 + 1);
arraycopy(exceptionHandlers, 0, e, 0, c);
exceptionHandlers := e;
end;
h := ExceptionHandler.create(tryStart, tryFinish);
h.addCatch(catchOffset, classIndex);
e[c] := h;
exceptionHandlersCount := c + 1;
end;
procedure JavaCode.sortHandlers();
var
s1: int;
s2: int;
i: int;
j: int;
c: int;
e: ExceptionHandler_Array1d;
h1: ExceptionHandler;
h2: ExceptionHandler;
begin
c := exceptionHandlersCount;
e := exceptionHandlers;
for i := 0 to c - 2 do begin
h1 := e[i];
for j := i + 1 to c - 1 do begin
h2 := e[j];
s1 := h1.getTryStart();
s2 := h2.getTryStart();
if (s2 < s1) or (s2 = s1) and (h1.getTryFinish() < h2.getTryFinish()) then begin
e[j] := h1;
e[i] := h2;
h1 := h2;
end;
end;
end;
end;
procedure JavaCode.fillInstructionOffsets();
var
i1: int;
i2: int;
pc: int;
size: int;
count: int;
buffer: int_Array1d;
offsets: int_Array1d;
begin
pc := 0;
size := getSize();
count := 0;
offsets := int_Array1d_create(1);
while pc < size do begin
if count = length(offsets) then begin
buffer := int_Array1d_create(count * 2);
arraycopy(offsets, 0, buffer, 0, count);
offsets := buffer;
end;
offsets[count] := pc;
inc(count);
case unsignedByteAt(pc) of
$00..$0f, $1a..$35, $3b..$83, $85..$98, $ac..$b1, $be..$bf, $c2..$c3: begin
inc(pc);
end;
$10, $12, $15..$19, $36..$3a, $a9, $bc: begin
inc(pc, 2);
end;
$11, $13..$14, $84, $99..$a8, $b2..$b8, $bb, $bd, $c0..$c1, $c6..$c7: begin
inc(pc, 3);
end;
$c5: begin
inc(pc, 4);
end;
$b9, $c8..$c9: begin
inc(pc, 5);
end;
$c4: begin
inc(pc);
case unsignedByteAt(pc) of
$15..$19, $36..$3a, $a9: begin
inc(pc, 3);
end;
$84: begin
inc(pc, 5);
end;
end;
end;
$aa: begin
repeat
inc(pc);
until (pc and 3) = 0;
inc(pc, 4);
i1 := intAt(pc);
inc(pc, 4);
i2 := intAt(pc);
inc(pc, (i2 - i1 + 2) * 4);
end;
$ab: begin
repeat
inc(pc);
until (pc and 3) = 0;
inc(pc, 4);
i1 := intAt(pc);
inc(pc, (i1 * 8) + 4);
end;
else
inc(pc);
end;
end;
if count < length(offsets) then begin
instructionOffsets := int_Array1d_create(count);
arraycopy(offsets, 0, instructionOffsets, 0, count);
exit;
end;
instructionOffsets := offsets;
end;
procedure JavaCode.fillTrueRegistersIndices();
var
l: int;
i: int;
j: int;
k: int;
r: int;
a: int_Array1d;
m: JavaMethod;
s: AnsiString;
begin
r := registersCount;
a := int_Array1d_create(r);
m := getOwner().asObject() as JavaMethod;
s := m.getSignature();
l := length(s);
i := 0;
j := 0;
trueRegistersIndices := a;
if (l > 0) and (s[1] = HEADER_PREFIX) then begin
if not m.isStatic() then begin
if r > 0 then begin
a[0] := 0;
end;
i := 1;
j := 1;
end;
k := 2;
while (k <= l) and (i < r) do begin
case s[k] of
PREFIX_DOUBLE, PREFIX_LONG: begin
if i + 1 < r then begin
a[i] := j;
a[i + 1] := j;
inc(i, 2);
inc(j);
end;
end;
PREFIX_OBJECT: begin
repeat
inc(k);
until (k > l) or (s[k] = SUFFIX_OBJECT);
a[i] := j;
inc(i);
inc(j);
end;
PREFIX_ARRAY: begin
repeat
inc(k);
until (k > l) or (s[k] <> PREFIX_ARRAY);
if k > l then begin
break;
end;
if s[k] = PREFIX_OBJECT then begin
repeat
inc(k);
until (k > l) or (s[k] = SUFFIX_OBJECT);
end;
a[i] := j;
inc(i);
inc(j);
end;
HEADER_SUFFIX: begin
break;
end;
else
a[i] := j;
inc(i);
inc(j);
end;
inc(k);
end;
end;
while i < r do begin
case getRegisterSize(i) of
0: begin
inc(i);
end;
1: begin
a[i] := j;
inc(i);
inc(j);
end;
2: begin
if getRegisterSize(i + 1) > 0 then begin
a[i] := j;
inc(i);
inc(j);
end else begin
if i + 1 < r then begin
a[i] := j;
a[i + 1] := j;
inc(i, 2);
inc(j);
end;
end;
end;
end;
end;
if (l > 0) and (s[1] = HEADER_PREFIX) then begin
if not m.isStatic() then begin
i := 1;
end else begin
i := 0;
end;
k := 2;
while (k <= l) and (i < r) do begin
case s[k] of
PREFIX_DOUBLE, PREFIX_LONG: begin
inc(i);
if (getRegisterSize(i) > 0) and (i < r) then begin
a[i] := j;
inc(j);
end;
inc(i);
end;
PREFIX_OBJECT: begin
repeat
inc(k);
until (k > l) or (s[k] = SUFFIX_OBJECT);
inc(i);
end;
PREFIX_ARRAY: begin
repeat
inc(k);
until (k > l) or (s[k] <> PREFIX_ARRAY);
if k > l then begin
break;
end;
if s[k] = PREFIX_OBJECT then begin
repeat
inc(k);
until (k > l) or (s[k] = SUFFIX_OBJECT);
end;
inc(i);
end;
HEADER_SUFFIX: begin
break;
end;
else
inc(i);
end;
inc(k);
end;
end;
variablesCount := j;
end;
function JavaCode.getRegisterSize(registerIndex: int): int;
var
i: int;
pc: int;
opcode: int;
a: int_Array1d;
begin
a := instructionOffsets;
for i := 0 to length(a) - 1 do begin
pc := a[i];
opcode := unsignedByteAt(pc);
case opcode of
$15, $17, $19, $36, $38, $3a, $84, $a9: begin
if unsignedByteAt(pc + 1) = registerIndex then begin
result := 1;
exit;
end;
end;
$c4: begin
case unsignedByteAt(pc + 1) of
$15, $17, $19, $36, $38, $3a, $84, $a9: begin
if unsignedShortAt(pc + 2) = registerIndex then begin
result := 1;
exit;
end;
end;
end;
end;
else
if
(registerIndex >= 0) and (registerIndex < 4) and
(
(opcode - $1a = registerIndex) or (opcode - $22 = registerIndex) or (opcode - $2a = registerIndex) or
(opcode - $3b = registerIndex) or (opcode - $43 = registerIndex) or (opcode - $4b = registerIndex)
)
then begin
result := 1;
exit;
end;
end;
end;
for i := 0 to length(a) - 1 do begin
pc := a[i];
opcode := unsignedByteAt(pc);
case opcode of
$16, $18, $37, $39: begin
if unsignedByteAt(pc + 1) = registerIndex then begin
result := 2;
exit;
end;
end;
$c4: begin
case unsignedByteAt(pc + 1) of
$16, $18, $37, $39: begin
if unsignedShortAt(pc + 2) = registerIndex then begin
result := 2;
exit;
end;
end;
end;
end;
else
if
(registerIndex >= 0) and (registerIndex < 4) and
(
(opcode - $1e = registerIndex) or (opcode - $26 = registerIndex) or (opcode - $3f = registerIndex) or (opcode - $47 = registerIndex)
)
then begin
result := 2;
exit;
end;
end;
end;
result := 0;
end;
procedure JavaCode.onAddAttribute(attribute: JavaAttribute);
begin
if (lineNumberTable = nil) and (attribute is JavaLineNumberTable) then begin
lineNumberTable := JavaLineNumberTable(attribute);
end;
end;
function JavaCode.getAttributeClass(const name: AnsiString): JavaAttribute_Class;
begin
if (lineNumberTable = nil) and (name = 'LineNumberTable') then begin
result := JavaLineNumberTable;
end else begin
result := nil;
end;
end;
function JavaCode.getInstructionsCount(): int;
begin
result := length(instructionOffsets);
end;
function JavaCode.getInstructionOffset(instructionIndex: int): int;
var
a: int_Array1d;
begin
a := instructionOffsets;
if (instructionIndex < 0) or (instructionIndex >= length(a)) then begin
raise ArrayIndexOutOfBoundsException.create(instructionIndex);
end;
result := a[instructionIndex];
end;
function JavaCode.getTrueRegisterIndex(javaRegisterIndex: int): int;
var
a: int_Array1d;
begin
a := trueRegistersIndices;
if (javaRegisterIndex < 0) or (javaRegisterIndex >= length(a)) then begin
raise ArrayIndexOutOfBoundsException.create(javaRegisterIndex);
end;
result := a[javaRegisterIndex];
end;
function JavaCode.getExceptionHandlersCount(): int;
begin
result := exceptionHandlersCount;
end;
function JavaCode.getExceptionHandler(index: int): ExceptionHandler;
begin
if (index < 0) or (index >= exceptionHandlersCount) then begin
raise ArrayIndexOutOfBoundsException.create(index);
end;
result := exceptionHandlers[index];
end;
function JavaCode.getVariablesCount(): int;
begin
result := variablesCount;
end;
function JavaCode.getLineNumberTable(): JavaLineNumberTable;
begin
result := lineNumberTable;
end;
function JavaCode.indexOfInstruction(instructionOffset: int): int;
var
l: int;
r: int;
i: int;
c: int;
a: int_Array1d;
begin
a := instructionOffsets;
l := 0;
r := length(a) - 1;
while l <= r do begin
i := (l + r) shr 1;
c := instructionOffset - a[i];
if c > 0 then begin
l := i + 1;
continue;
end;
if c < 0 then begin
r := i - 1;
continue;
end;
result := i;
exit;
end;
result := -1;
end;
{%endregion}
{%region JavaClassMember }
constructor JavaClassMember.create(owner: JavaClass; flags: int; const name, signature: AnsiString);
begin
inherited create();
self.owner := owner;
self.offset := 0;
self.flags := flags;
self.name := name;
self.signature := signature;
end;
procedure JavaClassMember.setOffset(offset: int);
begin
self.offset := offset;
end;
function JavaClassMember.getCompiler(): JavaStaticRecompiler;
begin
result := owner.getCompiler();
end;
function JavaClassMember.getOwner(): JavaClass;
begin
result := owner;
end;
function JavaClassMember.getOffset(): int;
begin
result := offset;
end;
function JavaClassMember.getFlags(): int;
begin
result := flags;
end;
function JavaClassMember.getName(): AnsiString;
begin
result := name;
end;
function JavaClassMember.getSignature(): AnsiString;
begin
result := signature;
end;
function JavaClassMember.getAccess(): int;
var
f: int;
begin
f := flags;
if (f and FLAG_PRIVATE) <> 0 then begin
result := ACCESS_PRIVATE;
exit;
end;
if (f and FLAG_PROTECTED) <> 0 then begin
result := ACCESS_PROTECTED;
exit;
end;
if (f and FLAG_PUBLIC) <> 0 then begin
result := ACCESS_PUBLIC;
exit;
end;
result := ACCESS_PACKAGED;
end;
function JavaClassMember.isStatic(): boolean;
begin
result := (flags and FLAG_STATIC) <> 0;
end;
function JavaClassMember.isFinal(): boolean;
begin
result := (flags and FLAG_FINAL) <> 0;
end;
{%endregion}
{%region JavaField }
constructor JavaField.create(owner: JavaClass; flags: int; const name, signature: AnsiString);
begin
inherited create(owner, flags, name, signature);
constantValue := nil;
outToExecutable := true;
end;
destructor JavaField.destroy;
begin
constantValue.free();
inherited destroy;
end;
procedure JavaField.onAddAttribute(attribute: JavaAttribute);
begin
if (constantValue = nil) and (attribute is JavaConstantValue) then begin
constantValue := JavaConstantValue(attribute);
if isStatic() and isFinal() then begin
outToExecutable := false;
end;
end;
end;
function JavaField.getAttributeClass(const name: AnsiString): JavaAttribute_Class;
begin
if (constantValue = nil) and (name = 'ConstantValue') then begin
result := JavaConstantValue;
end else begin
result := nil;
end;
end;
function JavaField.getConstantPoolIndex(): int;
var
c: JavaConstantValue;
begin
c := constantValue;
if c <> nil then begin
result := c.getConstantPoolIndex();
end else begin
result := 0;
end;
end;
function JavaField.isOutToExecutable(): boolean;
begin
result := outToExecutable;
end;
{%endregion}
{%region JavaMethod }
constructor JavaMethod.create(owner: JavaClass; flags: int; const name, signature: AnsiString);
begin
inherited create(owner, flags, name, signature);
parametersCount := computeParametersCount((flags and FLAG_STATIC) <> 0, signature);
end;
destructor JavaMethod.destroy;
begin
sourceCode.free();
inherited destroy;
end;
procedure JavaMethod.generateSyscall();
begin
{ public static native long syscall(long argument, int number); }
addCommand($9004, getOwner().getLongIndex($01bf0000f9000443)) { load long $01bf0000f9000443 };
addCommand($3042, $0002) { load int [esp + $20] [number] };
addCommand($500b, $ffff) { load int $0000ffff };
addCommand($1062) { and int };
addCommand($1080) { cast int to long };
addCommand($2079, $20) { sal long $20 };
addCommand($1061) { or long };
addCommand($10fe) { currthrd int };
addCommand($300a, $0100) { load short as int $0100 };
addCommand($1060) { or int };
addCommand($1080) { cast int to long };
addCommand($30f9, $0007) { syscall $0007 };
addCommand($1084) { cast long to int };
addCommand($2009, $10) { load byte as int $10 };
addCommand($1050) { add int };
addCommand($10b9) { call int };
addCommand($20bf, $02) { ret value $02 };
end;
procedure JavaMethod.generateGetVariableAddress();
begin
{ public static native int getLocalVariableAddress(<type> var); }
{ public static native int getObjectFieldAddress(<type> fld); }
addCommand($2009, $00) { load byte as int $00 };
addCommand($20bf, $01) { ret value $01 };
end;
procedure JavaMethod.generateVoidInterrupt();
begin
{ static native void interrupt(int number) throws Throwable; }
addCommand($9004, getOwner().getLongIndex($00000001bd0050ff)) { load long $00000001bd0050ff };
addCommand($3042, $0002) { load int [esp + $20] [number] };
addCommand($300a, $00ff) { load short as int $00ff };
addCommand($1062) { and int };
addCommand($1080) { cast int to long };
addCommand($2079, $10) { sal long $10 };
addCommand($1061) { or long };
addCommand($10fe) { currthrd int };
addCommand($300a, $0100) { load short as int $0100 };
addCommand($1060) { or int };
addCommand($1080) { cast int to long };
addCommand($30f9, $0007) { syscall $0007 };
addCommand($1084) { cast long to int };
addCommand($2009, $10) { load byte as int $10 };
addCommand($1050) { add int };
addCommand($10b9) { call int };
addCommand($20bd, $01) { ret $01 };
end;
procedure JavaMethod.generateIntInterrupt();
begin
{ static native void interrupt(int parameter, int number) throws Throwable; }
addCommand($9004, getOwner().getLongIndex($01bd0051ff000442)) { load long $01bd0051ff000442 };
addCommand($3042, $0002) { load int [esp + $20] [number] };
addCommand($300a, $00ff) { load short as int $00ff };
addCommand($1062) { and int };
addCommand($1080) { cast int to long };
addCommand($2079, $28) { sal long $28 };
addCommand($1061) { or long };
addCommand($10fe) { currthrd int };
addCommand($300a, $0100) { load short as int $0100 };
addCommand($1060) { or int };
addCommand($1080) { cast int to long };
addCommand($30f9, $0007) { syscall $0007 };
addCommand($1084) { cast long to int };
addCommand($2009, $10) { load byte as int $10 };
addCommand($1050) { add int };
addCommand($10b9) { call int };
addCommand($20bd, $02) { ret $02 };
end;
procedure JavaMethod.generateLongInterrupt();
begin
{ static native void interrupt(long parameter, int number) throws Throwable; }
addCommand($9004, getOwner().getLongIndex($01bd0052ff000443)) { load long $01bd0052ff000443 };
addCommand($3042, $0002) { load int [esp + $20] [number] };
addCommand($300a, $00ff) { load short as int $00ff };
addCommand($1062) { and int };
addCommand($1080) { cast int to long };
addCommand($2079, $28) { sal long $28 };
addCommand($1061) { or long };
addCommand($10fe) { currthrd int };
addCommand($300a, $0100) { load short as int $0100 };
addCommand($1060) { or int };
addCommand($1080) { cast int to long };
addCommand($30f9, $0007) { syscall $0007 };
addCommand($1084) { cast long to int };
addCommand($2009, $10) { load byte as int $10 };
addCommand($1050) { add int };
addCommand($10b9) { call int };
addCommand($20bd, $02) { ret $02 };
end;
procedure JavaMethod.generateObjectInterrupt();
begin
{ static native void interrupt(Object parameter, int number) throws Throwable; }
addCommand($9004, getOwner().getLongIndex($0001bd00fa000447)) { load long $0001bd00fa000447 };
addCommand($3042, $0002) { load int [esp + $20] [number] };
addCommand($300a, $00ff) { load short as int $00ff };
addCommand($1062) { and int };
addCommand($1080) { cast int to long };
addCommand($2079, $20) { sal long $20 };
addCommand($1061) { or long };
addCommand($10fe) { currthrd int };
addCommand($300a, $0100) { load short as int $0100 };
addCommand($1060) { or int };
addCommand($1080) { cast int to long };
addCommand($30f9, $0007) { syscall $0007 };
addCommand($1084) { cast long to int };
addCommand($2009, $10) { load byte as int $10 };
addCommand($1050) { add int };
addCommand($10b9) { call int };
addCommand($20bd, $02) { ret $02 };
end;
procedure JavaMethod.generateRunExcept();
begin
{ static native void runExcept(Throwable throwable) throws Throwable; }
addCommand($3047, $0001) { load [esp + $10] [exception] };
addCommand($1012) { dup };
addCommand($40c7, $0c) { getfield object +$0c [Throwable.monitor: Object] };
addCommand($5f0b) { call Object.monitorenter() };
addCommand($2157) { runexcept object };
end;
procedure JavaMethod.generateGetFloatAt();
begin
{ static native float getFloatAt(int address); }
addCommand($3042, $0001) { load int [esp + $10] [address] };
addCommand($40cd, $00) { getfield float as real +$00 };
addCommand($20bf, $01) { ret value $01 };
end;
procedure JavaMethod.generateGetDoubleAt();
begin
{ static native double getDoubleAt(int address); }
addCommand($3042, $0001) { load int [esp + $10] [address] };
addCommand($40ce, $00) { getfield double as real +$00 };
addCommand($20bf, $01) { ret value $01 };
end;
procedure JavaMethod.generateGetByteAt();
begin
{ static native byte getByteAt(int address); }
addCommand($3042, $0001) { load int [esp + $10] [address] };
addCommand($40c8, $00) { getfield byte as int +$00 };
addCommand($20bf, $01) { ret value $01 };
end;
procedure JavaMethod.generateGetShortAt();
begin
{ static native short getShortAt(int address); }
addCommand($3042, $0001) { load int [esp + $10] [address] };
addCommand($40c9, $00) { getfield short as int +$00 };
addCommand($20bf, $01) { ret value $01 };
end;
procedure JavaMethod.generateGetIntAt();
begin
{ static native int getIntAt(int address); }
addCommand($3042, $0001) { load int [esp + $10] [address] };
addCommand($40ca, $00) { getfield int +$00 };
addCommand($20bf, $01) { ret value $01 };
end;
procedure JavaMethod.generateGetLongAt();
begin
{ static native long getLongAt(int address); }
addCommand($3042, $0001) { load int [esp + $10] [address] };
addCommand($40c3, $00) { getfield long +$00 };
addCommand($20bf, $01) { ret value $01 };
end;
procedure JavaMethod.generateGetObjectAt();
begin
{ static native Object getObjectAt(int address); }
addCommand($3042, $0001) { load int [esp + $10] [address] };
addCommand($40c7, $00) { getfield object +$00 };
addCommand($20bf, $01) { ret value $01 };
end;
procedure JavaMethod.generateSetFloatAt();
begin
{ static native void setFloatAt(int address, float value); }
addCommand($3042, $0002) { load int [esp + $20] [address] };
addCommand($3046, $0002) { load real [esp + $20] [value] };
addCommand($40dd, $00) { setfield real as float +$00 };
addCommand($20bd, $02) { ret $02 };
end;
procedure JavaMethod.generateSetDoubleAt();
begin
{ static native void setDoubleAt(int address, double value); }
addCommand($3042, $0002) { load int [esp + $20] [address] };
addCommand($3046, $0002) { load real [esp + $20] [value] };
addCommand($40de, $00) { setfield real as double +$00 };
addCommand($20bd, $02) { ret $02 };
end;
procedure JavaMethod.generateSetByteAt();
begin
{ static native void setByteAt(int address, byte value); }
addCommand($3042, $0002) { load int [esp + $20] [address] };
addCommand($3042, $0002) { load int [esp + $20] [value] };
addCommand($40d8, $00) { setfield int as byte +$00 };
addCommand($20bd, $02) { ret $02 };
end;
procedure JavaMethod.generateSetShortAt();
begin
{ static native void setShortAt(int address, short value); }
addCommand($3042, $0002) { load int [esp + $20] [address] };
addCommand($3042, $0002) { load int [esp + $20] [value] };
addCommand($40d9, $00) { setfield int as short +$00 };
addCommand($20bd, $02) { ret $02 };
end;
procedure JavaMethod.generateSetIntAt();
begin
{ static native void setIntAt(int address, int value); }
addCommand($3042, $0002) { load int [esp + $20] [address] };
addCommand($3042, $0002) { load int [esp + $20] [value] };
addCommand($40da, $00) { setfield int +$00 };
addCommand($20bd, $02) { ret $02 };
end;
procedure JavaMethod.generateSetLongAt();
begin
{ static native void setLongAt(int address, long value); }
addCommand($3042, $0002) { load int [esp + $20] [address] };
addCommand($3043, $0002) { load long [esp + $20] [value] };
addCommand($40d3, $00) { setfield long +$00 };
addCommand($20bd, $02) { ret $02 };
end;
procedure JavaMethod.generateSetObjectAt();
begin
{ static native void setObjectAt(int address, Object value); }
addCommand($3042, $0002) { load int [esp + $20] [address] };
addCommand($3047, $0002) { load object [esp + $20] [value] };
addCommand($40d7, $00) { setfield object +$00 };
addCommand($20bd, $02) { ret $02 };
end;
procedure JavaMethod.generateGetCurrentThreadID();
begin
{ static native int getCurrentThreadID(); }
addCommand($10fe) { currthrd int };
addCommand($10be) { ret value };
end;
procedure JavaMethod.generateGetReturnAddress();
begin
{ static native int getReturnAddress(); }
addCommand($2009, $00) { load byte as int $00 };
addCommand($10be) { ret value };
end;
procedure JavaMethod.generateConvertToReference();
begin
{ static native int convertToReference(Object obj); }
addCommand($3047, $0001) { load object [esp + $10] [obj] };
addCommand($109b) { cast object to int };
addCommand($20bf, $01) { ret value $01 };
end;
procedure JavaMethod.generateConvertToObject();
begin
{ static native Object convertToObject(int ref); }
addCommand($3042, $0001) { load int [esp + $10] [ref] };
addCommand($1097) { cast int to object };
addCommand($20bf, $01) { ret value $01 };
end;
procedure JavaMethod.generateGetMethodAddress();
begin
{ static native int getMethodAddress(AnsiString internalRepresentation); }
addCommand($2009, $00) { load byte as int $00 };
addCommand($20bf, $01) { ret value $01 };
end;
procedure JavaMethod.generateGetClassInstance();
begin
{ static native Class getClassInstance(AnsiString internalRepresentation); }
addCommand($102f) { load null };
addCommand($20bf, $01) { ret value $01 };
end;
procedure JavaMethod.generateArrayCopy(direction: boolean; dataType: int);
var
opcodeOffset: int;
begin
{ static native void arraycopy<direction>_<dataType>(Object src, int sidx, Object dst, int didx, int length); }
if direction then begin
opcodeOffset := 8;
end else begin
opcodeOffset := 0;
end;
if dataType = 6 then begin
dataType := 7;
end;
inc(opcodeOffset, dataType);
addCommand($3047, $0005) { load object [esp + $50] [src] };
addCommand($3042, $0005) { load int [esp + $50] [sidx] };
addCommand($3047, $0005) { load object [esp + $50] [dst] };
addCommand($3042, $0005) { load int [esp + $50] [didx] };
addCommand($3042, $0005) { load int [esp + $50] [length] };
addCommand($3200 + opcodeOffset) { arraycopy };
addCommand($20bd, $05) { ret $05 };
end;
procedure JavaMethod.generateArrayFind(direction: boolean; dataType: int);
var
opcodeOffset: int;
begin
{ static native int arrayfind<direction>_<dataType>(Object src, int sidx, <dataType> value); }
if direction then begin
opcodeOffset := 8;
end else begin
opcodeOffset := 0;
end;
if dataType = 6 then begin
dataType := 7;
end;
inc(opcodeOffset, dataType);
addCommand($3047, $0003) { load object [esp + $30] [src] };
addCommand($3042, $0003) { load int [esp + $30] [sidx] };
if (dataType >= 0) and (dataType < 2) then begin
addCommand($3042, $0003) { load int [esp + $30] [value] };
end else begin
addCommand($3040 + dataType, $0003) { load <dataType> [esp + $30] [value] };
end;
addCommand($3210 + opcodeOffset) { arrayfind };
addCommand($20bf, $03) { ret value $03 };
end;
procedure JavaMethod.generateArrayFill(dataType: int);
begin
{ static native void arrayfill_<dataType>(Object dst, int didx, int count, <dataType> value); }
if dataType = 4 then begin
dataType := 7;
end;
addCommand($3047, $0004) { load object [esp + $40] [dst] };
addCommand($3042, $0004) { load int [esp + $40] [didx] };
addCommand($3042, $0004) { load int [esp + $40] [count] };
addCommand($3040, $0004) { load [esp + $40] [value] };
addCommand($3220 + dataType) { arrayfill };
addCommand($20bd, $04) { ret $04 };
end;
procedure JavaMethod.generateFind(direction, zero: boolean);
var
opcodeOffset: int;
begin
{ static native int find<zero><direction>(long[] descriptors, int index, int <zero ? refCountFieldOffset : size>); }
opcodeOffset := 0;
if direction then begin
inc(opcodeOffset);
end;
if zero then begin
inc(opcodeOffset, 2);
end;
addCommand($3047, $0003) { load object [esp + $30] [descriptors] };
addCommand($3042, $0003) { load int [esp + $30] [index] };
addCommand($3042, $0003) { load int [esp + $30] [<zero ? offset : size>] };
addCommand($3228 + opcodeOffset) { find };
addCommand($20bf, $03) { ret value $03 };
end;
procedure JavaMethod.generateGetObjectRefs();
begin
{ static native int getObjectRefs(Object refThis, int refAnot, int[] refOffsets); }
addCommand($3047, $0003) { load object [esp + $30] [refThis] };
addCommand($3042, $0003) { load int [esp + $30] [refAnot] };
addCommand($3047, $0003) { load object [esp + $30] [refOffsets] };
addCommand($322c) { getobjectrefs };
addCommand($20bf, $03) { ret value $03 };
end;
procedure JavaMethod.generateGetArrayRefs();
begin
{ static native int getArrayRefs(Object refThis, int refAnot, int[] refOffsets); }
addCommand($3047, $0003) { load object [esp + $30] [refThis] };
addCommand($3042, $0003) { load int [esp + $30] [refAnot] };
addCommand($3047, $0003) { load object [esp + $30] [refOffsets] };
addCommand($322d) { getarrayrefs };
addCommand($20bf, $03) { ret value $03 };
end;
procedure JavaMethod.generateBlockFindF();
begin
{ static native int blockfindf(long[] descriptors, int startFromIndex, int block); }
addCommand($3047, $0003) { load object [esp + $30] [descriptors] };
addCommand($3042, $0003) { load int [esp + $30] [startFromIndex] };
addCommand($3042, $0003) { load int [esp + $30] [block] };
addCommand($322e) { blockfindf };
addCommand($20bf, $03) { ret value $03 };
end;
procedure JavaMethod.generateBlockFindB();
begin
{ static native int blockfindb(long[] descriptors, int startFromIndex, int block); }
addCommand($3047, $0003) { load object [esp + $30] [descriptors] };
addCommand($3042, $0003) { load int [esp + $30] [startFromIndex] };
addCommand($3042, $0003) { load int [esp + $30] [block] };
addCommand($322f) { blockfindb };
addCommand($20bf, $03) { ret value $03 };
end;
procedure JavaMethod.generateInvokeDefaultConstructor();
var
index: int;
begin
{ static native void invokeDefaultConstructor(Object uninitializedInstance); }
addCommand($3047, $0001) { load object [esp + $10] [uninitializedInstance] };
addCommand($1012) { dup };
addCommand($10cf) { getclass };
addCommand($40c7, $18) { getfield object Class.virtualsAddresses: int[] };
index := (getCompiler().methodDefaultConstructor as JavaMethod).getVirtualIndex();
if index < $80 then begin
addCommand($2009, index) { load byte as int index };
end else
if index < $8000 then begin
addCommand($300a, index) { load short as int index };
end else begin
addCommand($500b, index) { load int index };
end;
addCommand($210a) { getarraycell int };
addCommand($10b9) { call int };
addCommand($20bd, $01) { ret $01 };
end;
procedure JavaMethod.generateIntPart();
begin
{ public static native double intPart(double x); }
addCommand($3045, $0001) { load double [esp + $10] [x] };
addCommand($2170) { int real };
addCommand($20bf, $01) { ret value $01 };
end;
procedure JavaMethod.generateFracPart();
begin
{ public static native double fracPart(double x); }
addCommand($3045, $0001) { load double [esp + $10] [x] };
addCommand($2171) { frac real };
addCommand($20bf, $01) { ret value $01 };
end;
procedure JavaMethod.generateSqrt();
begin
{ public static native double sqrt(double x); }
addCommand($3045, $0001) { load double [esp + $10] [x] };
addCommand($2172) { sqrt real };
addCommand($20bf, $01) { ret value $01 };
end;
procedure JavaMethod.generateArctan();
begin
{ public static native double arctan(double y, double x); }
addCommand($3045, $0002) { load double [esp + $20] [y] };
addCommand($3045, $0002) { load double [esp + $20] [x] };
addCommand($2173) { atan real };
addCommand($20bf, $02) { ret value $02 };
end;
procedure JavaMethod.generateSin();
begin
{ public static native double sin(double x); }
addCommand($3045, $0001) { load double [esp + $10] [x] };
addCommand($2174) { sin real };
addCommand($20bf, $01) { ret value $01 };
end;
procedure JavaMethod.generateCos();
begin
{ public static native double cos(double x); }
addCommand($3045, $0001) { load double [esp + $10] [x] };
addCommand($2175) { cos real };
addCommand($20bf, $01) { ret value $01 };
end;
procedure JavaMethod.generatePow2();
begin
{ public static native double pow2(double x); }
addCommand($3045, $0001) { load double [esp + $10] [x] };
addCommand($2176) { pow2 real };
addCommand($20bf, $01) { ret value $01 };
end;
procedure JavaMethod.generateLog2();
begin
{ public static native double log2(double x); }
addCommand($3045, $0001) { load double [esp + $10] [x] };
addCommand($2177) { log2 real };
addCommand($20bf, $01) { ret value $01 };
end;
procedure JavaMethod.generateFloor();
begin
{ public static native double floor(double x); }
addCommand($3045, $0001) { load double [esp + $10] [x] };
addCommand($217c) { floor real };
addCommand($20bf, $01) { ret value $01 };
end;
procedure JavaMethod.generateCeil();
begin
{ public static native double ceil(double x); }
addCommand($3045, $0001) { load double [esp + $10] [x] };
addCommand($217d) { ceil real };
addCommand($20bf, $01) { ret value $01 };
end;
procedure JavaMethod.generateRound();
begin
{ public static native long round(double x); }
addCommand($3045, $0001) { load double [esp + $10] [x] };
addCommand($217f) { round real };
addCommand($20bf, $01) { ret value $01 };
end;
procedure JavaMethod.defineVirtualStatus();
var
i: int;
access: int;
minAccess: int;
methodAccess: int;
name: AnsiString;
signature: AnsiString;
packageName: AnsiString;
cls: JavaClass;
clso: JavaClass;
owner: JavaClass;
method: JavaMethod;
compiler: JavaStaticRecompiler;
begin
if virtualStatus <> VIRTUAL_STATUS_NOT_DEFINED then begin
exit;
end;
virtualStatus := VIRTUAL_STATUS_NOT_VIRTUAL;
access := getAccess();
owner := getOwner();
if (isStatic()) or (access = ACCESS_PRIVATE) or (owner.isInterface()) then begin
exit;
end;
compiler := getCompiler();
name := getName();
signature := getSignature();
if (owner.getAccess() = ACCESS_PUBLIC) and (access = ACCESS_PUBLIC) and (name = NAME_CONSTRUCTOR) and (signature = SIGNATURE_NO_PARAMETERS) then begin
virtualStatus := VIRTUAL_STATUS_HAS_VIRTUAL;
cls := compiler.classObject;
if cls <> owner then begin
overridden := cls.findMember(NAME_CONSTRUCTOR, SIGNATURE_NO_PARAMETERS) as JavaMethod;
end;
exit;
end;
if name = NAME_CONSTRUCTOR then begin
exit;
end;
if isAbstract() then begin
virtualStatus := VIRTUAL_STATUS_HAS_VIRTUAL;
end;
{
Когда вы перекрываете виртуальный метод в языке Ява, компилятор обязательно требует,
чтобы видимость перекрывающего метода была такой же, или выше, чем у перекрываемого.
Закомментированные участки кода метода JavaMethod.defineVirtualStatus() проверяли то
же самое, однако это требование, как оказалось, НЕ соблюдают среды исполнения программ,
написанных на языке Ява, и эти участки кода пришлось взять под скобки комментариев.
}
cls := owner.getAncestor();
if cls <> nil then begin
method := cls.findMember(name, signature) as JavaMethod;
if (method <> nil) and (not method.isStatic()) and (not method.isFinal()) then begin
packageName := owner.getPackageName();
methodAccess := method.getAccess();
minAccess := ACCESS_PACKAGED;
clso := method.getOwner();
cls := owner;
repeat
cls := cls.getAncestor();
if packageName <> cls.getPackageName() then begin
minAccess := ACCESS_PROTECTED;
break;
end;
until cls = clso;
if (methodAccess >= minAccess) { and (access >= methodAccess) } then begin
virtualStatus := VIRTUAL_STATUS_HAS_VIRTUAL;
overridden := method;
exit;
end;
end;
end;
if (self.isFinal()) or (owner.isFinal()) then begin
exit;
end;
for i := compiler.getClassesCount() - 1 downto 0 do begin
cls := compiler.getClass(i);
if (cls = owner) or (not cls.isInheritedFrom(owner)) then begin
continue;
end;
method := cls.findMember(name, signature) as JavaMethod;
if (method <> self) and (method <> nil) and (not method.isStatic()) { and (method.getAccess() >= access) } then begin
virtualStatus := VIRTUAL_STATUS_HAS_VIRTUAL;
exit;
end;
end;
end;
procedure JavaMethod.addCommandFull(cmd: long);
var
count: int;
commands: long_Array1d;
begin
count := self.commandsCount;
commands := self.commands;
if count = length(commands) then begin
commands := long_Array1d_create(count * 2 + 1);
arraycopy(self.commands, 0, commands, 0, count);
self.commands := commands;
end;
commands[count] := cmd;
self.commandsCount := count + 1;
end;
procedure JavaMethod.addCommand();
begin
addCommandFull(long(0));
end;
procedure JavaMethod.addCommand(opcode: int);
begin
addCommandFull(long(opcode and $ffff));
end;
procedure JavaMethod.addCommand(opcode, data: int);
begin
addCommandFull(long(opcode and $ffff) + (long(data) shl 16));
end;
procedure JavaMethod.addCommand(opcode, classIndex, nameIndex, signatureIndex: int);
begin
addCommandFull(long(opcode and $ffff) + ((long(classIndex) and $ffff) shl 16) + ((long(nameIndex) and $ffff) shl 32) + ((long(signatureIndex) and $ffff) shl 48));
end;
procedure JavaMethod.transformParameters(const signature: AnsiString);
var
i: int;
p: int;
len: int;
begin
len := length(signature);
p := computeParametersCount(true, signature) - 1;
if (len > 0) and (signature[1] = HEADER_PREFIX) then begin
i := 2;
while i <= len do begin
case signature[i] of
HEADER_SUFFIX: begin
break;
end;
PREFIX_FLOAT: begin
addCommand($3044, p) { load float [esp + (p << 4)] };
addCommand($108b) { cast float to real };
addCommand($21f7) { mkreal float };
addCommand($304e, p) { store real [esp + (p << 4)] };
dec(p);
end;
PREFIX_DOUBLE: begin
addCommand($3045, p) { load double [esp + (p << 4)] };
addCommand($108f) { cast double to real };
addCommand($21fb) { mkreal double };
addCommand($304e, p) { store real [esp + (p << 4)] };
dec(p);
end;
PREFIX_BOOLEAN, PREFIX_CHAR, PREFIX_BYTE, PREFIX_SHORT, PREFIX_INT, PREFIX_LONG: begin
dec(p);
end;
PREFIX_OBJECT: begin
repeat
inc(i);
until (i >= len) or (signature[i] = SUFFIX_OBJECT);
dec(p);
end;
PREFIX_ARRAY: begin
repeat
inc(i);
until (i >= len) or (signature[i] <> PREFIX_ARRAY);
if i > len then begin
break;
end;
if signature[i] = PREFIX_OBJECT then begin
repeat
inc(i);
until (i >= len) or (signature[i] = SUFFIX_OBJECT);
end;
dec(p);
end;
end;
inc(i);
end;
end;
end;
procedure JavaMethod.transformReturnValue(const signature: AnsiString);
var
p: int;
begin
p := pos(HEADER_SUFFIX, signature) + 1;
if p > 1 then begin
case signature[p] of
PREFIX_FLOAT: begin
addCommand($1092) { cast real to float };
end;
PREFIX_DOUBLE: begin
addCommand($1093) { cast real to double };
end;
end;
end;
end;
procedure JavaMethod.insertNativeCode(nativeIndex: int);
begin
insertNativeCode(nativeIndex, 0);
end;
procedure JavaMethod.insertNativeCode(nativeIndex, parameter: int);
var
index: int;
intValue1: int;
intValue2: int;
owner: JavaClass;
member: JavaClassMember;
signature: AnsiString;
begin
owner := getOwner();
case nativeIndex of
0: begin
addCommand($30f9, parameter) { syscall parameter };
end;
1.. 6: begin
addCommand($10fe) { currthrd int };
addCommand($300a, $0200) { load short as int $0200 };
addCommand($1060) { or int };
addCommand($1080) { cast int to long };
addCommand($30f9, $0007) { syscall $0007 };
addCommand($1084) { cast long to int };
parameter := parameter shl 4;
if (parameter >= -$80) and (parameter < $80) then begin
addCommand($2009, parameter) { load byte as int parameter };
end else
if (parameter >= -$8000) and (parameter < $8000) then begin
addCommand($300a, parameter) { load short as int parameter };
end else begin
addCommand($500b, parameter) { load int parameter };
end;
addCommand($1050) { add int };
end;
7..12: begin
addCommand($109b) { cast object to int };
if (parameter >= -$80) and (parameter < $80) then begin
addCommand($2009, parameter) { load byte as int parameter };
end else
if (parameter >= -$8000) and (parameter < $8000) then begin
addCommand($300a, parameter) { load short as int parameter };
end else begin
addCommand($500b, parameter) { load int parameter };
end;
addCommand($1050) { add int };
end;
13..15: begin
addCommand($3150 - 13 + nativeIndex, parameter) { interrupt <void, int, long> parameter };
end;
16: begin
addCommand($20fa, parameter) { interrupt object parameter };
end;
17: begin
addCommand($1012) { dup };
addCommand($40c7, $0c) { getfield object +$0c [Throwable.monitor: Object] };
addCommand($5f0b) { call Object.monitorenter() };
addCommand($1014) { dup x1 };
addCommand($1016) { swap };
addCommand($211f) { setarraylength [Throwable.address: int] };
addCommand($10fd) { leave value };
addCommand($2157) { runexcept object };
end;
18: begin
if isStrictfp() then begin
addCommand($40c4) { getfield float +$00 };
end else begin
addCommand($40cd) { getfield float as real +$00 };
end;
end;
19: begin
if isStrictfp() then begin
addCommand($40c5) { getfield double +$00 };
end else begin
addCommand($40ce) { getfield double as real +$00 };
end;
end;
20: begin
addCommand($40c8) { getfield byte as int +$00 };
end;
21: begin
addCommand($40c9) { getfield short as int +$00 };
end;
22: begin
addCommand($40ca) { getfield int +$00 };
end;
23: begin
addCommand($40c3) { getfield long +$00 };
end;
24: begin
addCommand($40c7) { getfield object +$00 };
end;
25: begin
if isStrictfp() then begin
addCommand($40d4) { setfield float +$00 };
end else begin
addCommand($40dd) { setfield real as float +$00 };
end;
end;
26: begin
if isStrictfp() then begin
addCommand($40d5) { setfield double +$00 };
end else begin
addCommand($40de) { setfield real as double +$00 };
end;
end;
27: begin
addCommand($40d8) { setfield int as byte +$00 };
end;
28: begin
addCommand($40d9) { setfield int as short +$00 };
end;
29: begin
addCommand($40da) { setfield int +$00 };
end;
30: begin
addCommand($40d3) { setfield long +$00 };
end;
31: begin
addCommand($40d7) { setfield object +$00 };
end;
32: begin
addCommand($10fe) { currthrd int };
end;
33: begin
if isSynchronized() then begin
addCommand($30e0, $0002) { load [ebp + $20] };
end else begin
addCommand($30e0, $0001) { load [ebp + $10] };
end;
end;
34: begin
addCommand($109b) { cast object to int };
end;
35: begin
addCommand($1097) { cast int to object };
end;
36: begin
signature := (owner.getConstantPoolEntry(parameter) as StringEntry).stringValue();
intValue1 := pos(SEPARATOR_CANONICAL, signature);
intValue2 := pos(HEADER_PREFIX, signature);
if (intValue1 < 1) or (intValue2 < 1) then begin
raise ClassMemberNotFoundException.create('Не удалось найти метод ' + signature + '.');
end;
member := getCompiler().findClassByName(copy(signature, 1, intValue1 - 1)).findMember(
copy(signature, intValue1 + 1, intValue2 - intValue1 - 1),
copy(signature, intValue2, length(signature) - intValue2 + 1)
);
if (member = nil) or (not (member is JavaMethod)) then begin
raise ClassMemberNotFoundException.create('Не удалось найти метод ' + signature + '.');
end;
addCommand($5f0d, owner.getStringIndex(member.getOwner().getName()), owner.getStringIndex(member.getName()), owner.getStringIndex(member.getSignature())) { load int (адрес метода) };
end;
37: begin
signature := (owner.getConstantPoolEntry(parameter) as StringEntry).stringValue();
getCompiler().findClassBySignature(signature);
addCommand($5f06, parameter) { load int (адрес данных класса) };
addCommand($1097) { cast int to object };
end;
38: begin
addCommand($3200) { arraycopyf byte };
end;
39: begin
addCommand($3201) { arraycopyf short };
end;
40: begin
addCommand($3202) { arraycopyf int };
end;
41: begin
addCommand($3203) { arraycopyf long };
end;
42: begin
addCommand($3204) { arraycopyf float };
end;
43: begin
addCommand($3205) { arraycopyf double };
end;
44: begin
addCommand($3207) { arraycopyf object };
end;
45: begin
addCommand($3208) { arraycopyb byte };
end;
46: begin
addCommand($3209) { arraycopyb short };
end;
47: begin
addCommand($320a) { arraycopyb int };
end;
48: begin
addCommand($320b) { arraycopyb long };
end;
49: begin
addCommand($320c) { arraycopyb float };
end;
50: begin
addCommand($320d) { arraycopyb double };
end;
51: begin
addCommand($320f) { arraycopyb object };
end;
52: begin
addCommand($3210) { arrayfindf byte };
end;
53: begin
addCommand($3211) { arrayfindf short };
end;
54: begin
addCommand($3212) { arrayfindf int };
end;
55: begin
addCommand($3213) { arrayfindf long };
end;
56: begin
if not isStrictfp() then begin
addCommand($1092) { cast real to float };
end;
addCommand($3214) { arrayfindf float };
end;
57: begin
if not isStrictfp() then begin
addCommand($1093) { cast real to double };
end;
addCommand($3215) { arrayfindf double };
end;
58: begin
addCommand($3217) { arrayfindf object };
end;
59: begin
addCommand($3218) { arrayfindb byte };
end;
60: begin
addCommand($3219) { arrayfindb short };
end;
61: begin
addCommand($321a) { arrayfindb int };
end;
62: begin
addCommand($321b) { arrayfindb long };
end;
63: begin
if not isStrictfp() then begin
addCommand($1092) { cast real to float };
end;
addCommand($321c) { arrayfindb float };
end;
64: begin
if not isStrictfp() then begin
addCommand($1093) { cast real to double };
end;
addCommand($321d) { arrayfindb double };
end;
65: begin
addCommand($321f) { arrayfindb object };
end;
66: begin
addCommand($3220) { arrayfill byte };
end;
67: begin
addCommand($3221) { arrayfill short };
end;
68: begin
addCommand($3222) { arrayfill int };
end;
69: begin
addCommand($3223) { arrayfill long };
end;
70: begin
addCommand($3227) { arrayfill object };
end;
71: begin
addCommand($3228) { findfreef };
end;
72: begin
addCommand($3229) { findfreeb };
end;
73: begin
addCommand($322a) { findzerof };
end;
74: begin
addCommand($322b) { findzerob };
end;
75: begin
addCommand($322c) { getobjectrefs };
end;
76: begin
addCommand($322d) { getarrayrefs };
end;
77: begin
addCommand($322e) { blockfindf };
end;
78: begin
addCommand($322f) { blockfindb };
end;
79: begin
addCommand($1012) { dup };
addCommand($10cf) { getclass };
addCommand($40c7, $18) { getfield object Class.virtualsAddresses: int[] };
index := (getCompiler().methodDefaultConstructor as JavaMethod).getVirtualIndex();
if index < $80 then begin
addCommand($2009, index) { load byte as int index };
end else
if index < $8000 then begin
addCommand($300a, index) { load short as int index };
end else begin
addCommand($500b, index) { load int index };
end;
addCommand($210a) { getarraycell int };
addCommand($10b9) { call int };
end;
80: begin
if isStrictfp() then begin
addCommand($2168) { int double };
end else begin
addCommand($2170) { int real };
end;
end;
81: begin
if isStrictfp() then begin
addCommand($2169) { frac double };
end else begin
addCommand($2171) { frac real };
end;
end;
82: begin
if isStrictfp() then begin
addCommand($216a) { sqrt double };
end else begin
addCommand($2172) { sqrt real };
end;
end;
83: begin
if isStrictfp() then begin
addCommand($216b) { atan double };
end else begin
addCommand($2173) { atan real };
end;
end;
84: begin
if isStrictfp() then begin
addCommand($216c) { sin double };
end else begin
addCommand($2174) { sin real };
end;
end;
85: begin
if isStrictfp() then begin
addCommand($216d) { cos double };
end else begin
addCommand($2175) { cos real };
end;
end;
86: begin
if isStrictfp() then begin
addCommand($216e) { pow2 double };
end else begin
addCommand($2176) { pow2 real };
end;
end;
87: begin
if isStrictfp() then begin
addCommand($216f) { log2 double };
end else begin
addCommand($2177) { log2 real };
end;
end;
88: begin
if isStrictfp() then begin
addCommand($217a) { floor double };
end else begin
addCommand($217c) { floor real };
end;
end;
89: begin
if isStrictfp() then begin
addCommand($217b) { ceil double };
end else begin
addCommand($217d) { ceil real };
end;
end;
90: begin
if isStrictfp() then begin
addCommand($217e) { round double };
end else begin
addCommand($217f) { round real };
end;
end;
end;
end;
function JavaMethod.getNativeMethodIndex(pc: int): int;
var
i: int;
code: JavaCode;
member: JavaClassMember;
begin
code := sourceCode;
if code.unsignedByteAt(pc) = $b8 then begin
member := getOwner().getConstantPoolMember(code.unsignedShortAt(pc + 1), MEMBER_TYPE_STATIC_METHOD);
for i := 0 to length(NATIVE_METHODS) - 1 do begin
if NATIVE_METHODS[i].equals(member) then begin
result := i;
exit;
end;
end;
end;
result := -1;
end;
function JavaMethod.getVariableOffset(javaRegisterIndex: int): int;
var
index: int;
count: int;
begin
index := sourceCode.getTrueRegisterIndex(javaRegisterIndex);
count := parametersCount;
if index < count then begin
result := count - index + 1;
if isSynchronized() then begin
inc(result);
end;
exit;
end;
result := count - index - 1;
end;
procedure JavaMethod.setVirtualIndex(virtualIndex: int);
begin
self.virtualIndex := virtualIndex;
end;
procedure JavaMethod.prepareCompile();
var
wide: boolean;
clinit: boolean;
needClinitSynchronization: boolean;
i: int;
j: int;
pc: int;
pco: int;
index: int;
opcode: int;
icount: int;
nativeIndex: int;
classNameIndex: int;
loadExceptIndex: int;
exceptionHandlingStartIndex: int;
e: ConstantPoolEntry;
h: ExceptionHandler;
code: JavaCode;
owner: JavaClass;
member: JavaClassMember;
compiler: JavaStaticRecompiler;
name: AnsiString;
signature: AnsiString;
className: AnsiString;
memberName: AnsiString;
memberSignature: AnsiString;
memberOwner: JavaClass;
memberOwnerClinit: JavaClassMember;
intValue1: int;
intValue2: int;
longValue: long;
begin
owner := getOwner();
compiler := owner.getCompiler();
if isNative() then begin
if owner = compiler.classMalikSystem then begin
if NATIVE_METHODS[0].equals(self) then begin
generateSyscall();
exit;
end;
for i := 1 to 12 do begin
if NATIVE_METHODS[i].equals(self) then begin
generateGetVariableAddress();
exit;
end;
end;
if NATIVE_METHODS[13].equals(self) then begin
generateVoidInterrupt();
exit;
end;
if NATIVE_METHODS[14].equals(self) then begin
generateIntInterrupt();
exit;
end;
if NATIVE_METHODS[15].equals(self) then begin
generateLongInterrupt();
exit;
end;
if NATIVE_METHODS[16].equals(self) then begin
generateObjectInterrupt();
exit;
end;
if NATIVE_METHODS[17].equals(self) then begin
generateRunExcept();
exit;
end;
if NATIVE_METHODS[18].equals(self) then begin
generateGetFloatAt();
exit;
end;
if NATIVE_METHODS[19].equals(self) then begin
generateGetDoubleAt();
exit;
end;
if NATIVE_METHODS[20].equals(self) then begin
generateGetByteAt();
exit;
end;
if NATIVE_METHODS[21].equals(self) then begin
generateGetShortAt();
exit;
end;
if NATIVE_METHODS[22].equals(self) then begin
generateGetIntAt();
exit;
end;
if NATIVE_METHODS[23].equals(self) then begin
generateGetLongAt();
exit;
end;
if NATIVE_METHODS[24].equals(self) then begin
generateGetObjectAt();
exit;
end;
if NATIVE_METHODS[25].equals(self) then begin
generateSetFloatAt();
exit;
end;
if NATIVE_METHODS[26].equals(self) then begin
generateSetDoubleAt();
exit;
end;
if NATIVE_METHODS[27].equals(self) then begin
generateSetByteAt();
exit;
end;
if NATIVE_METHODS[28].equals(self) then begin
generateSetShortAt();
exit;
end;
if NATIVE_METHODS[29].equals(self) then begin
generateSetIntAt();
exit;
end;
if NATIVE_METHODS[30].equals(self) then begin
generateSetLongAt();
exit;
end;
if NATIVE_METHODS[31].equals(self) then begin
generateSetObjectAt();
exit;
end;
if NATIVE_METHODS[32].equals(self) then begin
generateGetCurrentThreadID();
exit;
end;
if NATIVE_METHODS[33].equals(self) then begin
generateGetReturnAddress();
exit;
end;
if NATIVE_METHODS[34].equals(self) then begin
generateConvertToReference();
exit;
end;
if NATIVE_METHODS[35].equals(self) then begin
generateConvertToObject();
exit;
end;
if NATIVE_METHODS[36].equals(self) then begin
generateGetMethodAddress();
exit;
end;
if NATIVE_METHODS[37].equals(self) then begin
generateGetClassInstance();
exit;
end;
for i := 38 to 51 do begin
if NATIVE_METHODS[i].equals(self) then begin
generateArrayCopy(i >= 45, (i - 38) mod 7);
exit;
end;
end;
for i := 52 to 65 do begin
if NATIVE_METHODS[i].equals(self) then begin
generateArrayFind(i >= 59, (i - 52) mod 7);
exit;
end;
end;
for i := 66 to 70 do begin
if NATIVE_METHODS[i].equals(self) then begin
generateArrayFill(i - 66);
exit;
end;
end;
for i := 71 to 74 do begin
if NATIVE_METHODS[i].equals(self) then begin
generateFind(((i - 71) and 1) <> 0, ((i - 71) and 2) <> 0);
exit;
end;
end;
if NATIVE_METHODS[75].equals(self) then begin
generateGetObjectRefs();
exit;
end;
if NATIVE_METHODS[76].equals(self) then begin
generateGetArrayRefs();
exit;
end;
if NATIVE_METHODS[77].equals(self) then begin
generateBlockFindF();
exit;
end;
if NATIVE_METHODS[78].equals(self) then begin
generateBlockFindB();
exit;
end;
if NATIVE_METHODS[78].equals(self) then begin
generateGetArrayRefs();
exit;
end;
if NATIVE_METHODS[79].equals(self) then begin
generateInvokeDefaultConstructor();
exit;
end;
end;
if owner = compiler.classMath then begin
if NATIVE_METHODS[80].equals(self) then begin
generateIntPart();
exit;
end;
if NATIVE_METHODS[81].equals(self) then begin
generateFracPart();
exit;
end;
if NATIVE_METHODS[82].equals(self) then begin
generateSqrt();
exit;
end;
if NATIVE_METHODS[83].equals(self) then begin
generateArctan();
exit;
end;
if NATIVE_METHODS[84].equals(self) then begin
generateSin();
exit;
end;
if NATIVE_METHODS[85].equals(self) then begin
generateCos();
exit;
end;
if NATIVE_METHODS[86].equals(self) then begin
generatePow2();
exit;
end;
if NATIVE_METHODS[87].equals(self) then begin
generateLog2();
exit;
end;
if NATIVE_METHODS[88].equals(self) then begin
generateFloor();
exit;
end;
if NATIVE_METHODS[89].equals(self) then begin
generateCeil();
exit;
end;
if NATIVE_METHODS[90].equals(self) then begin
generateRound();
exit;
end;
end;
raise NativeMethodNotFoundException.create('Неизвестный статическому рекомпилятору «родной» метод: ' + owner.getName() + '.' + getName() + getSignature());
end;
code := self.sourceCode;
if code = nil then begin
exit;
end;
name := getName();
signature := getSignature();
className := owner.getName();
classNameIndex := owner.getStringIndex(className);
clinit := isStatic() and (name = NAME_INITIALIZATION) and (signature = SIGNATURE_NO_PARAMETERS);
needClinitSynchronization := clinit and
(className <> CLASS_MEMORY) and (className <> CLASS_CLASS) and
(className <> CLASS_THREAD) and (className <> CLASS_THROWABLE) and
(className <> CLASS_STRING) and (className <> CLASS_STRING_POOL)
;
icount := code.getInstructionsCount();
commandIndices := int_Array1d_create(icount + 1);
commandsCount := 0;
commands := nil;
{ Генерирование промежуточного кода }
if (isStatic() or (name = NAME_CONSTRUCTOR)) and (name <> NAME_INITIALIZATION) then begin
member := owner.findMember(NAME_INITIALIZATION, SIGNATURE_NO_PARAMETERS);
if (member <> nil) and (member.getOwner() = owner) then begin
addCommand($50b6, classNameIndex, owner.getStringIndex(NAME_INITIALIZATION), owner.getStringIndex(SIGNATURE_NO_PARAMETERS)) { call static owner.<clinit>() };
end;
end;
if clinit then begin
if needClinitSynchronization then begin
addCommand($5f03, classNameIndex) { load int (адрес класса – владельца этого метода) };
addCommand($1097) { cast int to object };
addCommand($1012) { dup };
addCommand($40ca, $08) { getfield int +$08 [Class.modifiers: int] };
addCommand($2076, $1f) { shr int $1f };
addCommand($3124, $02) { je int 0 (+2 команды) };
addCommand($1010) { pop };
addCommand($10bc) { ret };
addCommand($2001, $00) { load byte as long $00 };
addCommand($30f9, $0004) { syscall $0004 };
addCommand($1010) { pop };
addCommand($1012) { dup };
addCommand($40ca, $08) { getfield int +$08 [Class.modifiers: int] };
addCommand($2076, $1f) { shr int $1f };
addCommand($3124, $05) { je int 0 (+5 команд) };
addCommand($1010) { pop };
addCommand($2001, $00) { load byte as long $00 };
addCommand($30f9, $0005) { syscall $0005 };
addCommand($1010) { pop };
addCommand($10bc) { ret };
addCommand($1012) { dup };
addCommand($40c7, $30) { getfield object +$30 [Class.initializingThread: Thread] };
addCommand($1012) { dup };
addCommand($3120, $0b) { je object null (+11 команд) };
addCommand($50b6, owner.getStringIndex(CLASS_THREAD), owner.getStringIndex(NAME_CURRENT_THREAD),
owner.getStringIndex(HEADER_PREFIX + HEADER_SUFFIX + PREFIX_OBJECT + CLASS_THREAD + SUFFIX_OBJECT)
) { call Thread.currentThread(): Thread };
addCommand($3128, -$0b) { je object (-11 команд) };
addCommand($2001, $00) { load byte as long $00 };
addCommand($30f9, $0005) { syscall $0005 };
addCommand($1010) { pop };
addCommand($1012) { dup };
addCommand($40ca, $08) { getfield int +$08 [Class.modifiers: int] };
addCommand($2076, $1f) { shr int $1f };
addCommand($3124, -$04) { je int 0 (-4 команды) };
addCommand($1010) { pop };
addCommand($10bc) { ret };
addCommand($1010) { pop };
addCommand($1012) { dup };
addCommand($50b6, owner.getStringIndex(CLASS_THREAD), owner.getStringIndex(NAME_CURRENT_THREAD),
owner.getStringIndex(HEADER_PREFIX + HEADER_SUFFIX + PREFIX_OBJECT + CLASS_THREAD + SUFFIX_OBJECT)
) { call Thread.currentThread(): Thread };
addCommand($40d7, $30) { setfield object +$30 [Class.initializingThread: Thread] };
addCommand($2001, $00) { load byte as long $00 };
addCommand($30f9, $0005) { syscall $0005 };
addCommand($1010) { pop };
end else begin
addCommand($4232, $01) { jmponce (+1 команда) };
addCommand($10bc) { ret };
end;
end;
if isStrictfp() then begin
pc := parametersCount;
if not isStatic() then begin
dec(pc);
end;
j := length(signature);
if (j > 0) and (signature[1] = HEADER_PREFIX) then begin
i := 2;
while i <= j do begin
case signature[i] of
HEADER_SUFFIX: begin
break;
end;
PREFIX_FLOAT: begin
addCommand($3046, pc) { load real [esp + (pc << 4)] };
addCommand($1092) { cast real to float };
addCommand($304c, pc) { store float [esp + (pc << 4)] };
dec(pc);
end;
PREFIX_DOUBLE: begin
addCommand($3046, pc) { load real [esp + (pc << 4)] };
addCommand($1093) { cast real to double };
addCommand($304d, pc) { store double [esp + (pc << 4)] };
dec(pc);
end;
PREFIX_BOOLEAN, PREFIX_CHAR, PREFIX_BYTE, PREFIX_SHORT, PREFIX_INT, PREFIX_LONG: begin
dec(pc);
end;
PREFIX_OBJECT: begin
repeat
inc(i);
until (i >= j) or (signature[i] = SUFFIX_OBJECT);
dec(pc);
end;
PREFIX_ARRAY: begin
repeat
inc(i);
until (i >= j) or (signature[i] <> PREFIX_ARRAY);
if i > j then begin
break;
end;
if signature[i] = PREFIX_OBJECT then begin
repeat
inc(i);
until (i >= j) or (signature[i] = SUFFIX_OBJECT);
end;
dec(pc);
end;
end;
inc(i);
end;
end;
end;
if isSynchronized() then begin
if isStatic() then begin
addCommand($5f03, classNameIndex) { загрузить ссылку на класс-владелец этого метода };
addCommand($1097) { cast int to object };
end else begin
addCommand($3047, parametersCount) { load object [esp + (parametersCount << 4)] [this] };
end;
addCommand($1012) { dup };
addCommand($5f0b) { call Object.monitorenter() };
end;
addCommand($30fb, code.getVariablesCount() - parametersCount) { enter (code.getVariablesCount() - parametersCount) };
loadExceptIndex := commandsCount;
addCommand() { load except <…> };
i := 0;
while i < icount do begin
pc := code.getInstructionOffset(i);
commandIndices[i] := commandsCount;
opcode := code.unsignedByteAt(pc);
wide := false;
if opcode = $c4 then begin
inc(pc);
opcode := code.unsignedByteAt(pc);
wide := true;
end;
case opcode of
$00: { nop };
$01: begin
{ aconst_null }
addCommand($102f) { load null };
end;
$02..$08: begin
{ iconst <–1…5> }
intValue1 := opcode - $03;
nativeIndex := getNativeMethodIndex(pc + 1);
if (nativeIndex = 0) or (nativeIndex >= 13) and (nativeIndex <= 16) then begin
insertNativeCode(nativeIndex, intValue1);
inc(i, 2);
continue;
end;
addCommand($2009, intValue1) { load byte as int <–1…5> };
end;
$09..$0a: begin
{ lconst <0L…1L> }
addCommand($2001, opcode - $09) { load byte as long <0…1> };
end;
$0b..$0d: begin
{ fconst <0.f, 1.f, 2.f> }
if isStrictfp() then begin
addCommand($5005, -5 - $0b + opcode) { load float <0, 1, 2> };
end else begin
addCommand($500e, -5 - $0b + opcode) { load float as real <0, 1, 2> };
end;
end;
$0e..$0f: begin
{ dconst <0.d, 1.d> }
if isStrictfp() then begin
addCommand($9006, -2 - $0e + opcode) { load double <0, 1> };
end else begin
addCommand($900f, -2 - $0e + opcode) { load double as real <0, 1> };
end;
end;
$10: begin
{ bipush }
intValue1 := code.byteAt(pc + 1);
nativeIndex := getNativeMethodIndex(pc + 2);
if (nativeIndex = 0) or (nativeIndex >= 13) and (nativeIndex <= 16) then begin
insertNativeCode(nativeIndex, intValue1);
inc(i, 2);
continue;
end;
addCommand($2009, intValue1) { load byte as int intValue1 };
end;
$11: begin
{ sipush }
intValue1 := code.shortAt(pc + 1);
nativeIndex := getNativeMethodIndex(pc + 3);
if (nativeIndex = 0) or (nativeIndex >= 13) and (nativeIndex <= 16) then begin
insertNativeCode(nativeIndex, intValue1);
inc(i, 2);
continue;
end;
if (intValue1 >= -$80) and (intValue1 < $80) then begin
addCommand($2009, intValue1) { load byte as int intValue1 };
end else begin
addCommand($300a, intValue1) { load short as int intValue1 };
end;
end;
$12..$13: begin
{ ldc }
{ ldc_w }
if opcode = $12 then begin
index := code.unsignedByteAt(pc + 1);
inc(pc, 2);
end else begin
index := code.unsignedShortAt(pc + 1);
inc(pc, 3);
end;
e := owner.getConstantPoolEntry(index);
if e is IntegerEntry then begin
intValue1 := IntegerEntry(e).intValue();
nativeIndex := getNativeMethodIndex(pc);
if (nativeIndex = 0) or (nativeIndex >= 13) and (nativeIndex <= 16) then begin
insertNativeCode(nativeIndex, intValue1);
inc(i, 2);
continue;
end;
if (intValue1 >= -$80) and (intValue1 < $80) then begin
addCommand($2009, intValue1) { load byte as int intValue1 };
end else
if (intValue1 >= -$8000) and (intValue1 < $8000) then begin
addCommand($300a, intValue1) { load short as int intValue1 };
end else begin
addCommand($500b, intValue1) { load int intValue1 };
end;
end else
if e is FloatEntry then begin
if isStrictfp() then begin
addCommand($5005, index) { load float constantPool[index] };
end else begin
addCommand($500e, index) { load float as real constantPool[index] };
end;
end else
if (e is SingleIndexedEntry) and (SingleIndexedEntry(e).getEntryType() = ENTRY_STRING) then begin
index := SingleIndexedEntry(e).getIndex1();
nativeIndex := getNativeMethodIndex(pc);
if (nativeIndex >= 36) and (nativeIndex <= 37) then begin
insertNativeCode(nativeIndex, index);
inc(i, 2);
continue;
end;
addCommand($5f00, index) { загрузить индекс строки };
addCommand($5f01) { call static StringPool.getString(int): AnsiString };
end;
end;
$14: begin
{ ldc2_w }
index := code.unsignedShortAt(pc + 1);
e := owner.getConstantPoolEntry(index);
if e is LongEntry then begin
longValue := LongEntry(e).longValue();
if (longValue >= -$80) and (longValue < $80) then begin
addCommand($2001, int(longValue)) { load byte as long (int) longValue };
end else
if (longValue >= -$8000) and (longValue < $8000) then begin
addCommand($3002, int(longValue)) { load short as long (int) longValue };
end else
if (longValue >= -$80000000) and (longValue < $80000000) then begin
addCommand($5003, int(longValue)) { load int as long (int) longValue };
end else begin
addCommand($9004, index) { load long constantPool[index] };
end;
end else
if e is DoubleEntry then begin
if isStrictfp() then begin
addCommand($9006, index) { load double constantPool[index] };
end else begin
addCommand($900f, index) { load double as real constantPool[index] };
end;
end;
end;
$15, $1a..$1d: begin
{ iload }
if opcode = $15 then begin
if wide then begin
index := code.unsignedShortAt(pc + 1);
inc(pc, 3);
end else begin
index := code.unsignedByteAt(pc + 1);
inc(pc, 2);
end;
end else begin
index := opcode - $1a;
inc(pc);
end;
index := getVariableOffset(index);
nativeIndex := getNativeMethodIndex(pc);
if (nativeIndex >= 1) and (nativeIndex <= 6) then begin
insertNativeCode(nativeIndex, index);
inc(i, 2);
continue;
end;
addCommand($30e2, index) { load int [ebp + (index << 4)] };
end;
$16, $1e..$21: begin
{ lload }
if opcode = $16 then begin
if wide then begin
index := code.unsignedShortAt(pc + 1);
inc(pc, 3);
end else begin
index := code.unsignedByteAt(pc + 1);
inc(pc, 2);
end;
end else begin
index := opcode - $1e;
inc(pc);
end;
index := getVariableOffset(index);
nativeIndex := getNativeMethodIndex(pc);
if (nativeIndex >= 1) and (nativeIndex <= 6) then begin
insertNativeCode(nativeIndex, index);
inc(i, 2);
continue;
end;
addCommand($30e3, index) { load long [ebp + (index << 4)] };
end;
$17, $22..$25: begin
{ fload }
if opcode = $17 then begin
if wide then begin
index := code.unsignedShortAt(pc + 1);
inc(pc, 3);
end else begin
index := code.unsignedByteAt(pc + 1);
inc(pc, 2);
end;
end else begin
index := opcode - $22;
inc(pc);
end;
index := getVariableOffset(index);
nativeIndex := getNativeMethodIndex(pc);
if (nativeIndex >= 1) and (nativeIndex <= 6) then begin
insertNativeCode(nativeIndex, index);
inc(i, 2);
continue;
end;
addCommand($30e4, index) { load float [ebp + (index << 4)] };
end;
$18, $26..$29: begin
{ dload }
if opcode = $18 then begin
if wide then begin
index := code.unsignedShortAt(pc + 1);
inc(pc, 3);
end else begin
index := code.unsignedByteAt(pc + 1);
inc(pc, 2);
end;
end else begin
index := opcode - $26;
inc(pc);
end;
index := getVariableOffset(index);
nativeIndex := getNativeMethodIndex(pc);
if (nativeIndex >= 1) and (nativeIndex <= 6) then begin
insertNativeCode(nativeIndex, index);
inc(i, 2);
continue;
end;
addCommand($30e5, index) { load double [ebp + (index << 4)] };
end;
$19, $2a..$2d: begin
{ aload }
if opcode = $19 then begin
if wide then begin
index := code.unsignedShortAt(pc + 1);
inc(pc, 3);
end else begin
index := code.unsignedByteAt(pc + 1);
inc(pc, 2);
end;
end else begin
index := opcode - $2a;
inc(pc);
end;
index := getVariableOffset(index);
nativeIndex := getNativeMethodIndex(pc);
if (nativeIndex >= 1) and (nativeIndex <= 6) then begin
insertNativeCode(nativeIndex, index);
inc(i, 2);
continue;
end;
addCommand($30e7, index) { load object [ebp + (index << 4)] };
end;
$2e: begin
{ iaload }
addCommand($210a) { getarraycell int };
end;
$2f: begin
{ laload }
addCommand($2103) { getarraycell long };
end;
$30: begin
{ faload }
if isStrictfp() then begin
addCommand($2104) { getarraycell float };
end else begin
addCommand($210d) { getarraycell float as real };
end;
end;
$31: begin
{ daload }
if isStrictfp() then begin
addCommand($2105) { getarraycell double };
end else begin
addCommand($210e) { getarraycell double as real };
end;
end;
$32: begin
{ aaload }
addCommand($2107) { getarraycell object };
end;
$33: begin
{ baload }
addCommand($2108) { getarraycell byte as int };
end;
$34: begin
{ caload }
addCommand($210b) { getarraycell wchar };
end;
$35: begin
{ saload }
addCommand($2109) { getarraycell short as int };
end;
$36, $3b..$3e: begin
{ istore }
if opcode = $36 then begin
if wide then begin
index := code.unsignedShortAt(pc + 1);
end else begin
index := code.unsignedByteAt(pc + 1);
end;
end else begin
index := opcode - $3b;
end;
addCommand($30ea, getVariableOffset(index)) { store int [ebp + (index << 4)] };
end;
$37, $3f..$42: begin
{ lstore }
if opcode = $37 then begin
if wide then begin
index := code.unsignedShortAt(pc + 1);
end else begin
index := code.unsignedByteAt(pc + 1);
end;
end else begin
index := opcode - $3f;
end;
addCommand($30eb, getVariableOffset(index)) { store long [ebp + (index << 4)] };
end;
$38, $43..$46: begin
{ fstore }
if opcode = $38 then begin
if wide then begin
index := code.unsignedShortAt(pc + 1);
end else begin
index := code.unsignedByteAt(pc + 1);
end;
end else begin
index := opcode - $43;
end;
index := getVariableOffset(index);
if isStrictfp() then begin
addCommand($30ec, index) { store float [ebp + (index << 4)] };
end else begin
addCommand($30ee, index) { store real [ebp + (index << 4)] };
end;
end;
$39, $47..$4a: begin
{ dstore }
if opcode = $39 then begin
if wide then begin
index := code.unsignedShortAt(pc + 1);
end else begin
index := code.unsignedByteAt(pc + 1);
end;
end else begin
index := opcode - $47;
end;
index := getVariableOffset(index);
if isStrictfp() then begin
addCommand($30ed, index) { store double [ebp + (index << 4)] };
end else begin
addCommand($30ee, index) { store real [ebp + (index << 4)] };
end;
end;
$3a, $4b..$4e: begin
{ astore }
if opcode = $3a then begin
if wide then begin
index := code.unsignedShortAt(pc + 1);
end else begin
index := code.unsignedByteAt(pc + 1);
end;
end else begin
index := opcode - $4b;
end;
addCommand($30ef, getVariableOffset(index)) { store object [ebp + (index << 4)] };
end;
$4f: begin
{ iastore }
addCommand($211a) { setarraycell int };
end;
$50: begin
{ lastore }
addCommand($2113) { setarraycell long };
end;
$51: begin
{ fastore }
if isStrictfp() then begin
addCommand($2114) { setarraycell float };
end else begin
addCommand($211d) { setarraycell real as float };
end;
end;
$52: begin
{ dastore }
if isStrictfp() then begin
addCommand($2115) { setarraycell double };
end else begin
addCommand($211e) { setarraycell real as double };
end;
end;
$53: begin
{ aastore }
addCommand($3047, $0002) { load object [esp + $20] };
addCommand($1012) { dup };
addCommand($3042, $0003) { load int [esp + $30] };
addCommand($2156) { arraybound };
addCommand($3047, $0001) { load object [esp + $10] };
addCommand($5f02) { call Object.checkObjectArrayAssignable(Object) };
addCommand($2117) { setarraycell object };
end;
$54: begin
{ bastore }
addCommand($2118) { setarraycell int as byte };
end;
$55: begin
{ castore }
addCommand($211b) { setarraycell wchar };
end;
$56: begin
{ sastore }
addCommand($2119) { setarraycell int as short };
end;
$57: begin
{ pop }
addCommand($1018) { popdw };
end;
$58: begin
{ pop2 }
addCommand($1019) { popdw2 };
end;
$59: begin
{ dup }
addCommand($101a) { dupdw };
end;
$5a: begin
{ dup_x1 }
addCommand($101c) { dupdw x1 };
end;
$5b: begin
{ dup_x2 }
addCommand($101e) { dupdw x2 };
end;
$5c: begin
{ dup2 }
addCommand($101b) { dupdw2 };
end;
$5d: begin
{ dup2_x1 }
addCommand($101d) { dupdw2 x1 };
end;
$5e: begin
{ dup2_x2 }
addCommand($101f) { dupdw2 x2 };
end;
$5f: begin
{ swap }
addCommand($101c) { dupdw x1 };
addCommand($1018) { popdw };
end;
$60: begin
{ iadd }
addCommand($1050) { add int };
end;
$61: begin
{ ladd }
addCommand($1051) { add long };
end;
$62: begin
{ fadd }
if isStrictfp() then begin
addCommand($1052) { add float };
end else begin
addCommand($1070) { add real };
end;
end;
$63: begin
{ dadd }
if isStrictfp() then begin
addCommand($1053) { add double };
end else begin
addCommand($1070) { add real };
end;
end;
$64: begin
{ isub }
addCommand($1054) { sub int };
end;
$65: begin
{ lsub }
addCommand($1055) { sub long };
end;
$66: begin
{ fsub }
if isStrictfp() then begin
addCommand($1056) { sub float };
end else begin
addCommand($1071) { sub real };
end;
end;
$67: begin
{ dsub }
if isStrictfp() then begin
addCommand($1057) { sub double };
end else begin
addCommand($1071) { sub real };
end;
end;
$68: begin
{ imul }
addCommand($1058) { mul int };
end;
$69: begin
{ lmul }
addCommand($1059) { mul long };
end;
$6a: begin
{ fmul }
if isStrictfp() then begin
addCommand($105a) { mul float };
end else begin
addCommand($1072) { mul real };
end;
end;
$6b: begin
{ dmul }
if isStrictfp() then begin
addCommand($105b) { mul double };
end else begin
addCommand($1072) { mul real };
end;
end;
$6c: begin
{ idiv }
addCommand($105c) { div int };
end;
$6d: begin
{ ldiv }
addCommand($105d) { div long };
end;
$6e: begin
{ fdiv }
if isStrictfp() then begin
addCommand($105e) { div float };
end else begin
addCommand($1073) { div real };
end;
end;
$6f: begin
{ ddiv }
if isStrictfp() then begin
addCommand($105f) { div double };
end else begin
addCommand($1073) { div real };
end;
end;
$70: begin
{ irem }
addCommand($106c) { rem int };
end;
$71: begin
{ lrem }
addCommand($106d) { rem long };
end;
$72: begin
{ frem }
if isStrictfp() then begin
addCommand($106e) { rem float };
end else begin
addCommand($1077) { rem real };
end;
end;
$73: begin
{ drem }
if isStrictfp() then begin
addCommand($106f) { rem double };
end else begin
addCommand($1077) { rem real };
end;
end;
$74: begin
{ ineg }
addCommand($107c) { neg int };
end;
$75: begin
{ lneg }
addCommand($107d) { neg long };
end;
$76: begin
{ fneg }
if isStrictfp() then begin
addCommand($107e) { neg float };
end else begin
addCommand($107b) { neg real };
end;
end;
$77: begin
{ dneg }
if isStrictfp() then begin
addCommand($107f) { neg double };
end else begin
addCommand($107b) { neg real };
end;
end;
$78: begin
{ ishl }
addCommand($1068) { sal int };
end;
$79: begin
{ lshl }
addCommand($1069) { sal long };
end;
$7a: begin
{ ishr }
addCommand($1066) { sar int };
end;
$7b: begin
{ lshr }
addCommand($1067) { sar long };
end;
$7c: begin
{ iushr }
addCommand($106a) { shr int };
end;
$7d: begin
{ lushr }
addCommand($106b) { shr long };
end;
$7e: begin
{ iand }
addCommand($1062) { and int };
end;
$7f: begin
{ land }
addCommand($1063) { and long };
end;
$80: begin
{ ior }
addCommand($1060) { or int };
end;
$81: begin
{ lor }
addCommand($1061) { or long };
end;
$82: begin
{ ixor }
addCommand($1064) { xor int };
end;
$83: begin
{ lxor }
addCommand($1065) { xor long };
end;
$84: begin
{ iinc }
if wide then begin
index := code.unsignedShortAt(pc + 1);
intValue1 := code.shortAt(pc + 3);
end else begin
index := code.unsignedByteAt(pc + 1);
intValue1 := code.byteAt(pc + 2);
end;
index := getVariableOffset(index);
if intValue1 = 1 then begin
addCommand($41f1, index) { inc int [ebp + (index << 4)] };
end else
if intValue1 = -1 then begin
addCommand($41f9, index) { dec int [ebp + (index << 4)] };
end else begin
if (intValue1 >= -$80) and (intValue1 < $80) then begin
addCommand($2009, intValue1) { load byte as int intValue1 };
end else begin
addCommand($300a, intValue1) { load short as int intValue1 };
end;
addCommand($41c0, index) { add int [ebp + (index << 4)] };
end;
end;
$85: begin
{ i2l }
addCommand($1080) { cast int to long };
end;
$86: begin
{ i2f }
if isStrictfp() then begin
addCommand($1081) { cast int to float };
end else begin
addCommand($1083) { cast int to real };
addCommand($21f7) { mkreal float };
end;
end;
$87: begin
{ i2d }
if isStrictfp() then begin
addCommand($1082) { cast int to double };
end else begin
addCommand($1083) { cast int to real };
addCommand($21fb) { mkreal double };
end;
end;
$88: begin
{ l2i }
addCommand($1084) { cast long to int };
end;
$89: begin
{ l2f }
if isStrictfp() then begin
addCommand($1085) { cast long to float };
end else begin
addCommand($1087) { cast long to real };
addCommand($21f7) { mkreal float };
end;
end;
$8a: begin
{ l2d }
if isStrictfp() then begin
addCommand($1086) { cast long to double };
end else begin
addCommand($1087) { cast long to real };
addCommand($21fb) { mkreal double };
end;
end;
$8b: begin
{ f2i }
if isStrictfp() then begin
addCommand($1088) { cast float to int };
end else begin
addCommand($1090) { cast real to int };
end;
end;
$8c: begin
{ f2l }
if isStrictfp() then begin
addCommand($1089) { cast float to long };
end else begin
addCommand($1091) { cast real to long };
end;
end;
$8d: begin
{ f2d }
addCommand($108a) { cast float to double };
end;
$8e: begin
{ d2i }
if isStrictfp() then begin
addCommand($108c) { cast double to int };
end else begin
addCommand($1090) { cast real to int };
end;
end;
$8f: begin
{ d2l }
if isStrictfp() then begin
addCommand($108d) { cast double to long };
end else begin
addCommand($1091) { cast real to long };
end;
end;
$90: begin
{ d2f }
addCommand($108e) { cast double to float };
end;
$91: begin
{ i2b }
addCommand($1094) { cast int to byte };
end;
$92: begin
{ i2c }
addCommand($1096) { cast int to wchar };
end;
$93: begin
{ i2s }
addCommand($1095) { cast int to short };
end;
$94: begin
{ lcmp }
addCommand($10f1) { cmp long };
end;
$95: begin
{ fcmpl }
if isStrictfp() then begin
addCommand($10f2) { cmpl float };
end else begin
addCommand($10f6) { cmpl real };
end;
end;
$96: begin
{ fcmpg }
if isStrictfp() then begin
addCommand($10f3) { cmpg float };
end else begin
addCommand($10f7) { cmpg real };
end;
end;
$97: begin
{ dcmpl }
if isStrictfp() then begin
addCommand($10f4) { cmpl double };
end else begin
addCommand($10f6) { cmpl real };
end;
end;
$98: begin
{ dcmpg }
if isStrictfp() then begin
addCommand($10f5) { cmpg double };
end else begin
addCommand($10f7) { cmpg real };
end;
end;
$99: begin
{ ifeq }
addCommand($6144) { je int 0 <…> };
end;
$9a: begin
{ ifne }
addCommand($6145) { jne int 0 <…> };
end;
$9b: begin
{ iflt }
addCommand($6146) { jl int 0 <…> };
end;
$9c: begin
{ ifge }
addCommand($6147) { jge int 0 <…> };
end;
$9d: begin
{ ifgt }
addCommand($6142) { jg int 0 <…> };
end;
$9e: begin
{ ifle }
addCommand($6143) { jle int 0 <…> };
end;
$9f: begin
{ if_icmpeq }
addCommand($614c) { je int <…> };
end;
$a0: begin
{ if_icmpne }
addCommand($614d) { jne int <…> };
end;
$a1: begin
{ if_icmplt }
addCommand($614e) { jl int <…> };
end;
$a2: begin
{ if_icmpge }
addCommand($614f) { jge int <…> };
end;
$a3: begin
{ if_icmpgt }
addCommand($614a) { jg int <…> };
end;
$a4: begin
{ if_icmple }
addCommand($614b) { jle int <…> };
end;
$a5: begin
{ if_acmpeq }
addCommand($6148) { je object <…> };
end;
$a6: begin
{ if_acmpne }
addCommand($6149) { jne object <…> };
end;
$a7, $c8: begin
{ goto, goto_w }
addCommand($50b2) { jmp <…> };
end;
$aa: begin
{ tableswitch }
repeat
inc(pc);
until (pc and 3) = 0;
intValue1 := code.intAt(pc + 4);
intValue2 := code.intAt(pc + 8);
if intValue1 > intValue2 then begin
raise UnsupportedBytecodeException.create('Tableswitch: минимальное значение не должно быть больше максимального.');
end;
addCommand($615a, intValue1) { tableswitch int (min=intValue1, };
addCommand($4fff, intValue2) { max=intValue2, };
addCommand($4ffe, intValue2 - intValue1 + 1, 0, 0) { default=<…>, };
for j := intValue1 to intValue2 do begin
addCommand($4ffe, intValue2 - j, 0, 0) { label[j]=<…>) };
end;
end;
$ab: begin
{ lookupswitch }
repeat
inc(pc);
until (pc and 3) = 0;
intValue1 := code.intAt(pc + 4);
if intValue1 < 0 then begin
raise UnsupportedBytecodeException.create('Lookupswitch: количество меток не должно быть отрицательным.');
end;
addCommand($415e, intValue1) { lookupswitch int (labels=intValue1, };
addCommand($4ffe, intValue1 * 2, 0, 0) { default=<…>, };
for j := 1 to intValue1 do begin
addCommand($4fff, code.intAt(pc + (j * 8))) { value[j], };
addCommand($4ffe, (intValue1 - j) * 2, 0, 0) { label[j]=<…>) };
end;
end;
$ac..$b0: begin
{ ireturn, lreturn, freturn, dreturn, areturn }
if isStrictfp() then begin
case opcode of
$ae: begin
addCommand($108b) { cast float to real };
addCommand($21f7) { mkreal float };
end;
$af: begin
addCommand($108f) { cast double to real };
addCommand($21fb) { mkreal double };
end;
end;
end;
addCommand($10fd) { leave value };
if isSynchronized() then begin
addCommand($1016) { swap };
addCommand($5f0c) { call Object.monitorexit() };
end;
if parametersCount > 0 then begin
addCommand($20bf, parametersCount) { ret value parametersCount };
end else begin
addCommand($10be) { ret value };
end;
end;
$b1: begin
{ return }
if (not isStatic()) and (name = NAME_FINALIZE) and (signature = SIGNATURE_NO_PARAMETERS) then begin
index := getVariableOffset(0);
for j := 0 to owner.getFieldsCount() - 1 do begin
member := owner.getField(j);
memberSignature := member.getSignature();
if (not member.isStatic()) and (length(memberSignature) > 0) and (memberSignature[1] in [PREFIX_ARRAY, PREFIX_OBJECT]) then begin
addCommand($30e7, index) { load object [ebp + (index << 4)] [this] };
addCommand($102f) { load null };
addCommand($40d7, member.getOffset()) { setfield object this.member: Object };
end;
end;
member := overridden;
if member <> nil then begin
addCommand($30e7, index) { load object [ebp + (index << 4)] [this] };
addCommand($50b6, owner.getStringIndex(member.getOwner().getName()), owner.getStringIndex(member.getName()), owner.getStringIndex(member.getSignature())) { call super.$finalize$() };
end;
end;
addCommand($10fc) { leave };
if isSynchronized() then begin
addCommand($5f0c) { call Object.monitorexit() };
end;
if needClinitSynchronization then begin
addCommand($1012) { dup };
addCommand($1012) { dup };
addCommand($40ca, $08) { getfield int +$08 [Class.modifiers: int] };
addCommand($500b, $80000000) { load int $80000000 };
addCommand($1060) { or int };
addCommand($40da, $08) { setfield int +$08 [Class.modifiers: int] };
addCommand($102f) { load null };
addCommand($40d7, $30) { setfield object +$30 [Class.initializingThread: Thread] };
end;
if owner.isInheritedFrom(compiler.interfaceInterrupt) and (not isStatic()) and (name = NAME_INTERRUPT) and (parametersCount >= 1) and (parametersCount <= 2) then begin
case parametersCount of
1: begin
addCommand($10ba) { iret $01 };
end;
2: begin
addCommand($10bb) { iret $02 };
end;
end;
end else begin
if parametersCount > 0 then begin
addCommand($20bd, parametersCount) { ret parametersCount };
end else begin
addCommand($10bc) { ret };
end;
end;
end;
$b2: begin
{ getstatic }
member := owner.getConstantPoolMember(code.unsignedShortAt(pc + 1), MEMBER_TYPE_STATIC_FIELD);
if (not (member is JavaField)) or (not member.isStatic()) or (not JavaField(member).isOutToExecutable()) then begin
raise ClassMemberNotFoundException.create('Команде getstatic требуется ' + MEMBER_TYPES[MEMBER_TYPE_STATIC_FIELD] + ', не имеющее постоянного значения.');
end;
memberOwner := member.getOwner();
memberName := member.getName();
memberSignature := member.getSignature();
if memberOwner <> owner then begin
memberOwnerClinit := memberOwner.findMemberInternal(NAME_INITIALIZATION, SIGNATURE_NO_PARAMETERS);
if memberOwnerClinit <> nil then begin
addCommand($50b6,
owner.getStringIndex(memberOwner.getName()),
owner.getStringIndex(NAME_INITIALIZATION),
owner.getStringIndex(SIGNATURE_NO_PARAMETERS)
) { call static memberOwnerClinit.<clinit>() };
end;
end;
if length(memberSignature) > 0 then begin
case memberSignature[1] of
PREFIX_BOOLEAN, PREFIX_BYTE: begin
addCommand($5028,
owner.getStringIndex(memberOwner.getName()),
owner.getStringIndex(memberName),
owner.getStringIndex(memberSignature)
) { load byte as int [memberOwner.member: <boolean, byte>] };
end;
PREFIX_CHAR: begin
addCommand($502b,
owner.getStringIndex(memberOwner.getName()),
owner.getStringIndex(memberName),
owner.getStringIndex(memberSignature)
) { load wchar [memberOwner.member: char] };
end;
PREFIX_FLOAT: begin
if isStrictfp() then begin
addCommand($5024,
owner.getStringIndex(memberOwner.getName()),
owner.getStringIndex(memberName),
owner.getStringIndex(memberSignature)
) { load float [memberOwner.member: float] };
end else begin
addCommand($502d,
owner.getStringIndex(memberOwner.getName()),
owner.getStringIndex(memberName),
owner.getStringIndex(memberSignature)
) { load float as real [memberOwner.member: float] };
end;
end;
PREFIX_DOUBLE: begin
if isStrictfp() then begin
addCommand($5025,
owner.getStringIndex(memberOwner.getName()),
owner.getStringIndex(memberName),
owner.getStringIndex(memberSignature)
) { load double [memberOwner.member: double] };
end else begin
addCommand($502e,
owner.getStringIndex(memberOwner.getName()),
owner.getStringIndex(memberName),
owner.getStringIndex(memberSignature)
) { load double as real [memberOwner.member: double] };
end;
end;
PREFIX_SHORT: begin
addCommand($5029,
owner.getStringIndex(memberOwner.getName()),
owner.getStringIndex(memberName),
owner.getStringIndex(memberSignature)
) { load short as int [memberOwner.member: short] };
end;
PREFIX_INT: begin
addCommand($502a,
owner.getStringIndex(memberOwner.getName()),
owner.getStringIndex(memberName),
owner.getStringIndex(memberSignature)
) { load int [memberOwner.member: int] };
end;
PREFIX_LONG: begin
addCommand($5023,
owner.getStringIndex(memberOwner.getName()),
owner.getStringIndex(memberName),
owner.getStringIndex(memberSignature)
) { load long [memberOwner.member: long] };
end;
PREFIX_OBJECT, PREFIX_ARRAY: begin
addCommand($5027,
owner.getStringIndex(memberOwner.getName()),
owner.getStringIndex(memberName),
owner.getStringIndex(memberSignature)
) { load object [memberOwner.member: Object] };
end;
end;
end;
end;
$b3: begin
{ putstatic }
member := owner.getConstantPoolMember(code.unsignedShortAt(pc + 1), MEMBER_TYPE_STATIC_FIELD);
if (not (member is JavaField)) or (not member.isStatic()) or (not JavaField(member).isOutToExecutable()) then begin
raise ClassMemberNotFoundException.create('Команде putstatic требуется ' + MEMBER_TYPES[MEMBER_TYPE_STATIC_FIELD] + ', не имеющее постоянного значения.');
end;
memberOwner := member.getOwner();
memberName := member.getName();
memberSignature := member.getSignature();
if memberOwner <> owner then begin
memberOwnerClinit := memberOwner.findMemberInternal(NAME_INITIALIZATION, SIGNATURE_NO_PARAMETERS);
if memberOwnerClinit <> nil then begin
addCommand($50b6,
owner.getStringIndex(memberOwner.getName()),
owner.getStringIndex(NAME_INITIALIZATION),
owner.getStringIndex(SIGNATURE_NO_PARAMETERS)
) { call static memberOwnerClinit.<clinit>() };
end;
end;
if length(memberSignature) > 0 then begin
case memberSignature[1] of
PREFIX_BOOLEAN, PREFIX_BYTE: begin
addCommand($5038,
owner.getStringIndex(memberOwner.getName()),
owner.getStringIndex(memberName),
owner.getStringIndex(memberSignature)
) { store int as byte [memberOwner.member: <boolean, byte>] };
end;
PREFIX_CHAR: begin
addCommand($503b,
owner.getStringIndex(memberOwner.getName()),
owner.getStringIndex(memberName),
owner.getStringIndex(memberSignature)
) { store wchar [memberOwner.member: char] };
end;
PREFIX_FLOAT: begin
if isStrictfp() then begin
addCommand($5034,
owner.getStringIndex(memberOwner.getName()),
owner.getStringIndex(memberName),
owner.getStringIndex(memberSignature)
) { store float [memberOwner.member: float] };
end else begin
addCommand($503d,
owner.getStringIndex(memberOwner.getName()),
owner.getStringIndex(memberName),
owner.getStringIndex(memberSignature)
) { store real as float [memberOwner.member: float] };
end;
end;
PREFIX_DOUBLE: begin
if isStrictfp() then begin
addCommand($5035,
owner.getStringIndex(memberOwner.getName()),
owner.getStringIndex(memberName),
owner.getStringIndex(memberSignature)
) { store double [memberOwner.member: double] };
end else begin
addCommand($503e,
owner.getStringIndex(memberOwner.getName()),
owner.getStringIndex(memberName),
owner.getStringIndex(memberSignature)
) { store real as double [memberOwner.member: double] };
end;
end;
PREFIX_SHORT: begin
addCommand($5039,
owner.getStringIndex(memberOwner.getName()),
owner.getStringIndex(memberName),
owner.getStringIndex(memberSignature)
) { store int as short [memberOwner.member: short] };
end;
PREFIX_INT: begin
addCommand($503a,
owner.getStringIndex(memberOwner.getName()),
owner.getStringIndex(memberName),
owner.getStringIndex(memberSignature)
) { store int [memberOwner.member: int] };
end;
PREFIX_LONG: begin
addCommand($5033,
owner.getStringIndex(memberOwner.getName()),
owner.getStringIndex(memberName),
owner.getStringIndex(memberSignature)
) { store long [memberOwner.member: long] };
end;
PREFIX_OBJECT, PREFIX_ARRAY: begin
addCommand($5037,
owner.getStringIndex(memberOwner.getName()),
owner.getStringIndex(memberName),
owner.getStringIndex(memberSignature)
) { store object [memberOwner.member: Object] };
end;
end;
end;
end;
$b4: begin
{ getfield }
member := owner.getConstantPoolMember(code.unsignedShortAt(pc + 1), MEMBER_TYPE_INSTANCE_FIELD);
if (not (member is JavaField)) or member.isStatic() then begin
raise ClassMemberNotFoundException.create('Команде getfield требуется ' + MEMBER_TYPES[MEMBER_TYPE_INSTANCE_FIELD] + '.');
end;
memberSignature := member.getSignature();
nativeIndex := getNativeMethodIndex(pc + 3);
if (nativeIndex >= 7) and (nativeIndex <= 12) then begin
insertNativeCode(nativeIndex, member.getOffset());
inc(i, 2);
continue;
end;
if length(memberSignature) > 0 then begin
case memberSignature[1] of
PREFIX_BOOLEAN, PREFIX_BYTE: begin
addCommand($40c8, member.getOffset()) { getfield byte as int memberOwner.member: <boolean, byte> };
end;
PREFIX_CHAR: begin
addCommand($40cb, member.getOffset()) { getfield wchar memberOwner.member: char };
end;
PREFIX_FLOAT: begin
if isStrictfp() then begin
addCommand($40c4, member.getOffset()) { getfield float memberOwner.member: float };
end else begin
addCommand($40cd, member.getOffset()) { getfield float as real memberOwner.member: float };
end;
end;
PREFIX_DOUBLE: begin
if isStrictfp() then begin
addCommand($40c5, member.getOffset()) { getfield double memberOwner.member: double };
end else begin
addCommand($40ce, member.getOffset()) { getfield double as real memberOwner.member: double };
end;
end;
PREFIX_SHORT: begin
addCommand($40c9, member.getOffset()) { getfield short as int memberOwner.member: short };
end;
PREFIX_INT: begin
addCommand($40ca, member.getOffset()) { getfield int memberOwner.member: int };
end;
PREFIX_LONG: begin
addCommand($40c3, member.getOffset()) { getfield long memberOwner.member: long };
end;
PREFIX_OBJECT, PREFIX_ARRAY: begin
addCommand($40c7, member.getOffset()) { getfield object memberOwner.member: Object };
end;
end;
end;
end;
$b5: begin
{ putfield }
member := owner.getConstantPoolMember(code.unsignedShortAt(pc + 1), MEMBER_TYPE_INSTANCE_FIELD);
if (not (member is JavaField)) or member.isStatic() then begin
raise ClassMemberNotFoundException.create('Команде putfield требуется ' + MEMBER_TYPES[MEMBER_TYPE_INSTANCE_FIELD] + '.');
end;
memberSignature := member.getSignature();
if length(memberSignature) > 0 then begin
case memberSignature[1] of
PREFIX_BOOLEAN, PREFIX_BYTE: begin
addCommand($40d8, member.getOffset()) { setfield int as byte memberOwner.member: <boolean, byte> };
end;
PREFIX_CHAR: begin
addCommand($40db, member.getOffset()) { setfield wchar memberOwner.member: char };
end;
PREFIX_FLOAT: begin
if isStrictfp() then begin
addCommand($40d4, member.getOffset()) { setfield float memberOwner.member: float };
end else begin
addCommand($40dd, member.getOffset()) { setfield real as float memberOwner.member: float };
end;
end;
PREFIX_DOUBLE: begin
if isStrictfp() then begin
addCommand($40d5, member.getOffset()) { setfield double memberOwner.member: double };
end else begin
addCommand($40de, member.getOffset()) { setfield real as double memberOwner.member: double };
end;
end;
PREFIX_SHORT: begin
addCommand($40d9, member.getOffset()) { setfield int as short memberOwner.member: short };
end;
PREFIX_INT: begin
addCommand($40da, member.getOffset()) { setfield int memberOwner.member: int };
end;
PREFIX_LONG: begin
addCommand($40d3, member.getOffset()) { setfield long memberOwner.member: long };
end;
PREFIX_OBJECT, PREFIX_ARRAY: begin
addCommand($40d7, member.getOffset()) { setfield object memberOwner.member: Object };
end;
end;
end;
end;
$b6: begin
{ invokevirtual }
member := owner.getConstantPoolMember(code.unsignedShortAt(pc + 1), MEMBER_TYPE_INSTANCE_METHOD);
if (not (member is JavaMethod)) or member.isStatic() then begin
raise ClassMemberNotFoundException.create('Команде invokevirtual требуется ' + MEMBER_TYPES[MEMBER_TYPE_INSTANCE_METHOD] + '.');
end;
memberSignature := member.getSignature();
if JavaMethod(member).isVirtual() then begin
if isStrictfp() then begin
transformParameters(memberSignature);
end;
addCommand($3047, JavaMethod(member).parametersCount - 1) { load object [esp + ((JavaMethod(member).parametersCount - 1) << 4)] [this для вызываемого метода] };
addCommand($10cf) { getclass };
addCommand($40c7, $18) { getfield object Class.virtualsAddresses: int[] };
index := JavaMethod(member).getVirtualIndex();
if index < $80 then begin
addCommand($2009, index) { load byte as int index };
end else
if index < $8000 then begin
addCommand($300a, index) { load short as int index };
end else begin
addCommand($500b, index) { load int index };
end;
addCommand($210a) { getarraycell int };
addCommand($10b9) { call int };
end else begin
addCommand($5230, JavaMethod(member).parametersCount - 1) { check object null [esp + ((JavaMethod(member).parametersCount - 1) << 4)] [this для вызываемого метода] };
if isStrictfp() then begin
transformParameters(memberSignature);
end;
addCommand($50b6, owner.getStringIndex(member.getOwner().getName()), owner.getStringIndex(member.getName()), owner.getStringIndex(memberSignature)) { call member };
end;
if isStrictfp() then begin
transformReturnValue(memberSignature);
end;
end;
$b7: begin
{ invokespecial }
member := owner.getConstantPoolMember(code.unsignedShortAt(pc + 1), MEMBER_TYPE_INSTANCE_METHOD);
if (not (member is JavaMethod)) or member.isStatic() then begin
raise ClassMemberNotFoundException.create('Команде invokestatic требуется ' + MEMBER_TYPES[MEMBER_TYPE_INSTANCE_METHOD] + '.');
end;
memberSignature := member.getSignature();
addCommand($5230, JavaMethod(member).parametersCount - 1) { check object null [esp + ((JavaMethod(member).parametersCount - 1) << 4)] [this для вызываемого метода] };
if isStrictfp() then begin
transformParameters(memberSignature);
end;
addCommand($50b6, owner.getStringIndex(member.getOwner().getName()), owner.getStringIndex(member.getName()), owner.getStringIndex(memberSignature)) { call member };
if isStrictfp() then begin
transformReturnValue(memberSignature);
end;
end;
$b8: begin
{ invokestatic }
member := owner.getConstantPoolMember(code.unsignedShortAt(pc + 1), MEMBER_TYPE_STATIC_METHOD);
if (not (member is JavaMethod)) or (not member.isStatic()) then begin
raise ClassMemberNotFoundException.create('Команде invokestatic требуется ' + MEMBER_TYPES[MEMBER_TYPE_STATIC_METHOD] + '.');
end;
nativeIndex := getNativeMethodIndex(pc);
if (nativeIndex >= 17) and (nativeIndex <= 35) or (nativeIndex >= 38) then begin
insertNativeCode(nativeIndex);
inc(i);
continue;
end;
memberSignature := member.getSignature();
if isStrictfp() then begin
transformParameters(memberSignature);
end;
addCommand($50b6, owner.getStringIndex(member.getOwner().getName()), owner.getStringIndex(member.getName()), owner.getStringIndex(memberSignature)) { call <static method address> };
if isStrictfp() then begin
transformReturnValue(memberSignature);
end;
end;
$b9: begin
{ invokeinterface }
member := owner.getConstantPoolMember(code.unsignedShortAt(pc + 1), MEMBER_TYPE_INTERFACE_METHOD);
memberOwner := member.getOwner();
if (not (member is JavaMethod)) or member.isStatic() or (not memberOwner.isInterface()) or (not JavaMethod(member).isAbstract()) then begin
raise ClassMemberNotFoundException.create('Команде invokeinterface требуется ' + MEMBER_TYPES[MEMBER_TYPE_INTERFACE_METHOD] + '.');
end;
memberSignature := member.getSignature();
if isStrictfp() then begin
transformParameters(memberSignature);
end;
addCommand($3047, JavaMethod(member).parametersCount - 1) { load object [esp + ((JavaMethod(member).parametersCount - 1) << 4)] [this для вызываемого метода] };
addCommand($10cf) { getclass };
addCommand($5f03, owner.getStringIndex(memberOwner.getName())) { load int (адрес данных протокола) };
addCommand($1097) { cast int to object };
index := JavaMethod(member).getVirtualIndex() * IMT_ENTRY_SIZE;
if index < $80 then begin
addCommand($2009, index) { load byte as int index };
end else
if index < $8000 then begin
addCommand($300a, index) { load short as int index };
end else begin
addCommand($500b, index) { load int index };
end;
addCommand($5f04) { call Class.getInterfaceMethodEntryPoint(Class, int): int };
addCommand($10b9) { call int };
if isStrictfp() then begin
transformReturnValue(memberSignature);
end;
end;
$bb: begin
{ new }
index := code.unsignedShortAt(pc + 1);
index := (owner.getConstantPoolEntry(index) as SingleIndexedEntry).getIndex1();
className := (owner.getConstantPoolEntry(index) as StringEntry).stringValue();
compiler.findClassByName(className);
addCommand($5f03, index) { load int (адрес класса, инстанцию которого следует создать) };
addCommand($1097) { cast int to object };
addCommand($5f05) { call Class.allocateInstance(): Object };
end;
$bc: begin
{ newarray }
className := '';
case code.unsignedByteAt(pc + 1) of
4: className := PREFIX_ARRAY + PREFIX_BOOLEAN;
5: className := PREFIX_ARRAY + PREFIX_CHAR;
6: className := PREFIX_ARRAY + PREFIX_FLOAT;
7: className := PREFIX_ARRAY + PREFIX_DOUBLE;
8: className := PREFIX_ARRAY + PREFIX_BYTE;
9: className := PREFIX_ARRAY + PREFIX_SHORT;
10: className := PREFIX_ARRAY + PREFIX_INT;
11: className := PREFIX_ARRAY + PREFIX_LONG;
end;
compiler.findClassBySignature(className);
addCommand($5f06, owner.getStringIndex(className)) { load int (адрес класса, инстанцию которого следует создать) };
addCommand($1097) { cast int to object };
addCommand($5f07) { call static Array.create(int, Class): Object };
end;
$bd: begin
{ anewarray }
index := code.unsignedShortAt(pc + 1);
index := (owner.getConstantPoolEntry(index) as SingleIndexedEntry).getIndex1();
className := (owner.getConstantPoolEntry(index) as StringEntry).stringValue();
if (length(className) > 0) and (className[1] in [PREFIX_ARRAY, PREFIX_OBJECT]) then begin
className := PREFIX_ARRAY + className;
end else begin
className := PREFIX_ARRAY + PREFIX_OBJECT + className + SUFFIX_OBJECT;
end;
compiler.findClassBySignature(className);
addCommand($5f06, owner.getStringIndex(className)) { load int (адрес класса, инстанцию которого следует создать) };
addCommand($1097) { cast int to object };
addCommand($5f07) { call static Array.create(int, Class): Object };
end;
$be: begin
{ arraylength }
addCommand($210f) { getarraylength };
end;
$bf: begin
{ athrow }
addCommand($20fa, $20) { interrupt object $20 };
end;
$c0..$c1: begin
{ checkcast, instanceof }
index := code.unsignedShortAt(pc + 1);
index := (owner.getConstantPoolEntry(index) as SingleIndexedEntry).getIndex1();
className := (owner.getConstantPoolEntry(index) as StringEntry).stringValue();
if (length(className) = 0) or (not (className[1] in [PREFIX_ARRAY, PREFIX_OBJECT])) then begin
className := PREFIX_OBJECT + className + SUFFIX_OBJECT;
end;
compiler.findClassBySignature(className);
addCommand($5f06, owner.getStringIndex(className)) { load int (адрес класса для проверки) };
addCommand($1097) { cast int to object };
addCommand($1016) { swap };
addCommand($5f09 - $c0 + opcode) { call Class.cast(Object): Object } { call Class.isInstance(Object): boolean };
end;
$c2..$c3: begin
{ monitorenter, monitorexit }
addCommand($5230, $0000) { check object null [esp + $00] };
addCommand($5f0b - $c2 + opcode) { call Object.monitorenter() } { call Object.monitorexit() };
end;
$c5: begin
{ multianewarray }
index := code.unsignedShortAt(pc + 1);
index := (owner.getConstantPoolEntry(index) as SingleIndexedEntry).getIndex1();
className := (owner.getConstantPoolEntry(index) as StringEntry).stringValue();
intValue1 := code.unsignedByteAt(pc + 3);
compiler.findClassBySignature(PREFIX_ARRAY + PREFIX_INT);
compiler.findClassBySignature(className);
if intValue1 < $80 then begin
addCommand($2009, intValue1) { load byte as int intValue1 };
end else begin
addCommand($300a, intValue1) { load short as int intValue1 };
end;
addCommand($5f06, owner.getStringIndex(PREFIX_ARRAY + PREFIX_INT)) { load int (адрес класса int[]) };
addCommand($1097) { cast int to object };
addCommand($5f07) { call static Array.create(int, Class): Object };
for j := 0 to intValue1 - 1 do begin
addCommand($1012) { dup };
if j < $80 then begin
addCommand($2009, j) { load byte as int j };
end else begin
addCommand($300a, j) { load short as int j };
end;
addCommand($3042, intValue1 - j + 2) { load int [esp + ((intValue1 - j + 2) << 4)] };
addCommand($211a) { setarraycell int };
end;
addCommand($5f06, index) { load int (адрес класса создаваемого многомерного массива) };
addCommand($1097) { cast int to object };
addCommand($5f08) { call static Array.create(int[], Class): Object };
addCommand($304f, intValue1 - 1) { store object [esp + ((intValue1 - 1) << 4)] };
addCommand($3011, intValue1 - 1) { pop (intValue1 - 1) };
end;
$c6..$c7: begin
{ ifnull, ifnonnull }
addCommand($6140 - $c6 + opcode) { je object null <…> } { jne object null <…> };
end;
$ca: begin
{ breakpoint }
addCommand($103f) { breakpoint };
end;
$a8..$a9, $ba, $c9, $fe, $ff: begin
{ jsr, ret, invokedynamic, jsr_w, impdep1, impdep2 }
raise UnsupportedBytecodeException.create('Команды jsr, ret, invokedynamic, jsr_w, impdep1, impdep2 не поддерживаются.');
end;
else
raise UnsupportedBytecodeException.create('Неизвестный байт-код $' + toHexString(long(opcode), 2) + '.');
end;
inc(i);
end;
commandIndices[icount] := commandsCount;
{ Генерирование кода для обработки исключений }
exceptionHandlingStartIndex := commandsCount;
commands[loadExceptIndex] := long($5008) + ((long(exceptionHandlingStartIndex) - long(loadExceptIndex) - 1) shl 16);
for i := code.getExceptionHandlersCount() - 1 downto 0 do begin
h := code.getExceptionHandler(i);
pc := 0;
for j := 0 to h.getCatchesLength() - 1 do begin
index := h.getCatch(j).getClassIndex();
if index > 0 then begin
inc(pc, 5);
end;
inc(pc, 6);
end;
addCommand($1012) { dup };
addCommand($210f) { getarraylength [Throwable.address: int] };
addCommand($5ffd, commandIndices[code.indexOfInstruction(h.getTryStart())]) { load int try[i].start };
addCommand($614e, pc + 4) { jl int (+(pc + 4) команды) };
addCommand($1012) { dup };
addCommand($210f) { getarraylength [Throwable.address: int] };
addCommand($5ffd, commandIndices[code.indexOfInstruction(h.getTryFinish())]) { load int try[i].finish };
addCommand($614f, pc) { jge int (+pc команд) };
for j := 0 to h.getCatchesLength() - 1 do begin
index := h.getCatch(j).getClassIndex();
if index > 0 then begin
index := (owner.getConstantPoolEntry(index) as SingleIndexedEntry).getIndex1();
addCommand($5f03, index) { загрузить ссылку на класс исключения };
addCommand($1097) { cast int to object };
addCommand($3047, $0001) { load object [esp + $10] };
addCommand($5f0a) { call Class.isInstance(Object): boolean };
addCommand($6144, $06) { je int 0 (+6 команд) };
end;
addCommand($5008, exceptionHandlingStartIndex - commandsCount - 1) { load except exceptionHandlingStartIndex };
addCommand($1016) { swap };
addCommand($1012) { dup };
addCommand($40c7, $0c) { getfield object +$0c [Throwable.monitor: Object] };
addCommand($5f0c) { call Object.monitorexit() };
addCommand($50b2, commandIndices[code.indexOfInstruction(h.getCatch(j).getCatchOffset())] - commandsCount - 1) { jmp try[i].catch[j] };
end;
end;
if isSynchronized() then begin
addCommand($30e7, $0001) { load object [ebp + $10] <monitor> };
addCommand($5f0c) { call Object.monitorexit() };
if needClinitSynchronization then begin
addCommand($30e7, $0002) { load object [ebp + $20] };
addCommand($1012) { dup };
addCommand($1012) { dup };
addCommand($40ca, $08) { getfield int +$08 [Class.modifiers: int] };
addCommand($500b, $80000000) { load int $80000000 };
addCommand($1060) { or int };
addCommand($40da, $08) { setfield int +$08 [Class.modifiers: int] };
addCommand($102f) { load null };
addCommand($40d7, $30) { setfield object +$30 [Class.initializingThread: Thread] };
addCommand($30e0, $0003) { load [ebp + $30] <return address> };
end else begin
addCommand($1012) { dup };
addCommand($30e0, $0002) { load [ebp + $20] <return address> };
end;
end else begin
if needClinitSynchronization then begin
addCommand($30e7, $0001) { load object [ebp + $10] <monitor> };
addCommand($1012) { dup };
addCommand($1012) { dup };
addCommand($40ca, $08) { getfield int +$08 [Class.modifiers: int] };
addCommand($500b, $80000000) { load int $80000000 };
addCommand($1060) { or int };
addCommand($40da, $08) { setfield int +$08 [Class.modifiers: int] };
addCommand($102f) { load null };
addCommand($40d7, $30) { setfield object +$30 [Class.initializingThread: Thread] };
addCommand($30e0, $0002) { load [ebp + $20] <return address> };
end else begin
addCommand($1012) { dup };
addCommand($30e0, $0001) { load [ebp + $10] <return address> };
end;
end;
addCommand($21fa) { dec int };
addCommand($211f) { setarraylength [Throwable.address: int] };
addCommand($2157) { runexcept object };
{ Настройка меток }
for index := 0 to icount - 1 do begin
pc := code.getInstructionOffset(index);
opcode := code.unsignedByteAt(pc);
case opcode of
$99..$a7, $c6..$c8: begin
{ if, goto }
if opcode <> $c8 then begin
i := pc + code.shortAt(pc + 1);
end else begin
i := pc + code.intAt(pc + 1);
end;
i := commandIndices[code.indexOfInstruction(i)];
j := commandIndices[index];
commands[j] := commands[j] + ((long(i) - long(j) - 1) shl 16);
end;
$aa: begin
{ tableswitch }
pco := pc;
repeat
inc(pc);
until (pc and 3) = 0;
i := commandIndices[code.indexOfInstruction(pco + code.intAt(pc))];
j := commandIndices[index] + 2;
commands[j] := buildLong(int(commands[j]), i - j - 1);
inc(j);
intValue1 := code.intAt(pc + 4);
intValue2 := code.intAt(pc + 8);
inc(pc, 12);
for intValue1 := intValue1 to intValue2 do begin
i := commandIndices[code.indexOfInstruction(pco + code.intAt(pc))];
commands[j] := buildLong(int(commands[j]), i - j - 1);
inc(j);
inc(pc, 4);
end;
end;
$ab: begin
{ lookupswitch }
pco := pc;
repeat
inc(pc);
until (pc and 3) = 0;
i := commandIndices[code.indexOfInstruction(pco + code.intAt(pc))];
j := commandIndices[index] + 1;
commands[j] := buildLong(int(commands[j]), i - j - 1);
inc(j, 2);
intValue1 := code.intAt(pc + 4);
inc(pc, 12);
for intValue1 := intValue1 downto 1 do begin
i := commandIndices[code.indexOfInstruction(pco + code.intAt(pc))];
commands[j] := buildLong(int(commands[j]), i - j - 1);
inc(j, 2);
inc(pc, 8);
end;
end;
end;
end;
end;
procedure JavaMethod.fillStringPool();
var
i: int;
index: int;
cmd: long;
commands: long_Array1d;
owner: JavaClass;
compiler: JavaStaticRecompiler;
str: AnsiString;
begin
commands := self.commands;
owner := getOwner();
compiler := owner.getCompiler();
for i := 0 to commandsCount - 1 do begin
cmd := commands[i];
if (int(cmd) and $0fff) <> $0f00 then begin
continue;
end;
str := (owner.getConstantPoolEntry(int(cmd shr 16)) as StringEntry).stringValue();
index := compiler.getStringPoolStringIndex(str);
if index < $80 then begin
commands[i] := long($2009) + (long(index) shl 16);
end else
if index < $8000 then begin
commands[i] := long($300a) + (long(index) shl 16);
end else begin
commands[i] := long($500b) + (long(index) shl 16);
end;
end;
end;
procedure JavaMethod.writeCode(stream: DataOutput);
begin
getCompiler().writeCode(stream, commands, commandsCount, getOffset(), getOwner());
end;
function JavaMethod.reduceSizeofJumps(): boolean;
begin
result := getCompiler().reduceSizeofJumps(commands, commandsCount);
end;
function JavaMethod.reduceSizeofCalls(): boolean;
begin
result := getCompiler().reduceSizeofCalls(commands, commandsCount, getOffset(), getOwner());
end;
function JavaMethod.getRelativeOffset(javaInstructionOffset: int): int;
var
index: int;
begin
if sourceCode = nil then begin
result := -1;
exit;
end;
index := sourceCode.indexOfInstruction(javaInstructionOffset);
if index < 0 then begin
result := -1;
exit;
end;
result := computeCodeSize(commands, 0, commandIndices[index]);
end;
procedure JavaMethod.onAddAttribute(attribute: JavaAttribute);
begin
if (sourceCode = nil) and (attribute is JavaCode) then begin
sourceCode := JavaCode(attribute);
end;
end;
function JavaMethod.getAttributeClass(const name: AnsiString): JavaAttribute_Class;
begin
if (sourceCode = nil) and (name = 'Code') then begin
result := JavaCode;
end else begin
result := nil;
end;
end;
function JavaMethod.getCodeSize(): int;
begin
result := computeCodeSize(commands, 0, commandsCount);
if (result and $03) <> 0 then begin
result := (result and (-$04)) + $04;
end;
end;
function JavaMethod.getParametersCount(): int;
begin
result := parametersCount;
end;
function JavaMethod.getVirtualIndex(): int;
begin
result := virtualIndex;
end;
function JavaMethod.getOverridden(): JavaMethod;
begin
if virtualStatus = VIRTUAL_STATUS_NOT_DEFINED then begin
defineVirtualStatus();
end;
result := overridden;
end;
function JavaMethod.getLineNumberTable(): JavaLineNumberTable;
begin
if sourceCode <> nil then begin
result := sourceCode.getLineNumberTable();
end else begin
result := nil;
end;
end;
function JavaMethod.isSynchronized(): boolean;
begin
result := (getFlags() and FLAG_SYNCHRONIZED) <> 0;
end;
function JavaMethod.isStrictfp(): boolean;
begin
result := (getFlags() and FLAG_STRICTFP) <> 0;
end;
function JavaMethod.isAbstract(): boolean;
begin
result := (getFlags() and FLAG_ABSTRACT) <> 0;
end;
function JavaMethod.isVirtual(): boolean;
begin
if virtualStatus = VIRTUAL_STATUS_NOT_DEFINED then begin
defineVirtualStatus();
end;
result := virtualStatus = VIRTUAL_STATUS_HAS_VIRTUAL;
end;
function JavaMethod.isNative(): boolean;
begin
result := (getFlags() and FLAG_NATIVE) <> 0;
end;
{%endregion}
{%region JavaClass }
class procedure JavaClass.writeClassReference(stream: DataOutput; cls: JavaClass);
begin
if cls <> nil then begin
stream.writeIntLE(cls.getOffset());
end else begin
stream.writeIntLE(0);
end;
end;
class function JavaClass.getClassSignature(const name: AnsiString): AnsiString;
begin
if (length(name) > 0) and (name[1] = PREFIX_ARRAY) then begin
result := name;
end else begin
result := PREFIX_OBJECT + name + SUFFIX_OBJECT;
end;
end;
constructor JavaClass.create(owner: JavaStaticRecompiler; const constantPool: ConstantPoolEntry_Array1d; flags: int; const name, ancestor: AnsiString; const interfaces: AnsiString_Array1d);
var
len: int;
i: int;
p: int;
s: AnsiString;
intf: InterfaceImplementsInfo_Array1d;
begin
inherited create(nil, flags, name, JavaClass.getClassSignature(name));
len := length(name);
p := 0;
s := copy(name, 1, len);
for i := len downto 1 do begin
if name[i] = SEPARATOR_PACKAGES then begin
s[i] := SEPARATOR_CANONICAL;
if (name[1] <> PREFIX_ARRAY) and (p = 0) then begin
p := i;
end;
end;
end;
len := length(interfaces);
intf := InterfaceImplementsInfo_Array1d_create(len);
for i := len - 1 downto 0 do begin
intf[i] := InterfaceImplementsInfo.create(interfaces[i]);
end;
self.owner := owner;
self.packageName := copy(s, 1, max(0, p - 1));
self.outputName := s;
self.ancestorName := ancestor;
self.constantPoolLength := length(constantPool);
self.constantPool := constantPool;
self.interfacesCount := length(interfaces);
self.interfaces := intf;
end;
constructor JavaClass.create(owner: JavaStaticRecompiler; nameIndex: int);
begin
inherited create(nil, FLAG_PRIMITIVE + FLAG_FINAL + FLAG_PUBLIC, PRIMITIVES_NAMES[nameIndex], PRIMITIVES_PREFIXES[nameIndex]);
self.owner := owner;
self.packageName := '';
self.outputName := PRIMITIVES_NAMES[nameIndex];
self.ancestorName := CLASS_OBJECT;
self.constantPoolLength := 0;
self.constantPool := nil;
self.interfacesCount := 0;
self.interfaces := nil;
end;
destructor JavaClass.destroy;
var
i: int;
cnpl: ConstantPoolEntry_Array1d;
intf: InterfaceImplementsInfo_Array1d;
flds: JavaField_Array1d;
mthd: JavaMethod_Array1d;
begin
cnpl := constantPool;
for i := constantPoolLength - 1 downto 0 do begin
cnpl[i].free();
end;
intf := interfaces;
for i := interfacesCount - 1 downto 0 do begin
intf[i].free();
end;
flds := fields;
for i := fieldsCount - 1 downto 0 do begin
flds[i].free();
end;
mthd := methods;
for i := methodsCount - 1 downto 0 do begin
mthd[i].free();
end;
sourceFile.free();
inherited destroy;
end;
procedure JavaClass.addMethod(method: JavaMethod);
var
count: int;
methods: JavaMethod_Array1d;
begin
count := self.methodsCount;
methods := self.methods;
if count = length(methods) then begin
methods := JavaMethod_Array1d_create(count + 16);
arraycopy(self.methods, 0, methods, 0, count);
self.methods := methods;
end;
methods[count] := method;
self.methodsCount := count + 1;
end;
procedure JavaClass.addInterface(intf: JavaClass);
var
count: int;
interfaces: InterfaceImplementsInfo_Array1d;
begin
count := self.interfacesCount;
interfaces := self.interfaces;
if count = length(interfaces) then begin
interfaces := InterfaceImplementsInfo_Array1d_create(count + 4);
arraycopy(self.interfaces, 0, interfaces, 0, count);
self.interfaces := interfaces;
end;
interfaces[count] := InterfaceImplementsInfo.create(intf);
self.interfacesCount := count + 1;
end;
function JavaClass.findVirtualMethod(virtualIndex: int): JavaMethod;
var
i: int;
cls: JavaClass;
method: JavaMethod;
methods: JavaMethod_Array1d;
begin
cls := self;
repeat
methods := cls.methods;
for i := cls.methodsCount - 1 downto 0 do begin
method := methods[i];
if (method.isVirtual()) and (method.getVirtualIndex() = virtualIndex) then begin
result := method;
exit;
end;
end;
cls := cls.ancestor;
until (cls = nil) or (cls = self);
result := nil;
end;
function JavaClass.getRefFieldsOffsets(): int_Array1d;
var
i: int;
len: int;
old: int_Array1d;
cls: JavaClass;
field: JavaField;
fields: JavaField_Array1d;
signature: AnsiString;
begin
result := int_Array1d_create(15);
len := 0;
cls := self;
repeat
fields := cls.fields;
for i := cls.fieldsCount - 1 downto 0 do begin
field := fields[i];
signature := field.getSignature();
if not field.isStatic() and (length(signature) > 0) and (signature[1] in [PREFIX_OBJECT, PREFIX_ARRAY]) then begin
if len = length(result) then begin
old := result;
result := int_Array1d_create((len shl 1) + 1);
arraycopy(old, 0, result, 0, len);
end;
result[len] := field.getOffset();
inc(len);
end;
end;
cls := cls.ancestor;
until cls = nil;
if len <> length(result) then begin
old := result;
result := int_Array1d_create(len);
arraycopy(old, 0, result, 0, len);
end;
end;
procedure JavaClass.findAncestors();
var
i: int;
name: AnsiString;
info: InterfaceImplementsInfo;
intf: InterfaceImplementsInfo_Array1d;
compiler: JavaStaticRecompiler;
begin
compiler := owner;
name := ancestorName;
if length(name) > 0 then begin
ancestor := compiler.findClassByName(name);
end;
intf := interfaces;
for i := interfacesCount - 1 downto 0 do begin
info := intf[i];
info.setInterface(compiler.findClassByName(info.getInterfaceName()));
end;
end;
procedure JavaClass.defineImplementedMethods();
var
i: int;
j: int;
intf: JavaClass;
subIntf: JavaClass;
interfaceImplements: InterfaceImplementsInfo;
methodImplements: InterfaceMethodImplements;
method: JavaMethod;
name: AnsiString;
signature: AnsiString;
begin
if isInterface() then begin
i := 0;
while i < interfacesCount do begin
intf := interfaces[i].getInterface();
for j := intf.getInterfacesCount() - 1 downto 0 do begin
subIntf := intf.getInterface(j);
if not isInheritedFrom(subIntf) then begin
addInterface(subIntf);
end;
end;
inc(i);
end;
exit;
end;
i := 0;
while i < interfacesCount do begin
interfaceImplements := interfaces[i];
for j := interfaceImplements.getMethodsCount() - 1 downto 0 do begin
methodImplements := interfaceImplements.getMethodImplements(j);
name := methodImplements.getMethodName();
signature := methodImplements.getMethodSignature();
method := findMember(name, signature) as JavaMethod;
if method.getOwner().isInterface() then begin
method := JavaMethod.create(self, FLAG_PUBLIC + FLAG_ABSTRACT, name, signature);
addMethod(method);
end;
methodImplements.setClassMethod(method);
end;
intf := interfaceImplements.getInterface();
for j := intf.getInterfacesCount() - 1 downto 0 do begin
subIntf := intf.getInterface(j);
if not isInheritedFrom(subIntf) then begin
addInterface(subIntf);
end;
end;
inc(i);
end;
end;
procedure JavaClass.defineVirtualMethods();
var
i: int;
count: int;
virtualIndex: int;
ancestor: JavaClass;
overridden: JavaMethod;
method: JavaMethod;
methods: JavaMethod_Array1d;
begin
virtualIndex := 0;
count := self.methodsCount;
methods := self.methods;
if isInterface() then begin
for i := 0 to count - 1 do begin
method := methods[i];
if method.isAbstract() then begin
method.setVirtualIndex(virtualIndex);
inc(virtualIndex);
end;
end;
exit;
end;
ancestor := self.ancestor;
if ancestor <> nil then begin
virtualIndex := ancestor.virtualsCount;
end;
for i := 0 to count - 1 do begin
method := methods[i];
if not method.isVirtual() then begin
continue;
end;
overridden := method.getOverridden();
if overridden = nil then begin
method.setVirtualIndex(virtualIndex);
inc(virtualIndex);
end else begin
method.setVirtualIndex(overridden.getVirtualIndex());
end;
end;
self.virtualsCount := virtualIndex;
end;
procedure JavaClass.defineFieldOffsets();
var
i: int;
count: int;
offset: int;
ancestor: JavaClass;
field: JavaField;
fields: JavaField_Array1d;
compiler: JavaStaticRecompiler;
begin
compiler := self.owner;
ancestor := self.ancestor;
if ancestor <> nil then begin
offset := ancestor.instanceSize;
end else begin
offset := -4;
end;
count := self.fieldsCount;
fields := self.fields;
for i := 0 to count - 1 do begin
field := fields[i];
if field.isStatic() then begin
continue;
end;
field.setOffset(offset);
inc(offset, compiler.getTypeSize(field.getSignature()));
end;
self.instanceSize := offset;
end;
procedure JavaClass.writeIMTs(stream: DataOutput);
var
i: int;
j: int;
k: int;
s: int;
imtOffset: int;
interfaces: InterfaceImplementsInfo_Array1d;
implements: InterfaceImplementsInfo;
methodimpl: InterfaceMethodImplements;
classMethod: JavaMethod;
begin
if isInterface() then begin
exit;
end;
interfaces := self.interfaces;
for i := 0 to interfacesCount - 1 do begin
implements := interfaces[i];
imtOffset := implements.getIMTOffset();
for j := 0 to implements.getMethodsCount() - 1 do begin
methodimpl := implements.getMethodImplements(j);
classMethod := methodimpl.getClassMethod();
if classMethod.isVirtual() then begin
{ load object [esp + classMethod.getParametersCount() * $10] }
stream.writeByte($47);
stream.writeShortLE(classMethod.getParametersCount());
{ getclass }
stream.writeByte($cf);
{ getfield object +$18 }
stream.writeIntLE($000018c7);
{ load int classMethod.getVirtualIndex() }
stream.writeByte($0b);
stream.writeIntLE(classMethod.getVirtualIndex());
{ getarraycell int }
stream.writeShort($ff0a);
{ jmp int }
stream.writeByte($b8);
continue;
end;
s := classMethod.getOffset() - (imtOffset + j * IMT_ENTRY_SIZE + 2);
if (s >= -$80) and (s < $80) then begin
{ jmp ±$xx }
stream.writeByte($b0);
stream.writeByte(s);
for k := 2 to IMT_ENTRY_SIZE - 1 do begin
stream.writeByte($00);
end;
continue;
end;
dec(s);
if (s >= -$8000) and (s < $8000) then begin
{ jmp ±$jjii }
stream.writeByte($b1);
stream.writeShortLE(s);
for k := 3 to IMT_ENTRY_SIZE - 1 do begin
stream.writeByte($00);
end;
continue;
end;
{ jmp ±$llkkjjii }
stream.writeByte($b2);
stream.writeIntLE(s - 2);
for k := 5 to IMT_ENTRY_SIZE - 1 do begin
stream.writeByte($00);
end;
end;
end;
end;
procedure JavaClass.writeData(stream: DataOutput);
var
method: JavaMethod;
compiler: JavaStaticRecompiler;
interfaces: InterfaceImplementsInfo_Array1d;
intf: InterfaceImplementsInfo;
cls: JavaClass;
refOffsets: int_Array1d;
classInstanceSize: int;
refOffsetsCount: int;
offset: int;
i: int;
j: int;
begin
compiler := getCompiler();
cls := compiler.classClass;
refOffsets := getRefFieldsOffsets();
classInstanceSize := cls.getInstanceSize();
refOffsetsCount := length(refOffsets);
offset := getOffset() + classInstanceSize;
{ записываем инстанцию класса java.lang.Class }
stream.writeIntLE(0);
stream.writeIntLE(0);
stream.writeIntLE(cls.getOffset());
stream.writeIntLE(getFlags());
stream.writeIntLE(getInstanceSize());
stream.writeIntLE(nameIndex);
stream.writeIntLE(offset + 4);
stream.writeIntLE(offset + (20 + refOffsetsCount * 4) + 4);
stream.writeIntLE(0);
stream.writeIntLE(offset + (20 + refOffsetsCount * 4) + (20 + virtualsCount * 4) + 4);
writeClassReference(stream, ancestor);
writeClassReference(stream, getComponentClass());
writeClassReference(stream, next);
for i := $30 to classInstanceSize - 1 do begin
stream.writeByte(0);
end;
{ записываем инстанцию класса int[] (на неё ссылается поле refOffsets) }
stream.writeIntLE(0);
stream.writeIntLE(1);
writeClassReference(stream, compiler.findClassBySignature(PREFIX_ARRAY + PREFIX_INT));
stream.writeIntLE(refOffsetsCount);
stream.writeIntLE(0);
for i := 0 to refOffsetsCount - 1 do begin
stream.writeIntLE(refOffsets[i]);
end;
{ записываем инстанцию класса int[] (на неё ссылается поле virtualsAddresses) }
stream.writeIntLE(0);
stream.writeIntLE(1);
writeClassReference(stream, compiler.findClassBySignature(PREFIX_ARRAY + PREFIX_INT));
stream.writeIntLE(virtualsCount);
stream.writeIntLE(0);
for i := 0 to virtualsCount - 1 do begin
method := findVirtualMethod(i);
if method.isAbstract() then begin
method := compiler.methodThrowAbstractMethodError as JavaMethod;
end;
stream.writeIntLE(method.getOffset());
end;
{ записываем инстанцию класса java.lang.InterfaceEntry[] (на неё ссылается поле interfaces) }
inc(offset, (20 + refOffsetsCount * 4) + (20 + virtualsCount * 4) + (20 + interfacesCount * 4));
stream.writeIntLE(0);
stream.writeIntLE(1);
writeClassReference(stream, compiler.findClassBySignature(PREFIX_ARRAY + PREFIX_OBJECT + CLASS_INTERFACE_ENTRY + SUFFIX_OBJECT));
stream.writeIntLE(interfacesCount);
stream.writeIntLE(0);
cls := compiler.findClassByName(CLASS_INTERFACE_ENTRY);
j := cls.getInstanceSize() + 4;
for i := 0 to interfacesCount - 1 do begin
stream.writeIntLE(offset + (i * j) + 4);
end;
{ записываем инстанции класса java.lang.InterfaceEntry }
interfaces := self.interfaces;
for i := 0 to interfacesCount - 1 do begin
intf := interfaces[i];
stream.writeIntLE(0);
stream.writeIntLE(1);
writeClassReference(stream, cls);
stream.writeIntLE(intf.getIMTOffset());
writeClassReference(stream, intf.getInterface());
end;
end;
procedure JavaClass.setMembers(const fields: JavaField_Array1d; const methods: JavaMethod_Array1d);
var
f: boolean;
i: int;
m: JavaClassMember;
s: AnsiString;
begin
f := false;
for i := length(methods) - 1 downto 0 do begin
m := methods[i];
if (not m.isStatic()) and (m.getAccess() >= ACCESS_PROTECTED) and (m.getName() = NAME_FINALIZE) and (m.getSignature() = SIGNATURE_NO_PARAMETERS) then begin
f := true;
break;
end;
end;
if not f then begin
for i := length(fields) - 1 downto 0 do begin
m := fields[i];
s := m.getSignature();
if (not m.isStatic()) and (length(s) > 0) and (s[1] in [PREFIX_ARRAY, PREFIX_OBJECT]) then begin
f := true;
break;
end;
end;
end else begin
f := false;
end;
self.fieldsCount := length(fields);
self.fields := fields;
if f then begin
i := length(methods);
self.methodsCount := i + 1;
self.methods := JavaMethod_Array1d_create(i + 16);
if i > 0 then begin
arraycopy(methods, 0, self.methods, 0, i);
end;
m := JavaMethod.create(self, FLAG_PROTECTED, NAME_FINALIZE, SIGNATURE_NO_PARAMETERS);
m.onAddAttribute(JavaCode.create(m, 'Code', toByteArray1d([
byte($00), byte($00), byte($00), byte($01), byte($00), byte($00), byte($00), byte($01),
byte($b1), byte($00), byte($00), byte($00), byte($00)
]), constantPool));
self.methods[i] := JavaMethod(m);
end else begin
self.methodsCount := length(methods);
self.methods := methods;
end;
end;
procedure JavaClass.setNameIndex(nameIndex: int);
begin
self.nameIndex := nameIndex;
end;
procedure JavaClass.setNextClass(next: JavaClass);
begin
self.next := next;
end;
procedure JavaClass.setIMTOffset(interfaceIndex, imtOffset: int);
begin
if (interfaceIndex < 0) or (interfaceIndex >= interfacesCount) then begin
raise ArrayIndexOutOfBoundsException.create(interfaceIndex);
end;
interfaces[interfaceIndex].setIMTOffset(imtOffset);
end;
function JavaClass.getIMTOffset(interfaceIndex: int): int;
begin
if (interfaceIndex < 0) or (interfaceIndex >= interfacesCount) then begin
raise ArrayIndexOutOfBoundsException.create(interfaceIndex);
end;
result := interfaces[interfaceIndex].getIMTOffset();
end;
function JavaClass.findMember(const name, signature: AnsiString): JavaClassMember;
var
i: int;
cls: JavaClass;
intf: InterfaceImplementsInfo_Array1d;
begin
cls := self;
repeat
result := cls.findMemberInternal(name, signature);
if result <> nil then begin
exit;
end;
cls := cls.ancestor;
until (cls = nil) or (cls = self);
cls := self;
repeat
intf := cls.interfaces;
for i := cls.interfacesCount - 1 downto 0 do begin
result := intf[i].getInterface().findMemberInternal(name, signature);
if result <> nil then begin
exit;
end;
end;
cls := cls.ancestor;
until (cls = nil) or (cls = self);
end;
function JavaClass.findMemberInternal(const name, signature: AnsiString): JavaClassMember;
var
i: int;
member: JavaClassMember;
fields: JavaField_Array1d;
methods: JavaMethod_Array1d;
begin
if (length(signature) > 0) and (signature[1] = HEADER_PREFIX) then begin
methods := self.methods;
for i := methodsCount - 1 downto 0 do begin
member := methods[i];
if (member.getName() = name) and (member.getSignature() = signature) then begin
result := member;
exit;
end;
end;
end else begin
fields := self.fields;
for i := fieldsCount - 1 downto 0 do begin
member := fields[i];
if (member.getName() = name) and (member.getSignature() = signature) then begin
result := member;
exit;
end;
end;
end;
result := nil;
end;
procedure JavaClass.onAddAttribute(attribute: JavaAttribute);
begin
if (sourceFile = nil) and (attribute is JavaConstantValue) then begin
sourceFile := JavaConstantValue(attribute);
end;
end;
function JavaClass.getAttributeClass(const name: AnsiString): JavaAttribute_Class;
begin
if (sourceFile = nil) and (name = 'SourceFile') then begin
result := JavaConstantValue;
end else begin
result := nil;
end;
end;
function JavaClass.getCompiler(): JavaStaticRecompiler;
begin
result := owner;
end;
function JavaClass.getComponentClass(): JavaClass;
begin
result := nil;
end;
function JavaClass.getInstanceSize(): int;
begin
if isInterface() then begin
result := 0;
end else begin
result := instanceSize;
end;
end;
function JavaClass.getLongIndex(value: long): int;
var
i: int;
count: int;
constantPool: ConstantPoolEntry_Array1d;
entry: ConstantPoolEntry;
begin
count := self.constantPoolLength;
constantPool := self.constantPool;
for i := count - 1 downto 0 do begin
entry := constantPool[i];
if (entry is LongEntry) and (LongEntry(entry).longValue() = value) then begin
result := i;
exit;
end;
end;
if count = length(constantPool) then begin
constantPool := ConstantPoolEntry_Array1d_create(count * 2 + 1);
arraycopy(self.constantPool, 0, constantPool, 0, count);
self.constantPool := constantPool;
end;
constantPool[count] := LongEntry.create(value);
self.constantPoolLength := count + 1;
result := count;
end;
function JavaClass.getDoubleIndex(value: double): int;
var
i: int;
count: int;
bits: long;
constantPool: ConstantPoolEntry_Array1d;
entry: ConstantPoolEntry;
begin
count := self.constantPoolLength;
constantPool := self.constantPool;
bits := doubleToLongBits(value);
for i := count - 1 downto 0 do begin
entry := constantPool[i];
if (entry is DoubleEntry) and (doubleToLongBits(DoubleEntry(entry).doubleValue()) = bits) then begin
result := i;
exit;
end;
end;
if count = length(constantPool) then begin
constantPool := ConstantPoolEntry_Array1d_create(count * 2 + 1);
arraycopy(self.constantPool, 0, constantPool, 0, count);
self.constantPool := constantPool;
end;
constantPool[count] := DoubleEntry.create(value);
self.constantPoolLength := count + 1;
result := count;
end;
function JavaClass.getStringIndex(const value: AnsiString): int;
var
i: int;
count: int;
constantPool: ConstantPoolEntry_Array1d;
entry: ConstantPoolEntry;
begin
count := self.constantPoolLength;
constantPool := self.constantPool;
for i := count - 1 downto 0 do begin
entry := constantPool[i];
if (entry is StringEntry) and (StringEntry(entry).stringValue() = value) then begin
result := i;
exit;
end;
end;
if count = length(constantPool) then begin
constantPool := ConstantPoolEntry_Array1d_create(count * 2 + 1);
arraycopy(self.constantPool, 0, constantPool, 0, count);
self.constantPool := constantPool;
end;
constantPool[count] := StringEntry.create(value);
self.constantPoolLength := count + 1;
result := count;
end;
function JavaClass.getConstantPoolLength(): int;
begin
result := constantPoolLength;
end;
function JavaClass.getConstantPoolEntry(index: int): ConstantPoolEntry;
begin
if (index < -5) or (index >= constantPoolLength) then begin
raise ArrayIndexOutOfBoundsException.create(index);
end;
if index >= 0 then begin
result := constantPool[index];
end else begin
result := owner.getConstantPoolEntry(index);
end;
end;
function JavaClass.getConstantPoolMember(index, memberType: int): JavaClassMember;
var
e1: ConstantPoolEntry;
e2: ConstantPoolEntry;
begin
e2 := getConstantPoolEntry(index);
e1 := getConstantPoolEntry((e2 as DoubleIndexedEntry).getIndex1());
e2 := getConstantPoolEntry((e2 as DoubleIndexedEntry).getIndex2());
result := getConstantPoolMember((e1 as SingleIndexedEntry).getIndex1(), (e2 as DoubleIndexedEntry).getIndex1(), (e2 as DoubleIndexedEntry).getIndex2(), memberType);
end;
function JavaClass.getConstantPoolMember(classNameIndex, memberNameIndex, memberSignatureIndex, memberType: int): JavaClassMember;
var
constantPool: ConstantPoolEntry_Array1d;
className: AnsiString;
memberName: AnsiString;
memberSignature: AnsiString;
begin
constantPool := self.constantPool;
className := (constantPool[classNameIndex] as StringEntry).stringValue();
memberName := (constantPool[memberNameIndex] as StringEntry).stringValue();
memberSignature := (constantPool[memberSignatureIndex] as StringEntry).stringValue();
result := getCompiler().findClassByName(className).findMember(memberName, memberSignature);
if result = nil then begin
if (memberType = MEMBER_TYPE_STATIC_FIELD) or (memberType = MEMBER_TYPE_INSTANCE_FIELD) then begin
memberSignature := ': ' + memberSignature;
end;
raise ClassMemberNotFoundException.create('Не удалось найти ' + MEMBER_TYPES[memberType] + ': ' + className + '.' + memberName + memberSignature);
end;
end;
function JavaClass.getPackageName(): AnsiString;
begin
result := packageName;
end;
function JavaClass.getOutputName(): AnsiString;
begin
result := outputName;
end;
function JavaClass.getAncestor(): JavaClass;
begin
result := ancestor;
end;
function JavaClass.getInterfacesCount(): int;
begin
result := interfacesCount;
end;
function JavaClass.getInterfaceImplements(index: int): InterfaceImplementsInfo;
begin
if (index < 0) or (index >= interfacesCount) then begin
raise ArrayIndexOutOfBoundsException.create(index);
end;
result := interfaces[index];
end;
function JavaClass.getInterface(index: int): JavaClass;
begin
if (index < 0) or (index >= interfacesCount) then begin
raise ArrayIndexOutOfBoundsException.create(index);
end;
result := interfaces[index].getInterface();
end;
function JavaClass.getAbstractMethodsCount(): int;
var
i: int;
m: JavaMethod_Array1d;
begin
result := 0;
m := methods;
for i := methodsCount - 1 downto 0 do begin
if m[i].isAbstract() then begin
inc(result);
end;
end;
end;
function JavaClass.getMethodsCount(): int;
begin
result := methodsCount;
end;
function JavaClass.getMethod(index: int): JavaMethod;
begin
if (index < 0) or (index >= methodsCount) then begin
raise ArrayIndexOutOfBoundsException.create(index);
end;
result := methods[index];
end;
function JavaClass.getFieldsCount(): int;
begin
result := fieldsCount;
end;
function JavaClass.getField(index: int): JavaField;
begin
if (index < 0) or (index >= fieldsCount) then begin
raise ArrayIndexOutOfBoundsException.create(index);
end;
result := fields[index];
end;
function JavaClass.getSourceFile(): AnsiString;
var
i: int;
s: JavaConstantValue;
e: ConstantPoolEntry;
begin
s := sourceFile;
if s <> nil then begin
i := s.getConstantPoolIndex();
if (i >= 0) and (i < constantPoolLength) then begin
e := constantPool[i];
if e is StringEntry then begin
result := StringEntry(e).stringValue();
exit;
end;
end;
end;
result := UNKNOWN_SOURCE;
end;
function JavaClass.getDataSize(): int;
var
compiler: JavaStaticRecompiler;
begin
compiler := owner;
result := (4 + compiler.classClass.instanceSize) + (20 + (length(getRefFieldsOffsets()) shl 2)) + (20 + (virtualsCount shl 2)) + (20 + (compiler.classInterfaceEntry.instanceSize + 8) * interfacesCount);
end;
function JavaClass.isDirectSuperClass(ancestor: JavaClass): boolean;
var
i: int;
begin
if (ancestor <> nil) and (ancestor.isInterface()) then begin
for i := interfacesCount - 1 downto 0 do begin
if interfaces[i].getInterface() = ancestor then begin
result := true;
exit;
end;
end;
result := false;
exit;
end;
result := self.ancestor = ancestor;
end;
function JavaClass.isInheritedFrom(cls: JavaClass): boolean;
var
i: int;
c: JavaClass;
intf: InterfaceImplementsInfo_Array1d;
begin
result := cls = self;
if not result then begin
c := self;
if cls.isInterface() then begin
repeat
intf := c.interfaces;
for i := c.interfacesCount - 1 downto 0 do begin
if intf[i].getInterface() = cls then begin
result := true;
exit;
end;
end;
c := c.ancestor;
until (c = nil) or (c = self);
end else begin
repeat
if c = cls then begin
result := true;
exit;
end;
c := c.ancestor;
until (c = nil) or (c = self);
end;
end;
end;
function JavaClass.isPrimitive(): boolean;
begin
result := (getFlags() and FLAG_PRIMITIVE) <> 0;
end;
function JavaClass.isInterface(): boolean;
begin
result := (getFlags() and FLAG_INTERFACE) <> 0;
end;
function JavaClass.isAbstract(): boolean;
begin
result := (getFlags() and FLAG_ABSTRACT) <> 0;
end;
{%endregion}
{%region JavaArray }
constructor JavaArray.create(owner: JavaStaticRecompiler; componentClass: JavaClass);
begin
inherited create(owner, nil, (FLAG_FINAL or FLAG_STATIC) or (componentClass.getFlags() and (FLAG_PUBLIC or FLAG_PRIVATE or FLAG_PROTECTED)), PREFIX_ARRAY + componentClass.getSignature(), CLASS_OBJECT, nil);
self.componentClass := componentClass;
end;
function JavaArray.getComponentClass(): JavaClass;
begin
result := componentClass;
end;
function JavaArray.getInstanceSize(): int;
begin
result := 16;
end;
function JavaArray.getCellClass(): JavaClass;
var
cls: JavaClass;
begin
result := cellClass;
if result = nil then begin
cls := componentClass;
while cls is JavaArray do begin
cls := JavaArray(cls).componentClass;
end;
cellClass := cls;
result := cls;
end;
end;
function JavaArray.getDimensionsCount(): int;
var
cls: JavaClass;
begin
result := dimensionsCount;
if result = 0 then begin
result := 1;
cls := componentClass;
while cls is JavaArray do begin
cls := JavaArray(cls).componentClass;
inc(result);
end;
dimensionsCount := result;
end;
end;
{%endregion}
{%region JavaStaticRecompiler }
procedure JavaStaticRecompiler.writeToTextDebugInfoFile(stream: DataOutput; cls: JavaClass);
begin
stream.writeChars(globalOffsetToString(cls.getOffset()) + '=class: ' + cls.getSignature());
cls := cls.getAncestor();
if cls <> nil then begin
stream.writeChars(' : ' + cls.getSignature() + LINE_ENDING);
end else begin
stream.writeChars(LINE_ENDING);
end;
end;
constructor JavaStaticRecompiler.create();
var
manifestInput: Input;
manifest: ProgrammeManifest;
coreJarArchive: ZIPArchiveReader;
coreJarFileName: AnsiString;
configuration: AnsiString;
profile: AnsiString;
i: int;
begin
inherited create();
coreDirectory := '';
coreJarFileName := parseParams()[0];
for i := length(coreJarFileName) downto 1 do begin
if coreJarFileName[i] = DIRECTORY_SEPARATOR then begin
coreDirectory := copy(coreJarFileName, 1, i) + ('java' + DIRECTORY_SEPARATOR);
coreJarFileName := coreDirectory + 'malik-core.jar';
break;
end;
end;
coreJarArchive := ZIPArchiveReader.create(FileInputStream.create(coreJarFileName));
try
manifestInput := coreJarArchive.openFile(MANIFEST_FILE_NAME);
if manifestInput <> nil then begin
manifest := ProgrammeManifest.create();
try
manifest.loadFromStream(manifestInput);
configuration := manifest.getValue(MANIFEST_PROPERTY_MIDLET_CONFIGURATION);
profile := manifest.getValue(MANIFEST_PROPERTY_MIDLET_PROFILE);
if (length(configuration) > 0) and (length(profile) > 0) then begin
platformName := 'Java (J2ME, ' + configuration + ', ' + profile + ')';
end else begin
platformName := 'Java (неопределённой редакции)';
end;
finally
manifest.free();
end;
end else begin
platformName := 'Java (неопределённой редакции)';
end;
finally
coreJarArchive.free();
end;
init();
end;
constructor JavaStaticRecompiler.create(const coreDirectory, platformName: AnsiString);
begin
inherited create();
self.coreDirectory := coreDirectory;
self.platformName := platformName;
init();
end;
destructor JavaStaticRecompiler.destroy;
var
i: int;
a: ConstantPoolEntry_Array1d;
p: JavaClass_Array1d;
begin
p := primitives;
for i := length(p) - 1 downto 0 do begin
p[i].free();
end;
a := fdconst;
for i := length(a) - 1 downto 0 do begin
a[i].free();
end;
strings.free();
initOrder.free();
inherited destroy;
end;
procedure JavaStaticRecompiler.init();
var
i: int;
p: JavaClass_Array1d;
begin
i := length(PRIMITIVES_NAMES);
p := JavaClass_Array1d_create(i);
for i := i - 1 downto 0 do begin
p[i] := JavaClass.create(self, i);
end;
primitives := p;
fdconst := toConstantPoolEntryArray1d([
FloatEntry.create(0.0), FloatEntry.create(1.0), FloatEntry.create(2.0),
DoubleEntry.create(0.0), DoubleEntry.create(1.0)
]);
strings := StringPool.create();
initOrder := StringPool.create();
setDefaults();
end;
procedure JavaStaticRecompiler.loadClassesFrom(archive: ZIPArchiveReader);
begin
archive.gotoFirstFile();
while not archive.isStayOnEnd() do begin
if endsWith(CLASS_FILE_EXTENSION, toLowerCase(archive.getCurrentFileName())) then begin
loadClass(archive.openCurrentFile());
end else begin
archive.gotoNextFile();
end;
end;
end;
procedure JavaStaticRecompiler.loadClass(source: Input);
var
stream: DataInput;
count: int;
i: int;
j: int;
version: int;
constantPool: ConstantPoolEntry_Array1d;
flags: int;
name: AnsiString;
ancestor: AnsiString;
interfaces: AnsiString_Array1d;
fields: JavaField_Array1d;
methods: JavaMethod_Array1d;
cls: JavaClass;
entryType: int;
utf8Constant: AnsiString;
intConstant: int;
longConstant: long;
index1: int;
index2: int;
memberFlags: int;
memberName: AnsiString;
memberSignature: AnsiString;
classes: JavaClass_Array1d;
begin
{ Незначительная уязвимость (возможно уже исправлено): если будет сгенерировано исключение, то возможна утечка памяти. }
stream := DataInputStream.create(source);
{ читаем сигнатуру CLASS-файла }
if stream.readInt() <> int($cafebabe) then begin
exit;
end;
{ читаем версию (максимальная поддерживаемая версия CLASS-файла = 48.0) }
version := stream.readUnsignedShort();
version := (stream.readUnsignedShort() shl 16) + version;
if (version < 0) or (version > $00300000) then begin
raise UnsupportedClassVersionException.create('Неподдерживаемая версия class-файла: ' + toDecString(long(version shr 16)) + '.' + toDecString(long(version and $ffff)) + '.');
end;
cls := nil;
try
{ читаем константы }
count := stream.readUnsignedShort();
constantPool := ConstantPoolEntry_Array1d_create(count);
i := 1;
while i < count do begin
entryType := stream.readByte();
case entryType of
ENTRY_UTF8: begin
utf8Constant := toUTF8String(stream.readUTF());
constantPool[i] := StringEntry.create(utf8Constant);
end;
ENTRY_INTEGER: begin
intConstant := stream.readInt();
constantPool[i] := IntegerEntry.create(intConstant);
end;
ENTRY_FLOAT: begin
intConstant := stream.readInt();
constantPool[i] := FloatEntry.create(intBitsToFloat(intConstant));
end;
ENTRY_LONG: begin
longConstant := stream.readLong();
constantPool[i] := LongEntry.create(longConstant);
inc(i);
end;
ENTRY_DOUBLE: begin
longConstant := stream.readLong();
constantPool[i] := DoubleEntry.create(longBitsToDouble(longConstant));
inc(i);
end;
ENTRY_CLASS, ENTRY_STRING: begin
index1 := stream.readUnsignedShort();
constantPool[i] := SingleIndexedEntry.create(entryType, index1);
end;
ENTRY_FIELD_REF, ENTRY_CLASS_METHOD_REF, ENTRY_INTERFACE_METHOD_REF, ENTRY_NAME_AND_SIGNATURE: begin
index1 := stream.readUnsignedShort();
index2 := stream.readUnsignedShort();
constantPool[i] := DoubleIndexedEntry.create(entryType, index1, index2);
end;
end;
inc(i);
end;
{ читаем флаги }
flags := stream.readUnsignedShort();
{ читаем имя класса }
i := stream.readUnsignedShort();
if (i >= length(constantPool)) or (not (constantPool[i] is SingleIndexedEntry)) then begin
raise ClassFileInvalidFormatException.create('Неправильный формат class-файла: нельзя определить имя класса.');
end;
i := SingleIndexedEntry(constantPool[i]).getIndex1();
if (i >= length(constantPool)) or (not (constantPool[i] is StringEntry)) then begin
raise ClassFileInvalidFormatException.create('Неправильный формат class-файла: нельзя определить имя класса.');
end;
name := StringEntry(constantPool[i]).stringValue();
{ читаем имя класса-предка }
i := stream.readUnsignedShort();
if i >= length(constantPool) then begin
raise ClassFileInvalidFormatException.create('Неправильный формат class-файла: нельзя определить имя класса-предка.');
end;
if i > 0 then begin
if not (constantPool[i] is SingleIndexedEntry) then begin
raise ClassFileInvalidFormatException.create('Неправильный формат class-файла: нельзя определить имя класса-предка.');
end;
i := SingleIndexedEntry(constantPool[i]).getIndex1();
if (i >= length(constantPool)) or (not (constantPool[i] is StringEntry)) then begin
raise ClassFileInvalidFormatException.create('Неправильный формат class-файла: нельзя определить имя класса-предка.');
end;
ancestor := StringEntry(constantPool[i]).stringValue();
end else begin
ancestor := '';
end;
{ читаем реализуемые протоколы }
count := stream.readUnsignedShort();
interfaces := String_Array1d_create(count);
for j := 0 to count - 1 do begin
i := stream.readUnsignedShort();
if (i >= length(constantPool)) or (not (constantPool[i] is SingleIndexedEntry)) then begin
raise ClassFileInvalidFormatException.create('Неправильный формат class-файла: нельзя определить имя протокола.');
end;
i := SingleIndexedEntry(constantPool[i]).getIndex1();
if (i >= length(constantPool)) or (not (constantPool[i] is StringEntry)) then begin
raise ClassFileInvalidFormatException.create('Неправильный формат class-файла: нельзя определить имя протокола.');
end;
interfaces[j] := StringEntry(constantPool[i]).stringValue();
end;
cls := JavaClass.create(self, constantPool, flags, name, ancestor, interfaces);
{ читаем поля }
count := stream.readUnsignedShort();
fields := JavaField_Array1d_create(count);
for j := 0 to count - 1 do begin
memberFlags := stream.readUnsignedShort();
i := stream.readUnsignedShort();
if (i >= length(constantPool)) or (not (constantPool[i] is StringEntry)) then begin
raise ClassFileInvalidFormatException.create('Неправильный формат class-файла: нельзя определить имя поля.');
end;
memberName := StringEntry(constantPool[i]).stringValue();
i := stream.readUnsignedShort();
if (i >= length(constantPool)) or (not (constantPool[i] is StringEntry)) then begin
raise ClassFileInvalidFormatException.create('Неправильный формат class-файла: нельзя определить тип поля.');
end;
memberSignature := StringEntry(constantPool[i]).stringValue();
fields[j] := JavaField.create(cls, memberFlags, memberName, memberSignature);
JavaAttribute.readAttributes(fields[j], stream, constantPool);
end;
{ читаем методы }
count := stream.readUnsignedShort();
methods := JavaMethod_Array1d_create(count);
for j := 0 to count - 1 do begin
memberFlags := stream.readUnsignedShort();
i := stream.readUnsignedShort();
if (i >= length(constantPool)) or (not (constantPool[i] is StringEntry)) then begin
raise ClassFileInvalidFormatException.create('Неправильный формат class-файла: нельзя определить имя метода.');
end;
memberName := StringEntry(constantPool[i]).stringValue();
i := stream.readUnsignedShort();
if (i >= length(constantPool)) or (not (constantPool[i] is StringEntry)) then begin
raise ClassFileInvalidFormatException.create('Неправильный формат class-файла: нельзя определить сигнатуру метода.');
end;
memberSignature := StringEntry(constantPool[i]).stringValue();
methods[j] := JavaMethod.create(cls, memberFlags, memberName, memberSignature);
JavaAttribute.readAttributes(methods[j], stream, constantPool);
end;
except
if cls = nil then begin
for i := length(constantPool) - 1 downto 0 do begin
constantPool[i].free();
end;
end;
for i := length(fields) - 1 downto 0 do begin
fields[i].free();
end;
for i := length(methods) - 1 downto 0 do begin
methods[i].free();
end;
cls.free();
raise;
end;
try
{ читаем атрибуты класса }
cls.setMembers(fields, methods);
JavaAttribute.readAttributes(cls, stream, constantPool);
except
cls.free();
raise;
end;
{ добавляем класс в список }
classes := self.classes;
count := self.classesCount;
if count = length(classes) then begin
classes := JavaClass_Array1d_create(count * 2 + 1);
arraycopy(self.classes, 0, classes, 0, count);
self.classes := classes;
end;
classes[count] := cls;
self.classesCount := count + 1;
end;
procedure JavaStaticRecompiler.addArray(arr: JavaArray);
var
count: int;
arrays: JavaArray_Array1d;
begin
count := self.arraysCount;
arrays := self.arrays;
if count = length(arrays) then begin
arrays := JavaArray_Array1d_create(count * 2 + 1);
arraycopy(self.arrays, 0, arrays, 0, count);
self.arrays := arrays;
end;
arrays[count] := arr;
self.arraysCount := count + 1;
end;
procedure JavaStaticRecompiler.findAncestors();
var
i: int;
classes: JavaClass_Array1d;
begin
classes := self.primitives;
for i := length(classes) - 1 downto 0 do begin
classes[i].findAncestors();
end;
classes := self.classes;
for i := self.classesCount - 1 downto 0 do begin
classes[i].findAncestors();
end;
end;
procedure JavaStaticRecompiler.findSystemMembers();
begin
classObject := findClassByName(CLASS_OBJECT);
classClass := findClassByName(CLASS_CLASS);
classInterfaceEntry := findClassByName(CLASS_INTERFACE_ENTRY);
classMalikSystem := findClassByName(CLASS_MALIK_SYSTEM);
classMath := findClassByName(CLASS_MATH);
interfaceInterrupt := findClassByName(INTERFACE_INTERRUPT);
methodDefaultConstructor := findSystemMember(MEMBER_DEFAULT_CONSTRUCTOR);
methodGetString := findSystemMember(MEMBER_GET_STRING);
methodCheckObjectArrayAssignable := findSystemMember(MEMBER_CHECK_OBJECT_ARRAY_ASSIGNABLE);
methodGetInterfaceMethodEntryPoint := findSystemMember(MEMBER_GET_INTERFACE_METHOD_ENTRY_POINT);
methodAllocateInstance := findSystemMember(MEMBER_ALLOCATE_INSTANCE);
methodArrayCreateOneDim := findSystemMember(MEMBER_ARRAY_CREATE_ONE_DIM);
methodArrayCreateMultiDim := findSystemMember(MEMBER_ARRAY_CREATE_MULTI_DIM);
methodCast := findSystemMember(MEMBER_CAST);
methodIsInstance := findSystemMember(MEMBER_IS_INSTANCE);
methodMonitorEnter := findSystemMember(MEMBER_MONITOR_ENTER);
methodMonitorExit := findSystemMember(MEMBER_MONITOR_EXIT);
methodThrowAbstractMethodError := findSystemMember(MEMBER_THROW_ABSTRACT);
methodMain := findSystemMember(MEMBER_MAIN_PROCEDURE);
end;
procedure JavaStaticRecompiler.sortClasses();
label
label0;
var
i: int;
j: int;
lim: int;
class1: JavaClass;
class2: JavaClass;
classes: JavaClass_Array1d;
begin
lim := self.classesCount - 1;
classes := self.classes;
for i := 0 to lim do begin
label0:
class1 := classes[i];
for j := i + 1 to lim do begin
class2 := classes[j];
if class1.isDirectSuperClass(class2) then begin
arraycopy(classes, i, classes, i + 1, j - i);
classes[i] := class2;
goto label0;
end;
end;
end;
end;
procedure JavaStaticRecompiler.preferenceForClassMembers();
var
i: int;
count: int;
cls: JavaClass;
classes: JavaClass_Array1d;
begin
count := self.classesCount;
classes := self.classes;
for i := 0 to count - 1 do begin
cls := classes[i];
cls.defineImplementedMethods();
cls.defineVirtualMethods();
cls.defineFieldOffsets();
end;
end;
procedure JavaStaticRecompiler.prepareMethods();
var
i: int;
j: int;
k: int;
count: int;
classes: JavaClass_Array1d;
cls: JavaClass;
begin
count := self.classesCount;
classes := self.classes;
for i := 0 to count - 1 do begin
cls := classes[i];
k := cls.getMethodsCount();
for j := 0 to k - 1 do begin
cls.getMethod(j).prepareCompile();
end;
end;
end;
procedure JavaStaticRecompiler.prepareEntry();
var
c: int;
i: int;
initOrder: StringPool;
commands: long_Array1d;
begin
initOrder := self.initOrder;
for i := initOrder.getLength() - 1 downto 0 do begin
if findClassByName(initOrder.getString(i)).findMemberInternal(NAME_INITIALIZATION, SIGNATURE_NO_PARAMETERS) = nil then begin
initOrder.delete(i);
end;
end;
c := initOrder.getLength();
commands := long_Array1d_create(c + 4);
self.entryCommands := commands;
commands[0] := long($5008) + ((long(c) + 1) shl 16) { load except (+(c + 1) команд) };
for i := 1 to c do begin
commands[i] := long($5f10) + ((long(i) - 1) shl 16) { call static initOrder[i].<clinit>() };
end;
commands[c + 1] := long($5f0f) { call static Run.main() };
commands[c + 2] := long($1010) { pop };
commands[c + 3] := long($10bc) { ret };
end;
procedure JavaStaticRecompiler.linkClasses();
var
i: int;
c: int;
classes: JavaClass_Array1d;
arrays: JavaArray_Array1d;
primitives: JavaClass_Array1d;
begin
findClassBySignature(PREFIX_ARRAY + PREFIX_BYTE);
findClassBySignature(PREFIX_ARRAY + PREFIX_INT);
findClassBySignature(PREFIX_ARRAY + PREFIX_OBJECT + CLASS_INTERFACE_ENTRY + SUFFIX_OBJECT);
classes := self.classes;
arrays := self.arrays;
primitives := self.primitives;
c := classesCount - 1;
for i := 0 to c do begin
if i < c then begin
classes[i].setNextClass(classes[i + 1]);
end else begin
classes[i].setNextClass(arrays[0]);
end;
end;
c := arraysCount - 1;
for i := 0 to c do begin
if i < c then begin
arrays[i].setNextClass(arrays[i + 1]);
end else begin
arrays[i].setNextClass(primitives[0]);
end;
end;
c := length(primitives) - 1;
for i := 0 to c do begin
if i < c then begin
primitives[i].setNextClass(primitives[i + 1]);
end else begin
primitives[i].setNextClass(nil);
end;
end;
end;
procedure JavaStaticRecompiler.extractStrings();
var
i: int;
j: int;
arrays: JavaArray_Array1d;
classes: JavaClass_Array1d;
strings: StringPool;
cls: JavaClass;
begin
strings := self.strings;
classes := self.primitives;
for i := 0 to length(classes) - 1 do begin
cls := classes[i];
cls.setNameIndex(strings.acquireStringIndex(cls.getOutputName()));
end;
classes := self.classes;
for i := 0 to classesCount - 1 do begin
cls := classes[i];
cls.setNameIndex(strings.acquireStringIndex(cls.getOutputName()));
end;
arrays := self.arrays;
for i := 0 to arraysCount - 1 do begin
cls := arrays[i];
cls.setNameIndex(strings.acquireStringIndex(cls.getOutputName()));
end;
classes := self.classes;
for i := 0 to classesCount - 1 do begin
cls := classes[i];
for j := 0 to cls.getMethodsCount() - 1 do begin
cls.getMethod(j).fillStringPool();
end;
end;
end;
procedure JavaStaticRecompiler.assignOffsets();
var
i: int;
j: int;
offset: int;
primitives: JavaClass_Array1d;
classes: JavaClass_Array1d;
arrays: JavaArray_Array1d;
member: JavaClassMember;
cls: JavaClass;
begin
offset := MalikProcessor.MEMORY_START + MalikProcessor.INTERRUPTS_TABLE_SIZE;
primitives := self.primitives;
classes := self.classes;
arrays := self.arrays;
self.imageBeginOffset := offset;
{ определяем смещения таблиц методов протоколов }
for i := 0 to classesCount - 1 do begin
cls := classes[i];
if cls.isInterface() then begin
continue;
end;
for j := 0 to cls.getInterfacesCount() - 1 do begin
cls.setIMTOffset(j, offset);
inc(offset, IMT_ENTRY_SIZE * cls.getInterface(j).getAbstractMethodsCount());
end;
end;
for i := 0 to arraysCount - 1 do begin
cls := arrays[i];
for j := 0 to cls.getInterfacesCount() - 1 do begin
cls.setIMTOffset(j, offset);
inc(offset, IMT_ENTRY_SIZE * cls.getInterface(j).getAbstractMethodsCount());
end;
end;
{ определяем смещения статичных полей }
for i := 0 to classesCount - 1 do begin
cls := classes[i];
for j := 0 to cls.getFieldsCount() - 1 do begin
member := cls.getField(j);
if (not member.isStatic()) or (not JavaField(member).isOutToExecutable()) then begin
continue;
end;
member.setOffset(offset);
inc(offset, getTypeSize(member.getSignature(), true));
end;
end;
{ определяем смещения классов }
for i := 0 to classesCount - 1 do begin
cls := classes[i];
cls.setOffset(offset + 4);
inc(offset, cls.getDataSize());
end;
for i := 0 to arraysCount - 1 do begin
cls := arrays[i];
cls.setOffset(offset + 4);
inc(offset, cls.getDataSize());
end;
for i := 0 to length(primitives) - 1 do begin
cls := primitives[i];
cls.setOffset(offset + 4);
inc(offset, cls.getDataSize());
end;
self.methodsOffset := offset;
end;
procedure JavaStaticRecompiler.reduceCodeSize();
var
f: boolean;
i: int;
j: int;
offset: int;
classesCount: int;
classes: JavaClass_Array1d;
cls: JavaClass;
method: JavaMethod;
entryCommands: long_Array1d;
strings: StringPool;
begin
classesCount := self.classesCount;
classes := self.classes;
repeat
f := false;
{ сокращаем размеры команд перехода }
for i := 0 to classesCount - 1 do begin
cls := classes[i];
for j := 0 to cls.getMethodsCount() - 1 do begin
if cls.getMethod(j).reduceSizeofJumps() then begin
f := true;
end;
end;
end;
{ определяем смещения методов }
offset := methodsOffset;
for i := 0 to classesCount - 1 do begin
cls := classes[i];
for j := 0 to cls.getMethodsCount() - 1 do begin
method := cls.getMethod(j);
method.setOffset(offset);
inc(offset, method.getCodeSize());
end;
end;
{ сокращаем размеры команд вызова }
for i := 0 to classesCount - 1 do begin
cls := classes[i];
for j := 0 to cls.getMethodsCount() - 1 do begin
if cls.getMethod(j).reduceSizeofCalls() then begin
f := true;
end;
end;
end;
until not f;
{ сокращаем размеры команд точки входа }
entryOffset := offset;
entryCommands := self.entryCommands;
i := length(entryCommands);
reduceSizeofCalls(entryCommands, i, offset, self);
inc(offset, computeCodeSize(entryCommands, 0, i));
if (offset and $03) <> 0 then begin
offset := (offset and (-$04)) + $04;
end;
{ определяем смещение строк }
stringsOffset := offset;
inc(offset, 4);
strings := self.strings;
for i := 0 to strings.getLength() - 1 do begin
inc(offset, length(strings.getString(i)) + 20);
if (offset and $03) <> 0 then begin
offset := (offset and (-$04)) + $04;
end;
end;
{ определяем смещение конца образа }
self.imageEndOffset := offset;
end;
procedure JavaStaticRecompiler.computeAvailableMemory();
var
heapEndOffset: int;
begin
heapEndOffset := imageEndOffset + descSize + heapSize;
if (heapEndOffset and (-$100000)) <> 0 then begin
heapEndOffset := (heapEndOffset and (-$100000)) + $100000;
end;
availableMemoryInMB := min(256, (heapEndOffset - MalikProcessor.MEMORY_START) shr 20);
end;
procedure JavaStaticRecompiler.createExecutableFile(const fileName: AnsiString);
var
i: int;
j: int;
len: int;
fileContents: FileOutputStream;
contents: ByteArrayOutputStream;
stream: DataOutput;
fileStream: DataOutput;
strings: StringPool;
member: JavaClassMember;
cls: JavaClass;
classes: JavaClass_Array1d;
arrays: JavaArray_Array1d;
primitives: JavaClass_Array1d;
image: byte_Array1d;
s: AnsiString;
begin
fileContents := FileOutputStream.create(fileName);
if fileContents.isInvalidHandle() then begin
fileContents.free();
raise IOException.create('Не удалось создать файл ' + fileName);
end;
contents := ByteArrayOutputStream.create();
stream := DataOutputStream.create(contents);
fileStream := DataOutputStream.create(fileContents);
classes := self.classes;
arrays := self.arrays;
primitives := self.primitives;
{ записываем таблицы методов протоколов }
for i := 0 to classesCount - 1 do begin
classes[i].writeIMTs(stream);
end;
for i := 0 to arraysCount - 1 do begin
arrays[i].writeIMTs(stream);
end;
{ записываем статичные поля }
for i := 0 to classesCount - 1 do begin
cls := classes[i];
for j := 0 to cls.getFieldsCount() - 1 do begin
member := cls.getField(j);
if (not member.isStatic()) or (not JavaField(member).isOutToExecutable()) then begin
continue;
end;
if MEMBER_STRING_POOL_OFFSET.equals(member) then begin
stream.writeIntLE(stringsOffset);
continue;
end;
if MEMBER_DESCRIPTORS_SIZE.equals(member) then begin
stream.writeIntLE(descSize);
continue;
end;
if MEMBER_HEAP_LIMIT.equals(member) then begin
stream.writeIntLE((availableMemoryInMB shl 20) + MalikProcessor.MEMORY_START);
continue;
end;
s := member.getSignature();
if length(s) > 0 then begin
case s[1] of
PREFIX_BOOLEAN, PREFIX_CHAR, PREFIX_FLOAT, PREFIX_BYTE, PREFIX_SHORT, PREFIX_INT, PREFIX_OBJECT, PREFIX_ARRAY: begin
stream.writeIntLE(0);
end;
PREFIX_DOUBLE, PREFIX_LONG: begin
stream.writeLongLE(0);
end;
end;
end;
end;
end;
{ записываем данные классов }
for i := 0 to classesCount - 1 do begin
classes[i].writeData(stream);
end;
for i := 0 to arraysCount - 1 do begin
arrays[i].writeData(stream);
end;
for i := 0 to length(primitives) - 1 do begin
primitives[i].writeData(stream);
end;
{ записываем код методов }
for i := 0 to classesCount - 1 do begin
cls := classes[i];
for j := 0 to cls.getMethodsCount() - 1 do begin
cls.getMethod(j).writeCode(stream);
end;
end;
writeCode(stream, entryCommands, length(entryCommands), entryOffset, self);
{ записываем строки }
cls := findClassBySignature(PREFIX_ARRAY + PREFIX_BYTE);
strings := self.strings;
len := strings.getLength();
stream.writeIntLE(len);
for i := 0 to len - 1 do begin
s := strings.getString(i);
j := length(s);
stream.writeIntLE(0);
stream.writeIntLE(0);
JavaClass.writeClassReference(stream, cls);
stream.writeIntLE(j);
stream.writeIntLE(0);
stream.writeChars(s);
while (j and $03) <> 0 do begin
stream.writeByte(0);
inc(j);
end;
end;
{ записываем исполняемый файл }
image := contents.toByteArray();
if compressionLevel > 0 then begin
image := Zlib.compress(image, compressionLevel);
fileStream.writeIntLE($014b4c4d);
end else begin
fileStream.writeIntLE($004b4c4d);
end;
fileStream.writeIntLE(imageBeginOffset);
fileStream.writeIntLE(entryOffset);
fileStream.writeShortLE(availableMemoryInMB);
fileStream.writeShortLE(stackSizeInMB);
fileStream.write(image);
{ закрываем файл }
fileStream := nil;
end;
procedure JavaStaticRecompiler.createTextDebugInfoFile(const fileName: AnsiString);
var
i: int;
j: int;
k: int;
offset: int;
fileContents: FileOutputStream;
stream: DataOutput;
lnt: JavaLineNumberTable;
intfImpl: InterfaceImplementsInfo;
mthdImpl: InterfaceMethodImplements;
member: JavaClassMember;
cls: JavaClass;
classes: JavaClass_Array1d;
arrays: JavaArray_Array1d;
primitives: JavaClass_Array1d;
s: AnsiString;
t: AnsiString;
begin
fileContents := FileOutputStream.create(fileName);
if fileContents.isInvalidHandle() then begin
fileContents.free();
raise IOException.create('Не удалось создать файл ' + fileName);
end;
stream := DataOutputStream.create(fileContents);
classes := self.classes;
arrays := self.arrays;
primitives := self.primitives;
stream.writeChars(LINE_ENDING);
{ записываем нестатичные поля }
for i := 0 to classesCount - 1 do begin
cls := classes[i];
s := cls.getName();
for j := 0 to cls.getFieldsCount() - 1 do begin
member := cls.getField(j);
if member.isStatic() then begin
continue;
end;
stream.writeChars(localOffsetToString(member.getOffset()) + '=' + s + '.' + member.getName() + ': ' + member.getSignature() + LINE_ENDING);
end;
end;
{ записываем таблицы методов протоколов }
for i := 0 to classesCount - 1 do begin
cls := classes[i];
if cls.isInterface() then begin
continue;
end;
s := cls.getName();
for j := 0 to cls.getInterfacesCount() - 1 do begin
intfImpl := cls.getInterfaceImplements(j);
t := intfImpl.getInterfaceName();
offset := intfImpl.getIMTOffset();
for k := 0 to intfImpl.getMethodsCount() - 1 do begin
mthdImpl := intfImpl.getMethodImplements(k);
stream.writeChars(globalOffsetToString(offset + k * IMT_ENTRY_SIZE) + '=func: ' + s + ' : ' + t + '.' + mthdImpl.getMethodName() + mthdImpl.getMethodSignature() + LINE_ENDING);
end;
end;
end;
{ записываем статичные поля }
for i := 0 to classesCount - 1 do begin
cls := classes[i];
s := cls.getName();
for j := 0 to cls.getFieldsCount() - 1 do begin
member := cls.getField(j);
if (not member.isStatic()) or (not JavaField(member).isOutToExecutable()) then begin
continue;
end;
stream.writeChars(globalOffsetToString(member.getOffset()) + '=var: ' + s + '.' + member.getName() + ': ' + member.getSignature() + LINE_ENDING);
end;
end;
{ записываем классы }
for i := 0 to classesCount - 1 do begin
writeToTextDebugInfoFile(stream, classes[i]);
end;
for i := 0 to arraysCount - 1 do begin
writeToTextDebugInfoFile(stream, arrays[i]);
end;
for i := 0 to length(primitives) - 1 do begin
writeToTextDebugInfoFile(stream, primitives[i]);
end;
{ записываем методы }
for i := 0 to classesCount - 1 do begin
cls := classes[i];
s := cls.getName();
t := cls.getSourceFile();
for j := 0 to cls.getMethodsCount() - 1 do begin
member := cls.getMethod(j);
if JavaMethod(member).isAbstract() then begin
continue;
end;
offset := member.getOffset();
stream.writeChars(globalOffsetToString(offset) + '=func: ' + s + '.' + member.getName() + member.getSignature() + LINE_ENDING);
if length(t) = 0 then begin
continue;
end;
lnt := JavaMethod(member).getLineNumberTable();
if lnt = nil then begin
continue;
end;
for k := 0 to lnt.getLinesCount() - 1 do begin
stream.writeChars(globalOffsetToString(offset + JavaMethod(member).getRelativeOffset(lnt.getCodeOffsetAt(k))) + '= ' + t + '[' + toDecString(lnt.getLineNumber(k)) + ']' + LINE_ENDING);
end;
end;
end;
stream.writeChars(globalOffsetToString(entryOffset) + '=func: Точка входа в программу' + LINE_ENDING);
stream.writeChars(globalOffsetToString(stringsOffset) + '=func: Строки программы' + LINE_ENDING);
{ закрываем файл }
stream := nil;
end;
procedure JavaStaticRecompiler.createBinDebugInfoFile(const fileName: AnsiString);
var
i: int;
j: int;
k: int;
len: int;
offset: int;
classNameIndex: int;
methodNameIndex: int;
sourceFileIndex: int;
fileContents: FileOutputStream;
stream: DataOutput;
cls: JavaClass;
method: JavaMethod;
strings: StringPool;
table: JavaLineNumberTable;
classes: JavaClass_Array1d;
procedure writeRecord(offset, classNameIndex, methodNameIndex, sourceFileIndex, lineNumber: int); inline;
begin
stream.writeInt(offset);
stream.writeInt(classNameIndex);
stream.writeInt(methodNameIndex);
stream.writeInt(sourceFileIndex);
stream.writeShort(lineNumber);
end;
begin
fileContents := FileOutputStream.create(fileName);
if fileContents.isInvalidHandle() then begin
fileContents.free();
raise IOException.create('Не удалось создать файл ' + fileName);
end;
stream := DataOutputStream.create(fileContents);
strings := StringPool.create();
try
{ формируем строки }
strings.acquireStringIndex('');
classes := self.classes;
for i := 0 to classesCount - 1 do begin
cls := classes[i];
for j := 0 to cls.getMethodsCount() - 1 do begin
method := cls.getMethod(j);
if method.isAbstract() then begin
continue;
end;
strings.acquireStringIndex(cls.getOutputName());
strings.acquireStringIndex(method.getName());
strings.acquireStringIndex(cls.getSourceFile());
end;
end;
strings.acquireStringIndex(PROGRAMME_ENTRY);
strings.acquireStringIndex(UNKNOWN_SOURCE);
{ записываем сформированные строки }
len := strings.getLength();
stream.writeInt(len);
for i := 0 to len - 1 do begin
stream.writeUTF(toUTF16String(strings.getString(i)));
end;
{ записываем данные на каждый метод и каждую строку исходного кода }
for i := 0 to classesCount - 1 do begin
cls := classes[i];
for j := 0 to cls.getMethodsCount() - 1 do begin
method := cls.getMethod(j);
if method.isAbstract() then begin
continue;
end;
offset := method.getOffset();
classNameIndex := strings.indexOfString(cls.getOutputName());
methodNameIndex := strings.indexOfString(method.getName());
sourceFileIndex := strings.indexOfString(cls.getSourceFile());
writeRecord(offset, classNameIndex, methodNameIndex, sourceFileIndex, 0);
table := method.getLineNumberTable();
if table = nil then begin
continue;
end;
for k := 0 to table.getLinesCount() - 1 do begin
writeRecord(offset + method.getRelativeOffset(table.getCodeOffsetAt(k)), classNameIndex, methodNameIndex, sourceFileIndex, table.getLineNumber(k));
end;
end;
end;
{ записываем данные на точку входа }
classNameIndex := strings.indexOfString('');
methodNameIndex := strings.indexOfString(PROGRAMME_ENTRY);
sourceFileIndex := strings.indexOfString(UNKNOWN_SOURCE);
writeRecord(entryOffset, classNameIndex, methodNameIndex, sourceFileIndex, 0);
finally
strings.free();
end;
{ закрываем файл }
stream := nil;
end;
procedure JavaStaticRecompiler.createStringPoolFile(const fileName: AnsiString);
var
i: int;
fileContents: FileOutputStream;
stream: DataOutput;
strings: StringPool;
begin
fileContents := FileOutputStream.create(fileName);
if fileContents.isInvalidHandle() then begin
fileContents.free();
raise IOException.create('Не удалось создать файл ' + fileName);
end;
stream := DataOutputStream.create(fileContents);
{ записываем строки программы в отдельный текстовый файл }
strings := self.strings;
stream.writeChars(#$ef#$bb#$bf);
for i := 0 to strings.getLength() - 1 do begin
stream.writeChars('[' + toDecString(i) + ']=' + strings.getString(i) + LINE_ENDING);
end;
{ закрываем файл }
stream := nil;
end;
procedure JavaStaticRecompiler.buildMalikManifest(const outputDirectory: AnsiString; javaManifest, malikManifest: ProgrammeManifest);
var
i: int;
f: AnsiString;
s: AnsiString;
imageFileStream: FileInputStream;
imageHandleStream: TStream;
image: TPortableNetworkGraphic;
iconFileStream: FileOutputStream;
iconHandleStream: TStream;
icon: TIcon;
begin
{ Извлекаем значок программы (если он есть) }
f := copy(executableFileName, 1, length(executableFileName));
if DIRECTORY_SEPARATOR <> '/' then begin
for i := length(f) downto 1 do begin
if f[i] = '/' then begin
f[i] := DIRECTORY_SEPARATOR;
end;
end;
end;
f := outputDirectory + f + '.ico';
s := javaManifest.getValue(MANIFEST_PROPERTY_MIDLET_ICON);
if length(s) > 0 then begin
if startsWith('/', s) then begin
s := 'res' + s;
end else begin
s := 'res/' + s;
end;
if DIRECTORY_SEPARATOR <> '/' then begin
for i := length(s) downto 1 do begin
if s[i] = '/' then begin
s[i] := DIRECTORY_SEPARATOR;
end;
end;
end;
imageFileStream := FileInputStream.create(outputDirectory + s);
try
if not imageFileStream.isInvalidHandle() then begin
imageHandleStream := THandleStream.create(imageFileStream.getHandle());
try
image := TPortableNetworkGraphic.create();
try
image.loadFromStream(imageHandleStream);
icon := TIcon.create();
try
icon.assign(image);
iconFileStream := FileOutputStream.create(f);
try
if not iconFileStream.isInvalidHandle() then begin
iconHandleStream := THandleStream.create(iconFileStream.getHandle());
try
icon.saveToStream(iconHandleStream);
finally
iconHandleStream.free();
end;
end;
finally
iconFileStream.free();
end;
finally
icon.free();
end;
finally
image.free();
end;
finally
imageHandleStream.free();
end;
end;
finally
imageFileStream.free();
end;
end;
{ Записываем свойства }
s := executableFileName;
if not startsWith('/', s) then begin
s := '/' + s;
end;
malikManifest.setValue(MANIFEST_PROPERTY_PROGRAMME_NAME, javaManifest.getValue(MANIFEST_PROPERTY_MIDLET_NAME));
malikManifest.setValue(MANIFEST_PROPERTY_PROGRAMME_VERSION, javaManifest.getValue(MANIFEST_PROPERTY_MIDLET_VERSION));
malikManifest.setValue(MANIFEST_PROPERTY_PROGRAMME_EXECUTABLE, s);
malikManifest.setValue(MANIFEST_PROPERTY_PROGRAMME_VENDOR, javaManifest.getValue(MANIFEST_PROPERTY_MIDLET_VENDOR));
malikManifest.setValue(MANIFEST_PROPERTY_PROGRAMME_DESCRIPTION, javaManifest.getValue(MANIFEST_PROPERTY_MIDLET_DESCRIPTION));
s := javaManifest.getValue(MANIFEST_PROPERTY_MIDLET_SITE);
if length(s) = 0 then begin
for i := length(MANIFEST_PROPERTY_MIDLET_SITE_ATLERNATIVES) - 1 downto 0 do begin
s := javaManifest.getValue(MANIFEST_PROPERTY_MIDLET_SITE_ATLERNATIVES[i]);
if length(s) > 0 then begin
malikManifest.setValue(MANIFEST_PROPERTY_PROGRAMME_SITE, s);
break;
end;
end;
end else begin
malikManifest.setValue(MANIFEST_PROPERTY_PROGRAMME_SITE, s);
end;
malikManifest.setValue(MANIFEST_PROPERTY_PROGRAMME_INSTALL_NOTIFY, javaManifest.getValue(MANIFEST_PROPERTY_MIDLET_INSTALL_NOTIFY));
malikManifest.setValue(MANIFEST_PROPERTY_PROGRAMME_DELETE_CONFIRM, javaManifest.getValue(MANIFEST_PROPERTY_MIDLET_DELETE_CONFIRM));
malikManifest.setValue(MANIFEST_PROPERTY_PROGRAMME_DELETE_NOTIFY, javaManifest.getValue(MANIFEST_PROPERTY_MIDLET_DELETE_NOTIFY));
malikManifest.setValue(MANIFEST_PROPERTY_SOURCE_PLATFORM, getPlatformName());
end;
procedure JavaStaticRecompiler.clear();
var
i: int;
c: JavaClass_Array1d;
a: JavaArray_Array1d;
begin
c := classes;
for i := classesCount - 1 downto 0 do begin
c[i].free();
end;
classes := nil;
classesCount := 0;
a := arrays;
for i := arraysCount - 1 downto 0 do begin
a[i].free();
end;
arrays := nil;
arraysCount := 0;
entryCommands := nil;
initOrder.clear();
strings.clear();
end;
function JavaStaticRecompiler.isJarArchiveForEmulator(archive: ZIPArchiveReader): boolean;
var
manifestInput: Input;
manifest: ProgrammeManifest;
begin
manifestInput := archive.openFile(MANIFEST_FILE_NAME);
if manifestInput <> nil then begin
manifest := ProgrammeManifest.create();
try
manifest.loadFromStream(manifestInput);
result := manifest.getValue('Library-Purpose') = 'Malik Emulator';
finally
manifest.free();
end;
end else begin
result := false;
end;
end;
function JavaStaticRecompiler.indexOfArray(const name: AnsiString): int;
var
i: int;
arrays: JavaArray_Array1d;
begin
arrays := self.arrays;
for i := arraysCount - 1 downto 0 do begin
if arrays[i].getName() = name then begin
result := i;
exit;
end;
end;
result := -1;
end;
function JavaStaticRecompiler.getArray(const name: AnsiString): JavaArray;
var
i: int;
dif: int;
len: int;
dimcount: int;
cellClass: JavaClass;
nearArray: JavaClass;
currentArray: JavaArray;
arrays: JavaArray_Array1d;
begin
{ если не указывается тип массива и список массивов не пуст, то возвращаем первый массив }
if (name = PREFIX_ARRAY) and (arraysCount > 0) then begin
result := self.arrays[0];
exit;
end;
{ ищем среди имеющихся массивов }
i := indexOfArray(name);
if i >= 0 then begin
result := self.arrays[i];
exit;
end;
{ определяем количество измерений (оно равно количеству квадратных скобок в начале сигнатуры) }
len := length(name);
dimcount := 1;
for i := 2 to len do begin
if name[i] <> PREFIX_ARRAY then begin
break;
end;
inc(dimcount);
end;
{ определяем класс ячеек массива }
cellClass := findClassBySignature(copy(name, dimcount + 1, len - dimcount));
{ ищем массив с наибольшим количеством измерений и с таким же классом ячеек }
nearArray := cellClass;
arrays := self.arrays;
for i := arraysCount - 1 downto 0 do begin
currentArray := arrays[i];
if currentArray.getCellClass() = cellClass then begin
nearArray := currentArray;
break;
end;
end;
{ определяем разность между требуемым количеством измерений и имеющимся }
if nearArray is JavaArray then begin
dif := dimcount - JavaArray(nearArray).getDimensionsCount();
end else begin
dif := dimcount;
end;
{ создаём массивы с недостающим количеством измерений }
for i := 1 to dif do begin
nearArray := JavaArray.create(self, nearArray);
nearArray.findAncestors();
nearArray.defineImplementedMethods();
nearArray.defineVirtualMethods();
nearArray.defineFieldOffsets();
addArray(JavaArray(nearArray));
end;
{ возвращаем последний созданный массив }
result := nearArray as JavaArray;
end;
function JavaStaticRecompiler.findSystemMember(desriptor: _Object): JavaClassMember;
var
d: ClassMemberDescriptor;
className: AnsiString;
memberName: AnsiString;
signature: AnsiString;
begin
d := ClassMemberDescriptor(desriptor);
className := d.getClassName();
memberName := d.getMemberName();
signature := d.getSignature();
result := findClassByName(className).findMember(memberName, signature);
if result = nil then begin
if (length(signature) = 0) or (signature[1] <> HEADER_PREFIX) then begin
signature := ': ' + signature;
end;
raise ClassMemberNotFoundException.create('Не удалось найти системный член класса: ' + className + '.' + memberName + signature);
end;
end;
procedure JavaStaticRecompiler.writeCode(stream: DataOutput; const commands: long_Array1d; commandsCount: int; offset: int; owner: ConstantPoolContainer);
var
codesize: int;
cmdsize: int;
opcode: int;
i: int;
c: long;
member: JavaClassMember;
begin
codesize := 0;
for i := 0 to commandsCount - 1 do begin
c := commands[i];
cmdsize := (int(c) shr 12) and $0f;
opcode := int(c) and $0fff;
inc(codesize, cmdsize);
case opcode of
{ основные опкоды }
$0000, $0010, $0012, $0014, $0016, $0018..$001f, $002f, $003f, $0050..$0073, $0077, $007b..$00af, $00b8..$00bc, $00be, $00cf, $00df, $00f0..$00f8, $00fc..$00fe: begin
stream.writeByte(opcode);
end;
$0001, $0009, $0074..$0076, $0078..$007a, $00bd, $00bf, $00fa: begin
stream.writeByte(opcode);
stream.writeByte(int(c) shr 16);
end;
$0002, $000a, $000c, $0011, $0013, $0015, $0040, $0042..$0048, $004a..$004f, $00e0, $00e2..$00e8, $00ea..$00ef, $00f9, $00fb: begin
stream.writeByte(opcode);
stream.writeShortLE(int(c) shr 16);
end;
$0003, $000b, $0017, $0041, $0049, $00e1, $00e9: begin
stream.writeByte(opcode);
stream.writeIntLE(int(c shr 16));
end;
$0004: begin
stream.writeByte(opcode);
stream.writeLongLE((owner.getConstantPoolEntry(int(c shr 16)) as LongEntry).longValue());
end;
$0005, $000d..$000e: begin
stream.writeByte(opcode);
stream.writeFloatLE((owner.getConstantPoolEntry(int(c shr 16)) as FloatEntry).floatValue());
end;
$0006, $000f: begin
stream.writeByte(opcode);
stream.writeDoubleLE((owner.getConstantPoolEntry(int(c shr 16)) as DoubleEntry).doubleValue());
end;
$0008, $00b2: begin
stream.writeByte(opcode);
stream.writeIntLE(computeCodeSize(commands, i + 1, int(c shr 16)));
end;
$0020..$002e, $0030..$003e: begin
member := owner.getConstantPoolMember((int(c) shr 16) and $ffff, int(c shr 32) and $ffff, int(c shr 48) and $ffff, 0);
stream.writeByte(opcode);
stream.writeIntLE(member.getOffset());
end;
$00b0: begin
stream.writeByte(opcode);
stream.writeByte(computeCodeSize(commands, i + 1, int(c shr 16)));
end;
$00b1: begin
stream.writeByte(opcode);
stream.writeShortLE(computeCodeSize(commands, i + 1, int(c shr 16)));
end;
$00b4: begin
member := owner.getConstantPoolMember((int(c) shr 16) and $ffff, int(c shr 32) and $ffff, int(c shr 48) and $ffff, 0);
stream.writeByte(opcode);
stream.writeByte(member.getOffset() - (offset + codesize));
end;
$00b5: begin
member := owner.getConstantPoolMember((int(c) shr 16) and $ffff, int(c shr 32) and $ffff, int(c shr 48) and $ffff, 0);
stream.writeByte(opcode);
stream.writeShortLE(member.getOffset() - (offset + codesize));
end;
$00b6: begin
member := owner.getConstantPoolMember((int(c) shr 16) and $ffff, int(c shr 32) and $ffff, int(c shr 48) and $ffff, 0);
stream.writeByte(opcode);
stream.writeIntLE(member.getOffset() - (offset + codesize));
end;
$00c0..$00ce, $00d0..$00de: begin
stream.writeIntLE(opcode + (int(c shr 16) shl 8));
end;
$0100..$011f, $0156..$0157, $0160..$017f, $01b0..$01bf, $01f2..$01f3, $01f6..$01f7, $01fa..$01fb, $01fe: begin
stream.writeShort($fe00 + opcode);
end;
$0120..$012f: begin
stream.writeShort($fe00 + opcode);
stream.writeByte(computeCodeSize(commands, i + 1, int(c shr 16)));
end;
$0130..$013f: begin
stream.writeShort($fe00 + opcode);
stream.writeShortLE(computeCodeSize(commands, i + 1, int(c shr 16)));
end;
$0140..$014f: begin
stream.writeShort($fe00 + opcode);
stream.writeIntLE(computeCodeSize(commands, i + 1, int(c shr 16)));
end;
$0150..$0155: begin
stream.writeShort($fe00 + opcode);
stream.writeByte(int(c) shr 16);
end;
$015a: begin
stream.writeShort($fe00 + opcode);
stream.writeIntLE(int(c shr 16));
end;
$015e: begin
stream.writeShort($fe00 + opcode);
stream.writeShortLE(int(c) shr 16);
end;
$0180..$01a3, $01a7, $01ab..$01af, $01c0..$01e3, $01e7, $01eb..$01f1, $01f4..$01f5, $01f8..$01f9, $01fc..$01fd: begin
stream.writeShort($fe00 + opcode);
stream.writeShortLE(int(c) shr 16);
end;
$01a4..$01a6, $01a8..$01aa, $01e4..$01e6, $01e8..$01ea: begin
stream.writeShort($fe00 + opcode);
stream.writeShortLE(int(c) shr 16);
stream.writeByte(int(c shr 32));
end;
$0200..$022f, $0233..$02ff: begin
stream.writeShort($ffff);
stream.writeByte(opcode);
end;
$0230..$0231: begin
stream.writeShort($ffff);
stream.writeByte(opcode);
stream.writeShortLE(int(c) shr 16);
end;
$0232: begin
stream.writeShort($ffff);
stream.writeByte($32);
stream.writeByte(computeCodeSize(commands, i + 1, int(c shr 16)));
end;
{ специальные опкоды }
$0f01..$0f02, $0f04..$0f05, $0f07..$0f0c, $0f0f..$0f10: begin
case opcode of
$0f01:
member := methodGetString;
$0f02:
member := methodCheckObjectArrayAssignable;
$0f04:
member := methodGetInterfaceMethodEntryPoint;
$0f05:
member := methodAllocateInstance;
$0f07:
member := methodArrayCreateOneDim;
$0f08:
member := methodArrayCreateMultiDim;
$0f09:
member := methodCast;
$0f0a:
member := methodIsInstance;
$0f0b:
member := methodMonitorEnter;
$0f0c:
member := methodMonitorExit;
$0f0f:
member := methodMain;
$0f10:
member := findClassByName(initOrder.getString(int(c shr 16))).findMemberInternal(NAME_INITIALIZATION, SIGNATURE_NO_PARAMETERS);
else
member := nil;
end;
case cmdsize of
2: begin
stream.writeByte($b4);
stream.writeByte(member.getOffset() - (offset + codesize));
end;
3: begin
stream.writeByte($b5);
stream.writeShortLE(member.getOffset() - (offset + codesize));
end;
5: begin
stream.writeByte($b6);
stream.writeIntLE(member.getOffset() - (offset + codesize));
end;
end;
end;
$0f03: begin
stream.writeByte($0b);
stream.writeIntLE(findClassByName((owner.getConstantPoolEntry(int(c shr 16)) as StringEntry).stringValue()).getOffset());
end;
$0f06: begin
stream.writeByte($0b);
stream.writeIntLE(findClassBySignature((owner.getConstantPoolEntry(int(c shr 16)) as StringEntry).stringValue()).getOffset());
end;
$0f0d: begin
member := owner.getConstantPoolMember((int(c) shr 16) and $ffff, int(c shr 32) and $ffff, int(c shr 48) and $ffff, 0);
stream.writeByte($0b);
stream.writeIntLE(member.getOffset());
end;
$0ffd: begin
stream.writeByte($0b);
stream.writeIntLE(offset + computeCodeSize(commands, 0, int(c shr 16)));
end;
$0ffe: begin
stream.writeIntLE(computeCodeSize(commands, i + 1, int(c shr 32)) - computeCodeSize(commands, i + 1, int(c) shr 16));
end;
$0fff: begin
stream.writeIntLE(int(c shr 16));
end;
end;
end;
while (codesize and $03) <> 0 do begin
stream.writeByte(0);
inc(codesize);
end;
end;
function JavaStaticRecompiler.reduceSizeofJumps(const commands: long_Array1d; commandsCount: int): boolean;
var
opcode: int;
i: int;
j: int;
s: int;
c: long;
begin
result := false;
for i := 0 to commandsCount - 1 do begin
c := commands[i];
opcode := int(c) and $0fff;
case opcode of
$00b0..$00b2: begin
j := int(c shr 16);
commands[i] := long($20b0) + (long(j) shl 16);
s := computeCodeSize(commands, i + 1, j);
if (s >= -$80) and (s < $80) then begin
result := result or (opcode <> $00b0);
continue;
end;
commands[i] := long($30b1) + (long(j) shl 16);
s := computeCodeSize(commands, i + 1, j);
if (s >= -$8000) and (s < $8000) then begin
result := result or (opcode <> $00b1);
continue;
end;
commands[i] := long($50b2) + (long(j) shl 16);
result := result or (opcode <> $00b2);
end;
$0120..$014f: begin
j := int(c shr 16);
commands[i] := long($3120 + long(opcode and $0f)) + (long(j) shl 16);
s := computeCodeSize(commands, i + 1, j);
if (s >= -$80) and (s < $80) then begin
result := result or ((opcode and $0ff0) <> $0120);
continue;
end;
commands[i] := long($4130 + long(opcode and $0f)) + (long(j) shl 16);
s := computeCodeSize(commands, i + 1, j);
if (s >= -$8000) and (s < $8000) then begin
result := result or ((opcode and $0ff0) <> $0130);
continue;
end;
commands[i] := long($6140 + long(opcode and $0f)) + (long(j) shl 16);
result := result or ((opcode and $0ff0) <> $0140);
end;
end;
end;
end;
function JavaStaticRecompiler.reduceSizeofCalls(const commands: long_Array1d; commandsCount: int; offset: int; owner: ConstantPoolContainer): boolean;
var
opcode: int;
size: int;
i: int;
s: int;
c: long;
f: JavaClassMember;
procedure setSize(newSize: int); inline;
begin
if (opcode >= $00b4) and (opcode <= $00b6) then begin
case newSize of
2: begin
commands[i] := long($20b4) + (c and (-$10000));
end;
3: begin
commands[i] := long($30b5) + (c and (-$10000));
end;
5: begin
commands[i] := long($50b6) + (c and (-$10000));
end;
end;
end else begin
commands[i] := (c and (-$f001)) + long(newSize shl 12);
end;
end;
begin
result := false;
for i := 0 to commandsCount - 1 do begin
c := commands[i];
opcode := int(c) and $0fff;
case opcode of
$00b4..$00b6: begin
f := owner.getConstantPoolMember((int(c) shr 16) and $ffff, int(c shr 32) and $ffff, int(c shr 48) and $ffff, 0);
end;
$0f01: begin
f := methodGetString;
end;
$0f02: begin
f := methodCheckObjectArrayAssignable;
end;
$0f04: begin
f := methodGetInterfaceMethodEntryPoint;
end;
$0f05: begin
f := methodAllocateInstance;
end;
$0f07: begin
f := methodArrayCreateOneDim;
end;
$0f08: begin
f := methodArrayCreateMultiDim;
end;
$0f09: begin
f := methodCast;
end;
$0f0a: begin
f := methodIsInstance;
end;
$0f0b: begin
f := methodMonitorEnter;
end;
$0f0c: begin
f := methodMonitorExit;
end;
$0f0f: begin
f := methodMain;
end;
$0f10: begin
f := findClassByName(initOrder.getString(int(c shr 16))).findMemberInternal(NAME_INITIALIZATION, SIGNATURE_NO_PARAMETERS);
end;
else
continue;
end;
size := (int(c) shr 12) and $0f;
setSize(2);
s := f.getOffset() - (offset + computeCodeSize(commands, 0, i + 1));
if (s >= -$80) and (s < $80) then begin
result := result or (size <> 2);
continue;
end;
setSize(3);
s := f.getOffset() - (offset + computeCodeSize(commands, 0, i + 1));
if (s >= -$8000) and (s < $8000) then begin
result := result or (size <> 3);
continue;
end;
setSize(5);
result := result or (size <> 5);
end;
end;
function JavaStaticRecompiler.getStringPoolStringIndex(const str: AnsiString): int;
begin
result := strings.acquireStringIndex(str);
end;
function JavaStaticRecompiler.getClassesCount(): int;
begin
result := classesCount;
end;
function JavaStaticRecompiler.getClass(index: int): JavaClass;
begin
if (index < 0) or (index >= classesCount) then begin
raise ArrayIndexOutOfBoundsException.create(index);
end;
result := classes[index];
end;
function JavaStaticRecompiler.getTypeSize(const signature: AnsiString): int;
begin
result := getTypeSize(signature, alignment);
end;
function JavaStaticRecompiler.getTypeSize(const signature: AnsiString; alignment: boolean): int;
begin
if length(signature) > 0 then begin
case signature[1] of
PREFIX_BOOLEAN, PREFIX_BYTE: begin
if alignment then begin
result := 4;
end else begin
result := 1;
end;
end;
PREFIX_CHAR, PREFIX_SHORT: begin
if alignment then begin
result := 4;
end else begin
result := 2;
end;
end;
PREFIX_OBJECT, PREFIX_ARRAY, PREFIX_FLOAT, PREFIX_INT: begin
result := 4;
end;
PREFIX_DOUBLE, PREFIX_LONG: begin
result := 8;
end;
else
result := 0;
end;
end else begin
result := 0;
end;
end;
function JavaStaticRecompiler.findClassByName(const name: AnsiString): JavaClass;
var
i: int;
cls: JavaClass;
classes: JavaClass_Array1d;
begin
classes := self.primitives;
for i := length(classes) - 1 downto 0 do begin
cls := classes[i];
if cls.getName() = name then begin
result := cls;
exit;
end;
end;
classes := self.classes;
for i := classesCount - 1 downto 0 do begin
cls := classes[i];
if cls.getName() = name then begin
result := cls;
exit;
end;
end;
if (length(name) = 0) or (name[1] <> PREFIX_ARRAY) then begin
raise ClassNotFoundException.create('Класс не найден: ' + name);
end;
result := getArray(name);
end;
function JavaStaticRecompiler.findClassBySignature(const signature: AnsiString): JavaClass;
var
i: int;
cls: JavaClass;
classes: JavaClass_Array1d;
begin
classes := self.primitives;
for i := length(classes) - 1 downto 0 do begin
cls := classes[i];
if cls.getSignature() = signature then begin
result := cls;
exit;
end;
end;
classes := self.classes;
for i := classesCount - 1 downto 0 do begin
cls := classes[i];
if cls.getSignature() = signature then begin
result := cls;
exit;
end;
end;
if (length(signature) = 0) or (signature[1] <> PREFIX_ARRAY) then begin
raise ClassNotFoundException.create('Класс не найден: ' + signature);
end;
result := getArray(signature);
end;
function JavaStaticRecompiler.createInstance(): StaticRecompiler;
var
r: JavaStaticRecompiler;
begin
r := JavaStaticRecompiler.create(coreDirectory, platformName);
r.outStrings := outStrings;
r.alignment := alignment;
r.compressionLevel := compressionLevel;
r.stackSizeInMB := stackSizeInMB;
r.heapSize := heapSize;
r.descSize := descSize;
r.executableFileName := executableFileName;
result := r;
end;
function JavaStaticRecompiler.install(const archive, destinationDirectory: AnsiString): AnsiString;
var
i: int;
len: int;
s: AnsiString;
subDirectory: AnsiString;
outputDirectory: AnsiString;
fileName: AnsiString;
files: UnicodeString_Array1d;
manifestInput: Input;
malikManifest: ProgrammeManifest;
javaManifest: ProgrammeManifest;
jarArchive: ZIPArchiveReader;
coreArchive: ZIPArchiveReader;
inFile: Input;
outFile: Output;
begin
{
1. Выполнить статическую рекомпиляцию
2. Определить папку, куда будем устанавливать программу (назовём её условно <outputDirectory>)
3. Записать исполянемый файл и файлы с отладочной информацией
4. Скопировать файлы из папки <emulator>\java\programme\ в папку <outputDirectory>
5. Извлечь файлы (кроме файлов .class) из архива в папку <outputDirectory>\res
6. Записать файл манифеста
7. Очистить память
}
jarArchive := ZIPArchiveReader.create(FileInputStream.create(archive));
try
manifestInput := jarArchive.openFile(MANIFEST_FILE_NAME);
if manifestInput = nil then begin
raise ManifestNotFoundException.create('В архиве не найден файл манифеста (' + MANIFEST_FILE_NAME + ').');
end;
javaManifest := ProgrammeManifest.create();
try
{ 1. Выполнить статическую рекомпиляцию }
with initOrder do begin
acquireStringIndex(CLASS_MEMORY);
acquireStringIndex(CLASS_CLASS);
acquireStringIndex(CLASS_THREAD);
acquireStringIndex(CLASS_THROWABLE);
acquireStringIndex(CLASS_STRING);
acquireStringIndex(CLASS_STRING_POOL);
acquireStringIndex(CLASS_RUNTIME);
acquireStringIndex(CLASS_SYSTEM);
end;
files := enumerateFiles(coreDirectory, 'jar');
for i := 0 to length(files) - 1 do begin
coreArchive := ZIPArchiveReader.create(FileInputStream.create(files[i]));
try
if isJarArchiveForEmulator(coreArchive) then begin
loadClassesFrom(coreArchive);
end;
finally
coreArchive.free();
end;
end;
loadClassesFrom(jarArchive);
findAncestors();
findSystemMembers();
sortClasses();
preferenceForClassMembers();
prepareMethods();
prepareEntry();
linkClasses();
extractStrings();
assignOffsets();
reduceCodeSize();
computeAvailableMemory();
{ 2. Определить папку, куда будем устанавливать программу (назовём её условно outputDirectory) }
javaManifest.loadFromStream(manifestInput);
s := trim(javaManifest.getValue(MANIFEST_PROPERTY_MIDLET_NAME));
i := length(s);
s := copy(s, 1, i);
while i > 0 do begin
if s[i] in ['\', '/', ':', '*', '?', '"', '<', '>', '|'] then begin
delete(s, i, 1);
end;
dec(i);
end;
if length(s) = 0 then begin
raise ManifestPropertyNotFoundException.create('В манифесте нет свойства ' + MANIFEST_PROPERTY_MIDLET_NAME + 'или оно содержит только недопустимые символы или не имеет символов.');
end;
result := destinationDirectory + s;
if fileExists(result) then begin
for i := 1 to MAX_INT do begin
s := result + ' (' + toDecString(i) + ')';
if fileExists(s) then continue;
result := s;
break;
end;
end;
if not createDirectory(result) then begin
raise IOException.create('Не удалось создать папку программы ' + result);
end;
outputDirectory := result + DIRECTORY_SEPARATOR;
{ 3. Записать исполянемый файл и файлы с отладочной информацией }
s := outputDirectory + executableFileName;
for i := 1 to length(s) do begin
if s[i] = '/' then begin
s[i] := DIRECTORY_SEPARATOR;
end;
end;
createExecutableFile(s + '.mal');
createTextDebugInfoFile(s + '.dbg');
createBinDebugInfoFile(s + '.bindbg');
if outStrings then begin
createStringPoolFile(s + '.txt');
end;
{ 4. Скопировать файлы из папки <emulator>\java\programme\ в папку <outputDirectory> }
copyFiles(coreDirectory + 'programme' + DIRECTORY_SEPARATOR, outputDirectory);
{ 5. Извлечь файлы (кроме файлов .class) из архива в папку <outputDirectory>\res }
subDirectory := outputDirectory + 'res';
if not createDirectory(subDirectory) then begin
raise IOException.create('Не удалось создать папку ' + subDirectory);
end;
s := outputDirectory + 'res' + DIRECTORY_SEPARATOR;
jarArchive.gotoFirstFile();
while not jarArchive.isStayOnEnd() do begin
fileName := jarArchive.getCurrentFileName();
if endsWith(CLASS_FILE_EXTENSION, toLowerCase(fileName)) then begin
jarArchive.gotoNextFile();
continue;
end;
len := length(fileName);
fileName := copy(fileName, 1, len);
if DIRECTORY_SEPARATOR <> '/' then begin
for i := len downto 1 do begin
if fileName[i] = '/' then begin
fileName[i] := DIRECTORY_SEPARATOR;
end;
end;
end;
for i := len downto 1 do begin
if fileName[i] = DIRECTORY_SEPARATOR then begin
subDirectory := s + copy(fileName, 1, i - 1);
if not createDirectory(subDirectory) then begin
raise IOException.create('Не удалось создать папку ' + subDirectory);
end;
break;
end;
end;
inFile := jarArchive.openCurrentFile();
if inFile = nil then begin
continue;
end;
outFile := FileOutputStream.create(s + fileName);
try
copyBytes(inFile, outFile, inFile.available());
finally
inFile := nil;
outFile := nil;
end;
end;
{ 6. Записать файл манифеста }
subDirectory := outputDirectory + MANIFEST_DIRECTORY;
if not createDirectory(subDirectory) then begin
raise IOException.create('Не удалось создать папку ' + subDirectory);
end;
malikManifest := ProgrammeManifest.create();
try
buildMalikManifest(outputDirectory, javaManifest, malikManifest);
malikManifest.saveToFile(outputDirectory + MANIFEST_FILE_PLATFORM_NAME);
finally
malikManifest.free();
end;
{ 7. Очистить память }
finally
javaManifest.free();
end;
finally
jarArchive.free();
clear(); { Убрать всё за собой :=) }
end;
end;
function JavaStaticRecompiler.getPlatformName(): AnsiString;
begin
result := platformName;
end;
function JavaStaticRecompiler.getArchiveTypeName(): AnsiString;
begin
result := 'Архив программ для J2ME';
end;
function JavaStaticRecompiler.getArchiveExtension(): AnsiString;
begin
result := 'jar';
end;
function JavaStaticRecompiler.getAlignment(): boolean;
begin
result := alignment;
end;
function JavaStaticRecompiler.getCompressionLevel(): int;
begin
result := compressionLevel;
end;
function JavaStaticRecompiler.getStackSize(): int;
begin
result := stackSizeInMB;
end;
function JavaStaticRecompiler.getHeapSize(): int;
begin
result := heapSize shr 10;
end;
function JavaStaticRecompiler.getDescriptorsSize(): int;
begin
result := descSize shr 10;
end;
function JavaStaticRecompiler.getOutputExecutableFileName(): AnsiString;
begin
result := '/' + executableFileName;
end;
procedure JavaStaticRecompiler.setDefaults();
begin
alignment := true;
compressionLevel := 0;
stackSizeInMB := 1;
heapSize := 20 shl 20; { 20 МБ }
descSize := heapSize shr 5; { 1/32 от размера кучи }
executableFileName := 'executable';
end;
procedure JavaStaticRecompiler.setAlignment(alignment: boolean);
begin
self.alignment := alignment;
end;
procedure JavaStaticRecompiler.setCompressionLevel(compressionLevel: int);
begin
self.compressionLevel := max(0, min(compressionLevel, 9));
end;
procedure JavaStaticRecompiler.setStackSize(sizeInMB: int);
begin
self.stackSizeInMB := max(1, min(sizeInMB, 16));
end;
procedure JavaStaticRecompiler.setHeapSize(sizeInKB: int);
begin
self.heapSize := max(4 shl 20, min(sizeInKB shl 10, 256 shl 20));
end;
procedure JavaStaticRecompiler.setDescriptorsSize(sizeInKB: int);
begin
self.descSize := sizeInKB shl 10;
end;
procedure JavaStaticRecompiler.setOutputExecutableFileName(const relativeFileName: AnsiString);
begin
if startsWith('/', relativeFileName) then begin
self.executableFileName := copy(relativeFileName, 2, length(relativeFileName) - 1);
end else begin
self.executableFileName := relativeFileName;
end;
end;
function JavaStaticRecompiler.getLongIndex(value: long): int;
begin
result := MIN_INT;
end;
function JavaStaticRecompiler.getDoubleIndex(value: double): int;
begin
result := MIN_INT;
end;
function JavaStaticRecompiler.getStringIndex(const value: AnsiString): int;
begin
result := MIN_INT;
end;
function JavaStaticRecompiler.getConstantPoolLength(): int;
begin
result := 0;
end;
function JavaStaticRecompiler.getConstantPoolEntry(index: int): ConstantPoolEntry;
begin
if (index < -5) or (index >= 0) then begin
raise ArrayIndexOutOfBoundsException.create(index);
end;
result := fdconst[index + 5];
end;
function JavaStaticRecompiler.getConstantPoolMember(index, memberType: int): JavaClassMember;
begin
result := nil;
end;
function JavaStaticRecompiler.getConstantPoolMember(classNameIndex, memberNameIndex, memberSignatureIndex, memberType: int): JavaClassMember;
begin
result := nil;
end;
{%endregion}
{%region ClassMemberDescriptor }
constructor ClassMemberDescriptor.create(const className, memberName, signature: AnsiString);
begin
inherited create();
self.className := className;
self.memberName := memberName;
self.signature := signature;
end;
function ClassMemberDescriptor.getClassName(): AnsiString;
begin
result := className;
end;
function ClassMemberDescriptor.getMemberName(): AnsiString;
begin
result := memberName;
end;
function ClassMemberDescriptor.getSignature(): AnsiString;
begin
result := signature;
end;
function ClassMemberDescriptor.equals(member: JavaClassMember): boolean;
begin
result := (className = member.getOwner().getName()) and (memberName = member.getName()) and (signature = member.getSignature());
end;
{%endregion}
initialization {%region}
PRIMITIVES_NAMES := toStringArray1d([
'boolean', 'char', 'float', 'double', 'byte', 'short', 'int', 'long', 'void'
]);
PRIMITIVES_PREFIXES := toStringArray1d([
PREFIX_BOOLEAN, PREFIX_CHAR, PREFIX_FLOAT, PREFIX_DOUBLE,
PREFIX_BYTE, PREFIX_SHORT, PREFIX_INT, PREFIX_LONG, PREFIX_VOID
]);
MEMBER_TYPES := toStringArray1d([
'статичное поле', 'поле объекта', 'статичный метод', 'метод объекта', 'метод протокола'
]);
MEMBER_DEFAULT_CONSTRUCTOR := ClassMemberDescriptor.create(CLASS_OBJECT, NAME_CONSTRUCTOR, SIGNATURE_NO_PARAMETERS);
MEMBER_STRING_POOL_OFFSET := ClassMemberDescriptor.create(CLASS_MEMORY, 'STRING_POOL_OFFSET', PREFIX_INT);
MEMBER_DESCRIPTORS_SIZE := ClassMemberDescriptor.create(CLASS_MEMORY, 'DESCRIPTORS_SIZE', PREFIX_INT);
MEMBER_HEAP_LIMIT := ClassMemberDescriptor.create(CLASS_MEMORY, 'HEAP_LIMIT', PREFIX_INT);
MEMBER_MONITOR_ENTER := ClassMemberDescriptor.create(CLASS_OBJECT, 'monitorenter', SIGNATURE_NO_PARAMETERS);
MEMBER_MONITOR_EXIT := ClassMemberDescriptor.create(CLASS_OBJECT, 'monitorexit', SIGNATURE_NO_PARAMETERS);
MEMBER_CHECK_OBJECT_ARRAY_ASSIGNABLE := ClassMemberDescriptor.create(CLASS_OBJECT, 'checkObjectArrayAssignable',
HEADER_PREFIX + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + HEADER_SUFFIX + PREFIX_VOID
);
MEMBER_GET_INTERFACE_METHOD_ENTRY_POINT := ClassMemberDescriptor.create(CLASS_CLASS, 'getInterfaceMethodEntryPoint',
HEADER_PREFIX + PREFIX_OBJECT + CLASS_CLASS + SUFFIX_OBJECT + PREFIX_INT + HEADER_SUFFIX + PREFIX_INT
);
MEMBER_ALLOCATE_INSTANCE := ClassMemberDescriptor.create(CLASS_CLASS, 'allocateInstance',
HEADER_PREFIX + HEADER_SUFFIX + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT
);
MEMBER_IS_INSTANCE := ClassMemberDescriptor.create(CLASS_CLASS, 'isInstance',
HEADER_PREFIX + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + HEADER_SUFFIX + PREFIX_BOOLEAN
);
MEMBER_CAST := ClassMemberDescriptor.create(CLASS_CLASS, 'cast',
HEADER_PREFIX + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + HEADER_SUFFIX + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT
);
MEMBER_GET_STRING := ClassMemberDescriptor.create(CLASS_STRING_POOL, 'getString',
HEADER_PREFIX + PREFIX_INT + HEADER_SUFFIX + PREFIX_OBJECT + CLASS_STRING + SUFFIX_OBJECT
);
MEMBER_ARRAY_CREATE_ONE_DIM := ClassMemberDescriptor.create(CLASS_ARRAY, 'create',
HEADER_PREFIX + PREFIX_INT + PREFIX_OBJECT + CLASS_CLASS + SUFFIX_OBJECT + HEADER_SUFFIX + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT
);
MEMBER_ARRAY_CREATE_MULTI_DIM := ClassMemberDescriptor.create(CLASS_ARRAY, 'create',
HEADER_PREFIX + PREFIX_ARRAY + PREFIX_INT + PREFIX_OBJECT + CLASS_CLASS + SUFFIX_OBJECT + HEADER_SUFFIX + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT
);
MEMBER_THROW_ABSTRACT := ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'throwAbstractMethodError', SIGNATURE_NO_PARAMETERS);
MEMBER_MAIN_PROCEDURE := ClassMemberDescriptor.create(CLASS_RUN, 'main', SIGNATURE_NO_PARAMETERS);
NATIVE_METHODS := toClassMemberDescriptorArray1d([
// 0
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'syscall',
HEADER_PREFIX + PREFIX_LONG + PREFIX_INT + HEADER_SUFFIX + PREFIX_LONG
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'getLocalVariableAddress',
HEADER_PREFIX + PREFIX_BOOLEAN + HEADER_SUFFIX + PREFIX_INT
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'getLocalVariableAddress',
HEADER_PREFIX + PREFIX_FLOAT + HEADER_SUFFIX + PREFIX_INT
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'getLocalVariableAddress',
HEADER_PREFIX + PREFIX_DOUBLE + HEADER_SUFFIX + PREFIX_INT
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'getLocalVariableAddress',
HEADER_PREFIX + PREFIX_INT + HEADER_SUFFIX + PREFIX_INT
),
// 5
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'getLocalVariableAddress',
HEADER_PREFIX + PREFIX_LONG + HEADER_SUFFIX + PREFIX_INT
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'getLocalVariableAddress',
HEADER_PREFIX + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + HEADER_SUFFIX + PREFIX_INT
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'getObjectFieldAddress',
HEADER_PREFIX + PREFIX_BOOLEAN + HEADER_SUFFIX + PREFIX_INT
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'getObjectFieldAddress',
HEADER_PREFIX + PREFIX_FLOAT + HEADER_SUFFIX + PREFIX_INT
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'getObjectFieldAddress',
HEADER_PREFIX + PREFIX_DOUBLE + HEADER_SUFFIX + PREFIX_INT
),
// 10
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'getObjectFieldAddress',
HEADER_PREFIX + PREFIX_INT + HEADER_SUFFIX + PREFIX_INT
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'getObjectFieldAddress',
HEADER_PREFIX + PREFIX_LONG + HEADER_SUFFIX + PREFIX_INT
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'getObjectFieldAddress',
HEADER_PREFIX + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + HEADER_SUFFIX + PREFIX_INT
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'interrupt',
HEADER_PREFIX + PREFIX_INT + HEADER_SUFFIX + PREFIX_VOID
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'interrupt',
HEADER_PREFIX + PREFIX_INT + PREFIX_INT + HEADER_SUFFIX + PREFIX_VOID
),
// 15
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'interrupt',
HEADER_PREFIX + PREFIX_LONG + PREFIX_INT + HEADER_SUFFIX + PREFIX_VOID
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'interrupt',
HEADER_PREFIX + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + PREFIX_INT + HEADER_SUFFIX + PREFIX_VOID
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'runExcept',
HEADER_PREFIX + PREFIX_INT + PREFIX_OBJECT + CLASS_THROWABLE + SUFFIX_OBJECT + HEADER_SUFFIX + PREFIX_VOID
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'getFloatAt',
HEADER_PREFIX + PREFIX_INT + HEADER_SUFFIX + PREFIX_FLOAT
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'getDoubleAt',
HEADER_PREFIX + PREFIX_INT + HEADER_SUFFIX + PREFIX_DOUBLE
),
// 20
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'getByteAt',
HEADER_PREFIX + PREFIX_INT + HEADER_SUFFIX + PREFIX_BYTE
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'getShortAt',
HEADER_PREFIX + PREFIX_INT + HEADER_SUFFIX + PREFIX_SHORT
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'getIntAt',
HEADER_PREFIX + PREFIX_INT + HEADER_SUFFIX + PREFIX_INT
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'getLongAt',
HEADER_PREFIX + PREFIX_INT + HEADER_SUFFIX + PREFIX_LONG
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'getObjectAt',
HEADER_PREFIX + PREFIX_INT + HEADER_SUFFIX + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT
),
// 25
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'setFloatAt',
HEADER_PREFIX + PREFIX_INT + PREFIX_FLOAT + HEADER_SUFFIX + PREFIX_VOID
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'setDoubleAt',
HEADER_PREFIX + PREFIX_INT + PREFIX_DOUBLE + HEADER_SUFFIX + PREFIX_VOID
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'setByteAt',
HEADER_PREFIX + PREFIX_INT + PREFIX_BYTE + HEADER_SUFFIX + PREFIX_VOID
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'setShortAt',
HEADER_PREFIX + PREFIX_INT + PREFIX_SHORT + HEADER_SUFFIX + PREFIX_VOID
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'setIntAt',
HEADER_PREFIX + PREFIX_INT + PREFIX_INT + HEADER_SUFFIX + PREFIX_VOID
),
// 30
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'setLongAt',
HEADER_PREFIX + PREFIX_INT + PREFIX_LONG + HEADER_SUFFIX + PREFIX_VOID
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'setObjectAt',
HEADER_PREFIX + PREFIX_INT + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + HEADER_SUFFIX + PREFIX_VOID
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'getCurrentThreadID',
HEADER_PREFIX + HEADER_SUFFIX + PREFIX_INT
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'getReturnAddress',
HEADER_PREFIX + HEADER_SUFFIX + PREFIX_INT
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'convertToReference',
HEADER_PREFIX + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + HEADER_SUFFIX + PREFIX_INT
),
// 35
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'convertToObject',
HEADER_PREFIX + PREFIX_INT + HEADER_SUFFIX + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'getMethodAddress',
HEADER_PREFIX + PREFIX_OBJECT + CLASS_STRING + SUFFIX_OBJECT + HEADER_SUFFIX + PREFIX_INT
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'getClassInstance',
HEADER_PREFIX + PREFIX_OBJECT + CLASS_STRING + SUFFIX_OBJECT + HEADER_SUFFIX + PREFIX_OBJECT + CLASS_CLASS + SUFFIX_OBJECT
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'arraycopyf_byte',
HEADER_PREFIX + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + PREFIX_INT + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + PREFIX_INT + PREFIX_INT + HEADER_SUFFIX + PREFIX_VOID
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'arraycopyf_short',
HEADER_PREFIX + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + PREFIX_INT + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + PREFIX_INT + PREFIX_INT + HEADER_SUFFIX + PREFIX_VOID
),
// 40
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'arraycopyf_int',
HEADER_PREFIX + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + PREFIX_INT + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + PREFIX_INT + PREFIX_INT + HEADER_SUFFIX + PREFIX_VOID
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'arraycopyf_long',
HEADER_PREFIX + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + PREFIX_INT + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + PREFIX_INT + PREFIX_INT + HEADER_SUFFIX + PREFIX_VOID
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'arraycopyf_float',
HEADER_PREFIX + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + PREFIX_INT + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + PREFIX_INT + PREFIX_INT + HEADER_SUFFIX + PREFIX_VOID
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'arraycopyf_double',
HEADER_PREFIX + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + PREFIX_INT + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + PREFIX_INT + PREFIX_INT + HEADER_SUFFIX + PREFIX_VOID
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'arraycopyf_object',
HEADER_PREFIX + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + PREFIX_INT + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + PREFIX_INT + PREFIX_INT + HEADER_SUFFIX + PREFIX_VOID
),
// 45
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'arraycopyb_byte',
HEADER_PREFIX + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + PREFIX_INT + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + PREFIX_INT + PREFIX_INT + HEADER_SUFFIX + PREFIX_VOID
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'arraycopyb_short',
HEADER_PREFIX + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + PREFIX_INT + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + PREFIX_INT + PREFIX_INT + HEADER_SUFFIX + PREFIX_VOID
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'arraycopyb_int',
HEADER_PREFIX + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + PREFIX_INT + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + PREFIX_INT + PREFIX_INT + HEADER_SUFFIX + PREFIX_VOID
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'arraycopyb_long',
HEADER_PREFIX + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + PREFIX_INT + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + PREFIX_INT + PREFIX_INT + HEADER_SUFFIX + PREFIX_VOID
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'arraycopyb_float',
HEADER_PREFIX + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + PREFIX_INT + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + PREFIX_INT + PREFIX_INT + HEADER_SUFFIX + PREFIX_VOID
),
// 50
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'arraycopyb_double',
HEADER_PREFIX + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + PREFIX_INT + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + PREFIX_INT + PREFIX_INT + HEADER_SUFFIX + PREFIX_VOID
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'arraycopyb_object',
HEADER_PREFIX + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + PREFIX_INT + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + PREFIX_INT + PREFIX_INT + HEADER_SUFFIX + PREFIX_VOID
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'arrayfindf_byte',
HEADER_PREFIX + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + PREFIX_INT + PREFIX_INT + HEADER_SUFFIX + PREFIX_INT
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'arrayfindf_short',
HEADER_PREFIX + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + PREFIX_INT + PREFIX_INT + HEADER_SUFFIX + PREFIX_INT
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'arrayfindf_int',
HEADER_PREFIX + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + PREFIX_INT + PREFIX_INT + HEADER_SUFFIX + PREFIX_INT
),
// 55
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'arrayfindf_long',
HEADER_PREFIX + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + PREFIX_INT + PREFIX_LONG + HEADER_SUFFIX + PREFIX_INT
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'arrayfindf_float',
HEADER_PREFIX + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + PREFIX_INT + PREFIX_FLOAT + HEADER_SUFFIX + PREFIX_INT
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'arrayfindf_double',
HEADER_PREFIX + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + PREFIX_INT + PREFIX_DOUBLE + HEADER_SUFFIX + PREFIX_INT
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'arrayfindf_object',
HEADER_PREFIX + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + PREFIX_INT + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + HEADER_SUFFIX + PREFIX_INT
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'arrayfindb_byte',
HEADER_PREFIX + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + PREFIX_INT + PREFIX_INT + HEADER_SUFFIX + PREFIX_INT
),
// 60
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'arrayfindb_short',
HEADER_PREFIX + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + PREFIX_INT + PREFIX_INT + HEADER_SUFFIX + PREFIX_INT
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'arrayfindb_int',
HEADER_PREFIX + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + PREFIX_INT + PREFIX_INT + HEADER_SUFFIX + PREFIX_INT
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'arrayfindb_long',
HEADER_PREFIX + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + PREFIX_INT + PREFIX_LONG + HEADER_SUFFIX + PREFIX_INT
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'arrayfindb_float',
HEADER_PREFIX + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + PREFIX_INT + PREFIX_FLOAT + HEADER_SUFFIX + PREFIX_INT
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'arrayfindb_double',
HEADER_PREFIX + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + PREFIX_INT + PREFIX_DOUBLE + HEADER_SUFFIX + PREFIX_INT
),
// 65
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'arrayfindb_object',
HEADER_PREFIX + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + PREFIX_INT + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + HEADER_SUFFIX + PREFIX_INT
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'arrayfill_byte',
HEADER_PREFIX + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + PREFIX_INT + PREFIX_INT + PREFIX_INT + HEADER_SUFFIX + PREFIX_VOID
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'arrayfill_short',
HEADER_PREFIX + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + PREFIX_INT + PREFIX_INT + PREFIX_INT + HEADER_SUFFIX + PREFIX_VOID
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'arrayfill_int',
HEADER_PREFIX + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + PREFIX_INT + PREFIX_INT + PREFIX_INT + HEADER_SUFFIX + PREFIX_VOID
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'arrayfill_long',
HEADER_PREFIX + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + PREFIX_INT + PREFIX_INT + PREFIX_LONG + HEADER_SUFFIX + PREFIX_VOID
),
// 70
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'arrayfill_object',
HEADER_PREFIX + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + PREFIX_INT + PREFIX_INT + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + HEADER_SUFFIX + PREFIX_VOID
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'findfreef',
HEADER_PREFIX + PREFIX_ARRAY + PREFIX_LONG + PREFIX_INT + PREFIX_INT + HEADER_SUFFIX + PREFIX_INT
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'findfreeb',
HEADER_PREFIX + PREFIX_ARRAY + PREFIX_LONG + PREFIX_INT + PREFIX_INT + HEADER_SUFFIX + PREFIX_INT
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'findzerof',
HEADER_PREFIX + PREFIX_ARRAY + PREFIX_LONG + PREFIX_INT + PREFIX_INT + HEADER_SUFFIX + PREFIX_INT
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'findzerob',
HEADER_PREFIX + PREFIX_ARRAY + PREFIX_LONG + PREFIX_INT + PREFIX_INT + HEADER_SUFFIX + PREFIX_INT
),
// 75
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'getObjectRefs',
HEADER_PREFIX + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + PREFIX_INT + PREFIX_ARRAY + PREFIX_INT + HEADER_SUFFIX + PREFIX_INT
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'getArrayRefs',
HEADER_PREFIX + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + PREFIX_INT + PREFIX_ARRAY + PREFIX_INT + HEADER_SUFFIX + PREFIX_INT
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'blockfindf',
HEADER_PREFIX + PREFIX_ARRAY + PREFIX_LONG + PREFIX_INT + PREFIX_INT + HEADER_SUFFIX + PREFIX_INT
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'blockfindb',
HEADER_PREFIX + PREFIX_ARRAY + PREFIX_LONG + PREFIX_INT + PREFIX_INT + HEADER_SUFFIX + PREFIX_INT
),
ClassMemberDescriptor.create(CLASS_MALIK_SYSTEM, 'invokeDefaultConstructor',
HEADER_PREFIX + PREFIX_OBJECT + CLASS_OBJECT + SUFFIX_OBJECT + HEADER_SUFFIX + PREFIX_VOID
),
// 80
ClassMemberDescriptor.create(CLASS_MATH, 'intPart',
HEADER_PREFIX + PREFIX_DOUBLE + HEADER_SUFFIX + PREFIX_DOUBLE
),
ClassMemberDescriptor.create(CLASS_MATH, 'fracPart',
HEADER_PREFIX + PREFIX_DOUBLE + HEADER_SUFFIX + PREFIX_DOUBLE
),
ClassMemberDescriptor.create(CLASS_MATH, 'sqrt',
HEADER_PREFIX + PREFIX_DOUBLE + HEADER_SUFFIX + PREFIX_DOUBLE
),
ClassMemberDescriptor.create(CLASS_MATH, 'arctan',
HEADER_PREFIX + PREFIX_DOUBLE + PREFIX_DOUBLE + HEADER_SUFFIX + PREFIX_DOUBLE
),
ClassMemberDescriptor.create(CLASS_MATH, 'sin',
HEADER_PREFIX + PREFIX_DOUBLE + HEADER_SUFFIX + PREFIX_DOUBLE
),
// 85
ClassMemberDescriptor.create(CLASS_MATH, 'cos',
HEADER_PREFIX + PREFIX_DOUBLE + HEADER_SUFFIX + PREFIX_DOUBLE
),
ClassMemberDescriptor.create(CLASS_MATH, 'pow2',
HEADER_PREFIX + PREFIX_DOUBLE + HEADER_SUFFIX + PREFIX_DOUBLE
),
ClassMemberDescriptor.create(CLASS_MATH, 'log2',
HEADER_PREFIX + PREFIX_DOUBLE + HEADER_SUFFIX + PREFIX_DOUBLE
),
ClassMemberDescriptor.create(CLASS_MATH, 'floor',
HEADER_PREFIX + PREFIX_DOUBLE + HEADER_SUFFIX + PREFIX_DOUBLE
),
ClassMemberDescriptor.create(CLASS_MATH, 'ceil',
HEADER_PREFIX + PREFIX_DOUBLE + HEADER_SUFFIX + PREFIX_DOUBLE
),
// 90
ClassMemberDescriptor.create(CLASS_MATH, 'round',
HEADER_PREFIX + PREFIX_DOUBLE + HEADER_SUFFIX + PREFIX_LONG
)
]);
addRecompiler(JavaStaticRecompiler.create());
{%endregion}
finalization {%region}
MEMBER_DEFAULT_CONSTRUCTOR.free();
MEMBER_STRING_POOL_OFFSET.free();
MEMBER_DESCRIPTORS_SIZE.free();
MEMBER_HEAP_LIMIT.free();
MEMBER_MONITOR_ENTER.free();
MEMBER_MONITOR_EXIT.free();
MEMBER_CHECK_OBJECT_ARRAY_ASSIGNABLE.free();
MEMBER_GET_INTERFACE_METHOD_ENTRY_POINT.free();
MEMBER_ALLOCATE_INSTANCE.free();
MEMBER_IS_INSTANCE.free();
MEMBER_CAST.free();
MEMBER_GET_STRING.free();
MEMBER_ARRAY_CREATE_ONE_DIM.free();
MEMBER_ARRAY_CREATE_MULTI_DIM.free();
MEMBER_THROW_ABSTRACT.free();
MEMBER_MAIN_PROCEDURE.free();
freeClassMemberDescriptors(NATIVE_METHODS);
{%endregion}
end.