BinarySourceGenerator.avt

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

/*
    Набор генераторов кода для языка программирования
    Объектно-ориентированный продвинутый векторный транслятор

    Copyright © 2021, 2024, 2026 Малик Разработчик

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

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

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

package ru.malik.elaborarer.avtoo.generator;

import avt.io.*;
import avt.io.charset.*;
import avt.util.*;
import platform.independent.filesystem.*;
import ru.malik.elaborarer.avtoo.lang.*;
import ru.malik.elaborarer.compression.zlib.*;

import ru.malik.elaborarer.avtoo.compiler.StringArray;

public class BinarySourceGenerator(CodeGenerator, AVTOOConstants, AVTOORecompilable, AVTOOService)
{
    /*<fold уровни создания файлов двоичного исходного кода>*/
    public static final int CLASS   = 0;
    public static final int PACKAGE = 1;
    public static final int LIBRARY = 2;
    /*</fold>*/

    private static void appendClassType(ClassType type, BinarySourceGeneratorConstants constants, Vector container) throws IOException {
        for(container.append(constants.serializeClassType(type)), boolean isStruct = type.isStruct(), int length = type.length, int index = 0; index < length; index++)
        {
            Code code = null;
            label0:
            {
                Member member = type[index];
                if(member instanceof Method)
                {
                    Method method = (Method) member;
                    code = method.code;
                    container.append(constants.serializeMethod(method));
                    break label0;
                }
                if(member instanceof Callable)
                {
                    Callable callable = (Callable) member;
                    code = callable.code;
                    container.append(constants.serializeCallable(callable));
                    break label0;
                }
                if(member instanceof Property)
                {
                    container.append(constants.serializeProperty((Property) member));
                    continue;
                }
                if(member instanceof Field)
                {
                    container.append(isStruct ? constants.serializeStructField((Field) member) : constants.serializeClassField((Field) member));
                }
                continue;
            }
            if(code != null) container.append(constants.serializeCode(code));
        }
    }

    private static void createRecompilable(Vector container, FileSystem fileSystem, String recompilablePath) throws IOException {
        byte[][] chunks = new byte[container.length][];
        container.copyInto(chunks, 0);
        ByteWriter stream = fileSystem.createFile(recompilablePath + BINARY_SOURCE_EXTENSION);
        try
        {
            with((new DataOutputStream(stream)).bigEndianDataOutput, (Checksum32) new CRC32())
            {
                writeLong(AVTOORecompilable.SIGNATURE_AVTR);
                for(int clength = chunks.length, int cindex = 0; cindex < clength; cindex++)
                {
                    byte[] dbytes = chunks[cindex];
                    int dlength = dbytes.length;
                    update(dbytes, 0, dlength);
                    writeInt(dlength - 4 >> 1);
                    write(dbytes);
                    writeInt(value);
                    reset();
                }
            }
            stream.flush();
        } finally
        {
            stream.close();
        }
    }

    private static Hashtable createSourcesTable(SourceArray sources) {
        Hashtable result = new Hashtable();
        for(int index = sources.length; index-- > 0; )
        {
            TextSource source = (TextSource) sources[index];
            Package owner = source.owner;
            if(owner == null) continue;
            String name = owner.specialCanonicalName;
            ((Vector) (result.contains(name) ? result[name] : result[name] = new Vector())).append(source);
        }
        return result;
    }

    private int fldLevel;
    private String fldOverwritten;

    public (): super(true) { fldLevel = CLASS; }

    public void compile() throws IOException, CompilerException {
        /* -- предыдущие стадии -- */
        super.compile();
        /* 8. Стадия выгрузки данных */
        Charset utf16 = Charset.get("UTF-16 BE");
        Library project = project;
        FileSystem fileSystem = project.fileSystem;
        String destinationPath = fldOverwritten = prepareDestinationPath(fileSystem, project.directoryPath + BINARY_SOURCE_PATH);
        Vector container = new Vector();
        BinarySourceGeneratorConstants constants = new BinarySourceGeneratorConstants();
        byte[] version = BinarySourceGeneratorConstants.serializeVersion();
        byte[] end = BinarySourceGeneratorConstants.serializeEnd();
        switch(fldLevel)
        {
            case LIBRARY:
            {
                {
                    container.append(version);
                    for(Hashtable sourcesTable = createSourcesTable(project.sources), int plength = project.length, int pindex = 0; pindex < plength; pindex++)
                    {
                        Package pack = project[pindex];
                        String packageName = pack.specialCanonicalName;
                        if(packageName.isEmpty()) continue;
                        Vector sourcesList = (Vector) sourcesTable[packageName];
                        TextSource[] sourcesArray = null;
                        if(sourcesList != null) sourcesList.copyInto(sourcesArray = new TextSource[sourcesList.length], 0);
                        container.append(constants.serializePackage(pack));
                        if(sourcesArray != null) for(int slength = sourcesArray.length, int sindex = 0; sindex < slength; sindex++)
                        {
                            TextSource source = sourcesArray[sindex];
                            container.append(BinarySourceGeneratorConstants.serializeTextSource(source, utf16));
                            for(ClassTypeArray declared = source.declared, int dlength = declared.length, int dindex = 0; dindex < dlength; dindex++)
                            {
                                appendClassType(declared[dindex], constants, container);
                            }
                        }
                    }
                    container.insert(1, constants.serializeConstants(utf16));
                    createRecompilable(container.append(end), fileSystem, destinationPath + "!library");
                    container.clear();
                    constants.clear();
                }
                break;
            }
            case PACKAGE:
            {
                for(Hashtable sourcesTable = createSourcesTable(project.sources), int plength = project.length, int pindex = 0; pindex < plength; pindex++)
                {
                    Package pack = project[pindex];
                    String packageName = pack.specialCanonicalName;
                    if(packageName.isEmpty()) continue;
                    Vector sourcesList = (Vector) sourcesTable[packageName];
                    TextSource[] sourcesArray = null;
                    if(sourcesList != null) sourcesList.copyInto(sourcesArray = new TextSource[sourcesList.length], 0);
                    container.append(version).append(constants.serializePackage(pack));
                    if(sourcesArray != null) for(int slength = sourcesArray.length, int sindex = 0; sindex < slength; sindex++)
                    {
                        TextSource source = sourcesArray[sindex];
                        container.append(BinarySourceGeneratorConstants.serializeTextSource(source, utf16));
                        for(ClassTypeArray declared = source.declared, int dlength = declared.length, int dindex = 0; dindex < dlength; dindex++)
                        {
                            appendClassType(declared[dindex], constants, container);
                        }
                    }
                    container.insert(1, constants.serializeConstants(utf16));
                    createRecompilable(container.append(end), fileSystem, destinationPath + packageName);
                    container.clear();
                    constants.clear();
                }
                break;
            }
            default:
            {
                for(int plength = project.length, int pindex = 0; pindex < plength; pindex++)
                {
                    Package pack = project[pindex];
                    String packageName = pack.specialCanonicalName;
                    if(packageName.isEmpty()) continue;
                    String directoryPath = destinationPath + packageName;
                    fileSystem.createDirectory(directoryPath);
                    directoryPath = directoryPath + '/';
                    {
                        container.append(version).append(constants.serializePackage(pack));
                        container.insert(1, constants.serializeConstants(utf16));
                        createRecompilable(container.append(end), fileSystem, directoryPath + "!package");
                        container.clear();
                        constants.clear();
                    }
                    for(int dlength = pack.length, int dindex = 0; dindex < dlength; dindex++)
                    {
                        ClassType type = (ClassType) pack[dindex];
                        if(type instanceof ArrayType) continue;
                        appendClassType(type, constants, container.append(version).append(BinarySourceGeneratorConstants.serializeTextSource((TextSource) type.source, utf16)));
                        container.insert(1, constants.serializeConstants(utf16));
                        createRecompilable(container.append(end), fileSystem, directoryPath + type.specialSimpleName);
                        container.clear();
                        constants.clear();
                    }
                }
            }
        }
        /* -- конец процесса компиляции -- */
    }

    public final String overwritten { read = fldOverwritten }

    public final int level { read = fldLevel, write = fldLevel = value < CLASS ? CLASS : value > LIBRARY ? LIBRARY : value }
}

service BinarySourceGeneratorConstants(Vector, AVTOOConstants, AVTOORecompilable)
{
    public static byte[] serializeVersion() throws IOException {
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        with((new DataOutputStream(stream)).bigEndianDataOutput)
        {
            writeInt(CHUNK_VERS);
            writeInt(VERSION_AVTR);
        }
        return stream.toByteArray();
    }

    public static byte[] serializeTextSource(TextSource source, Charset charset) throws IOException {
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        with((new DataOutputStream(stream)).bigEndianDataOutput)
        {
            writeInt(CHUNK_SURC);
            write(source.textSourcePath.toByteArray(charset));
        }
        return stream.toByteArray();
    }

    public static byte[] serializeEnd() throws IOException {
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        with((new DataOutputStream(stream)).bigEndianDataOutput)
        {
            writeInt(CHUNK_IEND);
        }
        return stream.toByteArray();
    }

    public void clear() {
        super.clear();
        append(null);
    }

    public byte[] serializeConstants(Charset charset) throws IOException {
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        with((new DataOutputStream(stream)).bigEndianDataOutput)
        {
            writeInt(CHUNK_CONS);
            for(Object[] elements = fldElements, int elength = fldLength, int eindex = 1; eindex < elength; eindex++)
            {
                Object element = elements[eindex];
                if(element == null)
                {
                    throw new UnencodableDataException(package.getResourceString("not-encodable.null-pointer"));
                }
                Class type = element.getClass();
                if(Boolean.class == type)
                {
                    writeShort(CONST_Z);
                    writeShort(((Boolean) element).booleanValue ? -1 : 0);
                    continue;
                }
                if(Char.class == type)
                {
                    writeShort(CONST_C);
                    writeShort(((Char) element).charValue);
                    continue;
                }
                if(Real.class == type)
                {
                    writeShort(CONST_R);
                    writeReal(((Real) element).realValue);
                    continue;
                }
                if(Double.class == type)
                {
                    writeShort(CONST_D);
                    writeDouble(((Double) element).doubleValue);
                    continue;
                }
                if(Double2.class == type)
                {
                    writeShort(CONST_D2);
                    writeDouble2(((Double2) element).double2Value);
                    continue;
                }
                if(Double4.class == type)
                {
                    writeShort(CONST_D4);
                    writeDouble4(((Double4) element).double4Value);
                    continue;
                }
                if(Double8.class == type)
                {
                    writeShort(CONST_D8);
                    writeDouble8(((Double8) element).double8Value);
                    continue;
                }
                if(Float.class == type)
                {
                    writeShort(CONST_F);
                    writeFloat(((Float) element).floatValue);
                    continue;
                }
                if(Float2.class == type)
                {
                    writeShort(CONST_F2);
                    writeFloat2(((Float2) element).float2Value);
                    continue;
                }
                if(Float4.class == type)
                {
                    writeShort(CONST_F4);
                    writeFloat4(((Float4) element).float4Value);
                    continue;
                }
                if(Float8.class == type)
                {
                    writeShort(CONST_F8);
                    writeFloat8(((Float8) element).float8Value);
                    continue;
                }
                if(Byte.class == type)
                {
                    writeShort(CONST_B);
                    writeShort(((Byte) element).byteValue);
                    continue;
                }
                if(Byte2.class == type)
                {
                    writeShort(CONST_B2);
                    writeByte2(((Byte2) element).byte2Value);
                    continue;
                }
                if(Byte4.class == type)
                {
                    writeShort(CONST_B4);
                    writeByte4(((Byte4) element).byte4Value);
                    continue;
                }
                if(Byte8.class == type)
                {
                    writeShort(CONST_B8);
                    writeByte8(((Byte8) element).byte8Value);
                    continue;
                }
                if(Short.class == type)
                {
                    writeShort(CONST_S);
                    writeShort(((Short) element).shortValue);
                    continue;
                }
                if(Short2.class == type)
                {
                    writeShort(CONST_S2);
                    writeShort2(((Short2) element).short2Value);
                    continue;
                }
                if(Short4.class == type)
                {
                    writeShort(CONST_S4);
                    writeShort4(((Short4) element).short4Value);
                    continue;
                }
                if(Short8.class == type)
                {
                    writeShort(CONST_S8);
                    writeShort8(((Short8) element).short8Value);
                    continue;
                }
                if(Int.class == type)
                {
                    writeShort(CONST_I);
                    writeInt(((Int) element).intValue);
                    continue;
                }
                if(Int2.class == type)
                {
                    writeShort(CONST_I2);
                    writeInt2(((Int2) element).int2Value);
                    continue;
                }
                if(Int4.class == type)
                {
                    writeShort(CONST_I4);
                    writeInt4(((Int4) element).int4Value);
                    continue;
                }
                if(Int8.class == type)
                {
                    writeShort(CONST_I8);
                    writeInt8(((Int8) element).int8Value);
                    continue;
                }
                if(Long.class == type)
                {
                    writeShort(CONST_J);
                    writeLong(((Long) element).longValue);
                    continue;
                }
                if(Long2.class == type)
                {
                    writeShort(CONST_J2);
                    writeLong2(((Long2) element).long2Value);
                    continue;
                }
                if(Long4.class == type)
                {
                    writeShort(CONST_J4);
                    writeLong4(((Long4) element).long4Value);
                    continue;
                }
                if(Long8.class == type)
                {
                    writeShort(CONST_J8);
                    writeLong8(((Long8) element).long8Value);
                    continue;
                }
                if(String.class == type) with((String) element)
                {
                    writeShort(CONST_ST);
                    writeShort(length);
                    write(toByteArray(charset));
                    continue;
                }
                if(Package.class.isAssignableFrom(type)) with((TableItem) element)
                {
                    writeShort(CONST_PK);
                    writeInt(indexOf(recompilableName));
                    continue;
                }
                if(Type.class.isAssignableFrom(type)) with((TableItem) element)
                {
                    writeShort(CONST_TP);
                    writeInt(indexOf(recompilableName));
                    continue;
                }
                if(Field.class.isAssignableFrom(type)) with((Member) element)
                {
                    writeShort(CONST_FL);
                    writeInt(indexOf(parentType));
                    writeInt(indexOf(recompilableName));
                    continue;
                }
                if(Property.class.isAssignableFrom(type)) with((Member) element)
                {
                    writeShort(CONST_PR);
                    writeInt(indexOf(parentType));
                    writeInt(indexOf(recompilableName));
                    continue;
                }
                if(Callable.class.isAssignableFrom(type)) with((Callable) element, arguments)
                {
                    writeShort(CONST_CL);
                    writeInt(indexOf(parentType));
                    writeInt(indexOf(recompilableName));
                    int alength = length;
                    writeShort(alength);
                    for(int aindex = 0; aindex < alength; aindex++) writeInt(indexOf(operator [](aindex).type));
                    continue;
                }
                throw new UnencodableDataException(String.format(package.getResourceString("not-encodable.constant-type"), new Object[] { type.simpleName }));
            }
        }
        return stream.toByteArray();
    }

    public byte[] serializePackage(Package pack) throws IOException {
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        with((new DataOutputStream(stream)).bigEndianDataOutput)
        {
            writeInt(CHUNK_PACK);
            writeShort(pack.attributes);
            writeInt(indexAcquire(pack.specialCanonicalName));
        }
        return stream.toByteArray();
    }

    public byte[] serializeClassType(ClassType type) throws IOException {
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        with((new DataOutputStream(stream)).bigEndianDataOutput)
        {
            writeInt(CHUNK_TYPE);
            writeShort(type.attributes);
            writeInt(indexAcquire(type.parentPackage));
            writeInt(indexAcquire(type.specialSimpleName));
            if(type.isHelper())
            {
                writeInt(indexAcquire(type.getHelperForType().specialCanonicalName));
            } else
            {
                ClassType supertype = type.getSuperclassType();
                writeInt(supertype == null ? 0 : indexAcquire(supertype.specialCanonicalName));
                for(int length = type.getSuperservicesLength(), int index = 0; index < length; index++)
                {
                    writeInt(indexAcquire(type.getSuperserviceTypeAt(index).specialCanonicalName));
                }
            }
        }
        return stream.toByteArray();
    }

    public byte[] serializeClassField(Field field) throws IOException {
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        with((new DataOutputStream(stream)).bigEndianDataOutput)
        {
            writeInt(CHUNK_CFLD);
            writeShort(field.attributes);
            writeInt(indexAcquire(field.type));
            writeInt(indexAcquire(field.specialSimpleName));
            Constant constant = field.value;
            if(constant != null) writeInt(indexAcquire(constant));
        }
        return stream.toByteArray();
    }

    public byte[] serializeStructField(Field field) throws IOException {
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        with((new DataOutputStream(stream)).bigEndianDataOutput)
        {
            writeInt(CHUNK_SFLD);
            writeShort(field.attributes);
            writeInt(indexAcquire(field.type));
            writeInt(indexAcquire(field.specialSimpleName));
            writeInt(field.capacity);
            writeInt(field.structOffset);
        }
        return stream.toByteArray();
    }

    public byte[] serializeProperty(Property property) throws IOException {
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        with((new DataOutputStream(stream)).bigEndianDataOutput)
        {
            writeInt(CHUNK_PROP);
            writeShort(property.attributes);
            writeInt(indexAcquire(property.type));
            writeInt(indexAcquire(property.specialSimpleName));
            writeInt(indexAcquire(property.indexMember));
            writeInt(indexAcquire(property.storedMember));
            writeInt(indexAcquire(property.readMember));
            writeInt(indexAcquire(property.writeMember));
        }
        return stream.toByteArray();
    }

    public byte[] serializeCallable(Callable callable) throws IOException {
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        with((new DataOutputStream(stream)).bigEndianDataOutput)
        {
            writeInt(CHUNK_OPER);
            writeShort(callable.attributes);
            writeInt(indexAcquire(callable.type));
            writeInt(indexAcquire(callable.specialSimpleName));
            with(callable.arguments)
            {
                int length = length;
                writeShort(length);
                for(int index = 0; index < length; index++) with(operator [](index))
                {
                    writeInt(indexAcquire(type));
                    writeInt(indexAcquire(specialSimpleName));
                }
            }
        }
        return stream.toByteArray();
    }

    public byte[] serializeMethod(Method method) throws IOException {
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        with((new DataOutputStream(stream)).bigEndianDataOutput)
        {
            writeInt(CHUNK_METH);
            writeShort(method.attributes);
            writeInt(indexAcquire(method.type));
            writeInt(indexAcquire(method.specialSimpleName));
            with(method.arguments)
            {
                int length = length;
                writeShort(length);
                for(int index = 0; index < length; index++) with(operator [](index))
                {
                    writeInt(indexAcquire(type));
                    writeInt(indexAcquire(specialSimpleName));
                }
            }
            for(int length = method.getThrowablesLength(), int index = 0; index < length; index++) writeInt(indexAcquire(method.getThrowableTypeAt(index).specialCanonicalName));
        }
        return stream.toByteArray();
    }

    public byte[] serializeCode(Code code) throws IOException {
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        with((new DataOutputStream(stream)).bigEndianDataOutput)
        {
            writeInt(CHUNK_CODE);
            {
                Hashtable primTable = new Hashtable();
                Hashtable refsTable = new Hashtable();
                StringArray primArray = new StringArray();
                StringArray refsArray = new StringArray();
                with(code.locals) for(int length = length, int index = 0; index < length; index++) with(operator [](index)) if(!isConstant())
                {
                    Type type = type;
                    String name = specialSimpleName;
                    if(type.isPrimitive())
                    {
                        if(!primTable.contains(name))
                        {
                            primArray.append(name);
                            primTable[name] = type;
                        } else if(((Type) primTable[name]).fieldWidth < type.fieldWidth)
                        {
                            primTable[name] = type;
                        }
                    } else
                    {
                        if(!refsTable.contains(name))
                        {
                            refsArray.append(name);
                            refsTable[name] = type;
                        }
                    }
                }
                int primLength = primArray.length;
                int refsLength = refsArray.length;
                int length = primLength + refsLength;
                if(length + Int.MIN_VALUE > 0xffff + Int.MIN_VALUE)
                {
                    throw new UnencodableDataException(String.format(package.getResourceString("not-encodable.too-namy-locals"), new Object[] { code.parentCallable }));
                }
                writeShort(length);
                for(int index = 0; index < primLength; index++)
                {
                    String name = primArray[index];
                    Type type = (Type) primTable[name];
                    writeInt(indexAcquire(type));
                    writeInt(indexAcquire(name));
                }
                for(int index = 0; index < refsLength; index++)
                {
                    String name = refsArray[index];
                    Type type = (Type) refsTable[name];
                    writeInt(indexAcquire(type));
                    writeInt(indexAcquire(name));
                }
            }
            for(Local thisArgument = code.parentCallable.arguments.thisArgument, int lastIndex = -1, int clength = code.length, int cindex = 0; cindex < clength; cindex++)
            {
                Node node = code[cindex];
                {
                    int lineIndex = (int) node.location;
                    if(lineIndex >= 0 && lineIndex != lastIndex)
                    {
                        int encoded = encodeDeclare(false, lastIndex = lineIndex);
                        if(isLongEncoded(encoded))
                        {
                            writeInt(encoded);
                        } else
                        {
                            writeShort(encoded);
                        }
                    }
                    if((lineIndex = node.debugIndex) >= 0)
                    {
                        int encoded = encodeDeclare(true, ~lineIndex);
                        if(isLongEncoded(encoded))
                        {
                            writeInt(encoded);
                        } else
                        {
                            writeShort(encoded);
                        }
                    }
                    if((lineIndex = node.labelIndex) >= 0)
                    {
                        int encoded = encodeDeclare(true, lineIndex);
                        if(isLongEncoded(encoded))
                        {
                            writeInt(encoded);
                        } else
                        {
                            writeShort(encoded);
                        }
                    }
                }
                int jlength = node.getJumpCasesLength();
                int nodeInstruction = node.instruction;
                int formInstruction = jlength > 0 ? FLAG_BOOLEAN_JUMP : 0;
                switch(nodeInstruction)
                {
                    case METHOD_ENTER:
                    {
                        writeShort(INST_METHOD_ENTER);
                        writeIndex(((Int) node.reference1).intValue);
                        continue;
                    }
                    case SWAP:
                    {
                        Type type = (Type) node.operand1;
                        writeShort(INST_SWAP | encodeType(type));
                        continue;
                    }
                    case BOUND:
                    case BEGIN:
                    case END:
                    {
                        writeShort(INST_BOUND);
                        continue;
                    }
                    case THROW:
                    {
                        Object type = node.reference1;
                        writeShort(INST_THROW);
                        writeIndex(indexAcquire(type));
                        continue;
                    }
                    case LOAD_STATIC:
                    {
                        TableItem global = node.operand1;
                        if(node.weak)
                        {
                            writeShort(INST_LOAD_STATICW);
                            writeIndex(indexAcquire(global));
                            continue;
                        }
                        writeShort(formInstruction |= INST_LOAD_STATIC);
                        writeIndex(indexAcquire(global));
                        break;
                    }
                    case LOAD_LOCAL:
                    {
                        TypedItem local = (TypedItem) node.operand1;
                        if(node.weak)
                        {
                            writeShort(INST_LOAD_LOCALW | encodeType(REF));
                            writeIndex(local == thisArgument ? 0 : indexOf(local.specialSimpleName));
                            continue;
                        }
                        writeShort(formInstruction |= INST_LOAD_LOCAL | encodeType(local.type));
                        writeIndex(local == thisArgument ? 0 : indexOf(local.specialSimpleName));
                        break;
                    }
                    case LOAD_CONST:
                    {
                        Constant constant = (Constant) node.operand1;
                        if(constant.isReference())
                        {
                            Object reference = constant.asObject();
                            if(reference == null)
                            {
                                writeShort(INST_LOAD_CONST_NULL);
                                continue;
                            }
                            if(reference instanceof RequiredReflectItem)
                            {
                                writeShort(node.weak ? INST_LOAD_CONSTW : INST_LOAD_CONST);
                                writeIndex(indexAcquire(reference));
                                continue;
                            }
                            if(reference instanceof String)
                            {
                                writeShort(INST_LOAD_CONST);
                                writeIndex(indexAcquire(reference));
                                continue;
                            }
                            throw new UnencodableDataException(String.format(package.getResourceString("not-encodable.constant-value"), new Object[] { reference.getClass().canonicalName }));
                        }
                        Type type = constant.type;
                        if(type.isBoolean())
                        {
                            writeShort(INST_LOAD_CONST_BYTE | (constant.asBoolean() ? 0xff : 0x00));
                            continue;
                        }
                        if(type.isInt())
                        {
                            int value = constant.asInt();
                            if(value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE)
                            {
                                writeShort(INST_LOAD_CONST_BYTE | constant.asByte() & 0xff);
                                continue;
                            }
                            if(value >= Short.MIN_VALUE && value <= Short.MAX_VALUE)
                            {
                                writeShort(INST_LOAD_CONST_SHORT);
                                writeShort(value);
                                continue;
                            }
                            writeShort(INST_LOAD_CONST_INT);
                            writeInt(value);
                            continue;
                        }
                        writeShort(INST_LOAD_CONST);
                        writeIndex(indexAcquire(constant));
                        continue;
                    }
                    case READ_ELEMENT:
                    {
                        Type type = (Type) node.operand1;
                        Constant index = (Constant) node.operand2;
                        if(index != null)
                        {
                            writeShort(INST_READ_ELEMENTI | encodeVectorIndex(index.asInt()) | encodeType(type));
                            continue;
                        }
                        writeShort(INST_READ_ELEMENT | encodeType(type));
                        continue;
                    }
                    case READ_COMPONENT:
                    {
                        Type type = (Type) node.operand1;
                        TableItem operand = node.operand2;
                        writeShort(formInstruction |= INST_READ_COMPONENT | encodeOperand(operand) | encodeType(type));
                        if(operand != null) writeIndex(operand == thisArgument ? 0 : !(operand instanceof Local) ? indexAcquire(operand) : indexOf(operand.specialSimpleName));
                        break;
                    }
                    case READ_FIELD:
                    {
                        TableItem fieldoid = node.operand1;
                        TableItem operand = node.operand2;
                        writeShort(formInstruction |= INST_READ_FIELD | encodeOperand(operand));
                        writeIndex(indexAcquire(fieldoid));
                        if(operand != null) writeIndex(operand == thisArgument ? 0 : !(operand instanceof Local) ? indexAcquire(operand) : indexOf(operand.specialSimpleName));
                        break;
                    }
                    case READ_SPECIAL:
                    {
                        TableItem fieldoid = node.operand1;
                        TableItem operand = node.operand2;
                        writeShort(formInstruction |= INST_READ_SPECIAL | encodeOperand(operand));
                        writeIndex(indexAcquire(fieldoid));
                        if(operand != null) writeIndex(operand == thisArgument ? 0 : !(operand instanceof Local) ? indexAcquire(operand) : indexOf(operand.specialSimpleName));
                        break;
                    }
                    case READ_PROPERTY:
                    {
                        TableItem fieldoid = node.operand1;
                        TableItem operand = node.operand2;
                        writeShort(formInstruction |= INST_READ_PROPERTY | encodeOperand(operand));
                        writeIndex(indexAcquire(fieldoid));
                        if(operand != null) writeIndex(operand == thisArgument ? 0 : !(operand instanceof Local) ? indexAcquire(operand) : indexOf(operand.specialSimpleName));
                        break;
                    }
                    case STORE_STATIC:
                    {
                        TableItem global = node.operand1;
                        Constant constant = (Constant) node.operand2;
                        if(constant != null)
                        {
                            if(constant.isNull())
                            {
                                writeShort(INST_STORE_STATIC_NULL);
                                writeIndex(indexAcquire(global));
                                continue;
                            }
                            Type type = constant.type;
                            if(type.isBoolean())
                            {
                                writeShort(formInstruction |= INST_STORE_STATIC_SHORT);
                                writeIndex(indexAcquire(global));
                                writeShort(constant.asBoolean() ? -1 : 0);
                                break;
                            }
                            if(type.isInt())
                            {
                                int value = constant.asInt();
                                if(value >= Short.MIN_VALUE && value <= Short.MAX_VALUE)
                                {
                                    writeShort(INST_STORE_STATIC_SHORT);
                                    writeIndex(indexAcquire(global));
                                    writeShort(value);
                                    continue;
                                }
                                writeShort(INST_STORE_STATIC_INT);
                                writeIndex(indexAcquire(global));
                                writeInt(value);
                                continue;
                            }
                            throw new UnencodableDataException(String.format(package.getResourceString("not-encodable.assignable.global"), new Object[] { type }));
                        }
                        writeShort(formInstruction |= INST_STORE_STATIC);
                        writeIndex(indexAcquire(global));
                        break;
                    }
                    case STORE_LOCAL:
                    case DECLARE_WITH:
                    case DECLARE_LOCAL:
                    {
                        int store = nodeInstruction - (STORE_LOCAL - STORE_NORMAL);
                        TypedItem local = (TypedItem) node.operand1;
                        Constant constant = (Constant) node.operand2;
                        if(constant != null)
                        {
                            if(constant.isNull())
                            {
                                writeShort(INST_STORE_LOCAL_NULL | encodeStore(store) | encodeType(REF));
                                writeIndex(local == thisArgument ? 0 : indexOf(local.specialSimpleName));
                                continue;
                            }
                            Type type = constant.type;
                            if(type.isBoolean())
                            {
                                writeShort(formInstruction |= INST_STORE_LOCAL_SHORT | encodeStore(store) | encodeType(BOOLEAN));
                                writeIndex(local == thisArgument ? 0 : indexOf(local.specialSimpleName));
                                writeShort(constant.asBoolean() ? -1 : 0);
                                break;
                            }
                            if(type.isInt())
                            {
                                int value = constant.asInt();
                                if(value >= Short.MIN_VALUE && value <= Short.MAX_VALUE)
                                {
                                    writeShort(INST_STORE_LOCAL_SHORT | encodeStore(store) | encodeType(type));
                                    writeIndex(local == thisArgument ? 0 : indexOf(local.specialSimpleName));
                                    writeShort(value);
                                    continue;
                                }
                                writeShort(INST_STORE_LOCAL_INT | encodeStore(store) | encodeType(type));
                                writeIndex(local == thisArgument ? 0 : indexOf(local.specialSimpleName));
                                writeInt(value);
                                continue;
                            }
                            throw new UnencodableDataException(String.format(package.getResourceString("not-encodable.assignable.local"), new Object[] { type }));
                        }
                        writeShort(formInstruction |= INST_STORE_LOCAL | encodeStore(store) | encodeType(local.type));
                        writeIndex(local == thisArgument ? 0 : indexOf(local.specialSimpleName));
                        break;
                    }
                    case INC_PRED_LOAD_LOCAL:
                    {
                        TypedItem local = (TypedItem) node.operand1;
                        writeShort(INST_INC_PRED_LOAD_LOCAL | encodeType(local.type));
                        writeIndex(indexOf(local.specialSimpleName));
                        continue;
                    }
                    case DEC_PRED_LOAD_LOCAL:
                    {
                        TypedItem local = (TypedItem) node.operand1;
                        writeShort(INST_DEC_PRED_LOAD_LOCAL | encodeType(local.type));
                        writeIndex(indexOf(local.specialSimpleName));
                        continue;
                    }
                    case INC_POST_LOAD_LOCAL:
                    {
                        TypedItem local = (TypedItem) node.operand1;
                        writeShort(INST_INC_POST_LOAD_LOCAL | encodeType(local.type));
                        writeIndex(indexOf(local.specialSimpleName));
                        continue;
                    }
                    case DEC_POST_LOAD_LOCAL:
                    {
                        TypedItem local = (TypedItem) node.operand1;
                        writeShort(INST_DEC_POST_LOAD_LOCAL | encodeType(local.type));
                        writeIndex(indexOf(local.specialSimpleName));
                        continue;
                    }
                    case WRITE_COMPONENT:
                    {
                        Type type = (Type) node.operand1;
                        writeShort(formInstruction |= INST_WRITE_COMPONENT | encodeType(type));
                        break;
                    }
                    case WRITE_FIELD:
                    {
                        TableItem fieldoid = node.operand1;
                        writeShort(formInstruction |= INST_WRITE_FIELD);
                        writeIndex(indexAcquire(fieldoid));
                        break;
                    }
                    case WRITE_SPECIAL:
                    {
                        TableItem fieldoid = node.operand1;
                        writeShort(formInstruction |= INST_WRITE_SPECIAL);
                        writeIndex(indexAcquire(fieldoid));
                        break;
                    }
                    case WRITE_PROPERTY:
                    {
                        TableItem fieldoid = node.operand1;
                        writeShort(formInstruction |= INST_WRITE_PROPERTY);
                        writeIndex(indexAcquire(fieldoid));
                        break;
                    }
                    case BRANCH:
                    {
                        if(jlength > 0)
                        {
                            int min = node.getJumpCaseValueAt(0);
                            int max = min;
                            for(int jindex = 1; jindex < jlength; jindex++)
                            {
                                int cur = node.getJumpCaseValueAt(jindex);
                                if(min > cur) min = cur;
                                if(max < cur) max = cur;
                            }
                            Node jumpDefault = node.jumpDefault;
                            if(((long) max - min + 2) <= ((long) jlength << 1))
                            {
                                writeShort(INST_SWITCH_TABLE);
                                writeInt(min);
                                writeIndex(jlength = max - min + 1);
                                for(int jvalue = min, int jindex = 0; jindex < jlength; jvalue++, jindex++)
                                {
                                    Node target = node.getJumpCase(jvalue);
                                    if(target == null) target = jumpDefault;
                                    writeLabel(target);
                                }
                            } else
                            {
                                writeShort(INST_SWITCH_LOOKUP);
                                writeIndex(jlength);
                                for(int jindex = 0; jindex < jlength; jindex++)
                                {
                                    int jvalue = node.getJumpCaseValueAt(jindex);
                                    Node target = node.getJumpCaseNodeAt(jindex);
                                    writeInt(jvalue);
                                    writeLabel(target);
                                }
                            }
                            writeLabel(jumpDefault);
                            continue;
                        }
                        /* падение через */
                    }
                    case JUMP:
                    case RETURN:
                    {
                        writeShort(INST_JUMP);
                        writeLabel(node.jumpDefault);
                        continue;
                    }
                    case LOAD_INTERRUPT:
                    {
                        TableItem callable = node.operand1;
                        writeShort(INST_LOAD_INTERRUPT);
                        writeIndex(indexAcquire(callable));
                        continue;
                    }
                    case REF_EQ:
                    {
                        TableItem operand = node.operand1;
                        writeShort(formInstruction |= (node.weak ? INST_REF_EQW : INST_REF_EQ) | encodeOperand(operand) | encodeType(REF));
                        if(operand != null) writeIndex(operand == thisArgument ? 0 : !(operand instanceof Local) ? indexAcquire(operand) : indexOf(operand.specialSimpleName));
                        break;
                    }
                    case REF_NE:
                    {
                        TableItem operand = node.operand1;
                        writeShort(formInstruction |= (node.weak ? INST_REF_NEW : INST_REF_NE) | encodeOperand(operand) | encodeType(REF));
                        if(operand != null) writeIndex(operand == thisArgument ? 0 : !(operand instanceof Local) ? indexAcquire(operand) : indexOf(operand.specialSimpleName));
                        break;
                    }
                    case REF_IS_NULL:
                    {
                        writeShort(formInstruction |= (node.weak ? INST_REF_IS_NULLW : INST_REF_IS_NULL) | encodeType(REF));
                        break;
                    }
                    case REF_IS_OBJECT:
                    {
                        writeShort(formInstruction |= (node.weak ? INST_REF_IS_OBJECTW : INST_REF_IS_OBJECT) | encodeType(REF));
                        break;
                    }
                    case CLINIT_TRY_LOCK:
                    {
                        TableItem operand = node.operand1;
                        writeShort(formInstruction |= INST_CLINIT_TRY_LOCK);
                        writeIndex(indexAcquire(operand));
                        break;
                    }
                    case CLINIT_UNLOCK:
                    {
                        TableItem operand = node.operand1;
                        writeShort(INST_CLINIT_UNLOCK);
                        writeIndex(indexAcquire(operand));
                        continue;
                    }
                    case MONITOR_ENTER:
                    {
                        writeShort(INST_MONITOR_ENTER | encodeType(REF));
                        continue;
                    }
                    case MONITOR_LEAVE:
                    {
                        writeShort(INST_MONITOR_LEAVE | encodeType(REF));
                        continue;
                    }
                    case FINALLY_ENTER:
                    {
                        writeShort(INST_FINALLY_ENTER);
                        continue;
                    }
                    case FINALLY_LEAVE:
                    {
                        writeShort(INST_FINALLY_LEAVE);
                        continue;
                    }
                    case NEW_ARRAY:
                    {
                        TableItem type = node.operand1;
                        Constant length = (Constant) node.operand2;
                        writeShort(INST_NEW_ARRAY);
                        writeIndex(indexAcquire(type));
                        writeInt(length.asInt());
                        continue;
                    }
                    case INVOKE_FINALLY:
                    {
                        Node target = (Node) node.reference1;
                        writeShort(INST_INVOKE_FINALLY);
                        writeLabel(target);
                        continue;
                    }
                    case INVOKE_STATIC:
                    {
                        TableItem callable = node.operand1;
                        writeShort(formInstruction |= node.weak ? INST_INVOKE_STATICD : INST_INVOKE_STATIC);
                        writeIndex(indexAcquire(callable));
                        break;
                    }
                    case INVOKE_SPECIAL:
                    {
                        TableItem callable = node.operand1;
                        writeShort(formInstruction |= node.weak ? INST_INVOKE_SPECIALD : INST_INVOKE_SPECIAL);
                        writeIndex(indexAcquire(callable));
                        break;
                    }
                    case INVOKE_VIRTUAL:
                    {
                        TableItem callable = node.operand1;
                        writeShort(formInstruction |= node.weak ? INST_INVOKE_VIRTUALD : INST_INVOKE_VIRTUAL);
                        writeIndex(indexAcquire(callable));
                        break;
                    }
                    case INVOKE_SERVICE:
                    {
                        TableItem callable = node.operand1;
                        writeShort(formInstruction |= node.weak ? INST_INVOKE_SERVICED : INST_INVOKE_SERVICE);
                        writeIndex(indexAcquire(callable));
                        break;
                    }
                    case O_VECT_DIV:
                    {
                        Type type = (Type) node.operand1;
                        TableItem operand = node.operand2;
                        writeShort(INST_VECT_DIV | encodeOperand(operand) | encodeType(type));
                        if(operand != null) writeIndex(operand instanceof Local ? indexOf(operand.specialSimpleName) : indexAcquire(operand));
                        continue;
                    }
                    case O_VECT_PCK:
                    {
                        Type type = (Type) node.operand1;
                        writeShort(INST_VECT_PCK | encodeType(type));
                        continue;
                    }
                    case O_VECT_LUP:
                    {
                        Type type = (Type) node.operand1;
                        writeShort(INST_VECT_LUP | encodeType(type));
                        continue;
                    }
                    case O_VECT_UUP:
                    {
                        Type type = (Type) node.operand1;
                        writeShort(INST_VECT_UUP | encodeType(type));
                        continue;
                    }
                    case O_VECT_MUL:
                    {
                        Type type = (Type) node.operand1;
                        TableItem operand = node.operand2;
                        writeShort(INST_VECT_MUL | encodeOperand(operand) | encodeType(type));
                        if(operand != null) writeIndex(operand instanceof Local ? indexOf(operand.specialSimpleName) : indexAcquire(operand));
                        continue;
                    }
                    case O_VECT_SHL:
                    {
                        Type type = (Type) node.operand1;
                        TableItem operand = node.operand2;
                        writeShort(INST_VECT_SHL | encodeOperand(operand) | encodeType(type));
                        if(operand != null) writeIndex(operand instanceof Local ? indexOf(operand.specialSimpleName) : indexAcquire(operand));
                        continue;
                    }
                    case O_VECT_SHR:
                    {
                        Type type = (Type) node.operand1;
                        TableItem operand = node.operand2;
                        writeShort(INST_VECT_SHR | encodeOperand(operand) | encodeType(type));
                        if(operand != null) writeIndex(operand instanceof Local ? indexOf(operand.specialSimpleName) : indexAcquire(operand));
                        continue;
                    }
                    case O_VECT_SHRU:
                    {
                        Type type = (Type) node.operand1;
                        TableItem operand = node.operand2;
                        writeShort(INST_VECT_SHRU | encodeOperand(operand) | encodeType(type));
                        if(operand != null) writeIndex(operand instanceof Local ? indexOf(operand.specialSimpleName) : indexAcquire(operand));
                        continue;
                    }
                    case O_VECT_ADD:
                    {
                        Type type = (Type) node.operand1;
                        TableItem operand = node.operand2;
                        writeShort(INST_VECT_ADD | encodeOperand(operand) | encodeType(type));
                        if(operand != null) writeIndex(operand instanceof Local ? indexOf(operand.specialSimpleName) : indexAcquire(operand));
                        continue;
                    }
                    case O_VECT_SUB:
                    {
                        Type type = (Type) node.operand1;
                        TableItem operand = node.operand2;
                        writeShort(INST_VECT_SUB | encodeOperand(operand) | encodeType(type));
                        if(operand != null) writeIndex(operand instanceof Local ? indexOf(operand.specialSimpleName) : indexAcquire(operand));
                        continue;
                    }
                    case O_VECT_EQ:
                    {
                        Type type = (Type) node.operand1;
                        TableItem operand = node.operand2;
                        writeShort(INST_VECT_EQ | encodeOperand(operand) | encodeType(type));
                        if(operand != null) writeIndex(operand instanceof Local ? indexOf(operand.specialSimpleName) : indexAcquire(operand));
                        continue;
                    }
                    case O_VECT_NE:
                    {
                        Type type = (Type) node.operand1;
                        TableItem operand = node.operand2;
                        writeShort(INST_VECT_NE | encodeOperand(operand) | encodeType(type));
                        if(operand != null) writeIndex(operand instanceof Local ? indexOf(operand.specialSimpleName) : indexAcquire(operand));
                        continue;
                    }
                    case O_VECT_GT:
                    {
                        Type type = (Type) node.operand1;
                        TableItem operand = node.operand2;
                        writeShort(INST_VECT_GT | encodeOperand(operand) | encodeType(type));
                        if(operand != null) writeIndex(operand instanceof Local ? indexOf(operand.specialSimpleName) : indexAcquire(operand));
                        continue;
                    }
                    case O_VECT_GE:
                    {
                        Type type = (Type) node.operand1;
                        TableItem operand = node.operand2;
                        writeShort(INST_VECT_GE | encodeOperand(operand) | encodeType(type));
                        if(operand != null) writeIndex(operand instanceof Local ? indexOf(operand.specialSimpleName) : indexAcquire(operand));
                        continue;
                    }
                    case O_VECT_LT:
                    {
                        Type type = (Type) node.operand1;
                        TableItem operand = node.operand2;
                        writeShort(INST_VECT_LT | encodeOperand(operand) | encodeType(type));
                        if(operand != null) writeIndex(operand instanceof Local ? indexOf(operand.specialSimpleName) : indexAcquire(operand));
                        continue;
                    }
                    case O_VECT_LE:
                    {
                        Type type = (Type) node.operand1;
                        TableItem operand = node.operand2;
                        writeShort(INST_VECT_LE | encodeOperand(operand) | encodeType(type));
                        if(operand != null) writeIndex(operand instanceof Local ? indexOf(operand.specialSimpleName) : indexAcquire(operand));
                        continue;
                    }
                    case O_SCAL_DIV:
                    {
                        Type type = (Type) node.operand1;
                        TableItem operand = node.operand2;
                        writeShort(INST_SCAL_DIV | encodeOperand(operand) | encodeType(type));
                        if(operand != null) writeIndex(operand instanceof Local ? indexOf(operand.specialSimpleName) : indexAcquire(operand));
                        continue;
                    }
                    case O_SCAL_DIVU:
                    {
                        Type type = (Type) node.operand1;
                        TableItem operand = node.operand2;
                        writeShort(INST_SCAL_DIVU | encodeOperand(operand) | encodeType(type));
                        if(operand != null) writeIndex(operand instanceof Local ? indexOf(operand.specialSimpleName) : indexAcquire(operand));
                        continue;
                    }
                    case O_SCAL_REM:
                    {
                        Type type = (Type) node.operand1;
                        TableItem operand = node.operand2;
                        writeShort(INST_SCAL_REM | encodeOperand(operand) | encodeType(type));
                        if(operand != null) writeIndex(operand instanceof Local ? indexOf(operand.specialSimpleName) : indexAcquire(operand));
                        continue;
                    }
                    case O_SCAL_REMU:
                    {
                        Type type = (Type) node.operand1;
                        TableItem operand = node.operand2;
                        writeShort(INST_SCAL_REMU | encodeOperand(operand) | encodeType(type));
                        if(operand != null) writeIndex(operand instanceof Local ? indexOf(operand.specialSimpleName) : indexAcquire(operand));
                        continue;
                    }
                    case O_SCAL_MUL:
                    {
                        Type type = (Type) node.operand1;
                        TableItem operand = node.operand2;
                        writeShort(INST_SCAL_MUL | encodeOperand(operand) | encodeType(type));
                        if(operand != null) writeIndex(operand instanceof Local ? indexOf(operand.specialSimpleName) : indexAcquire(operand));
                        continue;
                    }
                    case O_SCAL_SHL:
                    {
                        Type type = (Type) node.operand1;
                        TableItem operand = node.operand2;
                        writeShort(INST_SCAL_SHL | encodeOperand(operand) | encodeType(type));
                        if(operand != null) writeIndex(operand instanceof Local ? indexOf(operand.specialSimpleName) : indexAcquire(operand));
                        continue;
                    }
                    case O_SCAL_SHR:
                    {
                        Type type = (Type) node.operand1;
                        TableItem operand = node.operand2;
                        writeShort(INST_SCAL_SHR | encodeOperand(operand) | encodeType(type));
                        if(operand != null) writeIndex(operand instanceof Local ? indexOf(operand.specialSimpleName) : indexAcquire(operand));
                        continue;
                    }
                    case O_SCAL_SHRU:
                    {
                        Type type = (Type) node.operand1;
                        TableItem operand = node.operand2;
                        writeShort(INST_SCAL_SHRU | encodeOperand(operand) | encodeType(type));
                        if(operand != null) writeIndex(operand instanceof Local ? indexOf(operand.specialSimpleName) : indexAcquire(operand));
                        continue;
                    }
                    case O_SCAL_ADD:
                    {
                        Type type = (Type) node.operand1;
                        TableItem operand = node.operand2;
                        writeShort(INST_SCAL_ADD | encodeOperand(operand) | encodeType(type));
                        if(operand != null) writeIndex(operand instanceof Local ? indexOf(operand.specialSimpleName) : indexAcquire(operand));
                        continue;
                    }
                    case O_SCAL_SUB:
                    {
                        Type type = (Type) node.operand1;
                        TableItem operand = node.operand2;
                        writeShort(INST_SCAL_SUB | encodeOperand(operand) | encodeType(type));
                        if(operand != null) writeIndex(operand instanceof Local ? indexOf(operand.specialSimpleName) : indexAcquire(operand));
                        continue;
                    }
                    case O_SCAL_EQ:
                    {
                        Type type = (Type) node.operand1;
                        TableItem operand = node.operand2;
                        writeShort(formInstruction |= INST_SCAL_EQ | encodeOperand(operand) | encodeType(type));
                        if(operand != null) writeIndex(operand instanceof Local ? indexOf(operand.specialSimpleName) : indexAcquire(operand));
                        break;
                    }
                    case O_SCAL_NE:
                    {
                        Type type = (Type) node.operand1;
                        TableItem operand = node.operand2;
                        writeShort(formInstruction |= INST_SCAL_NE | encodeOperand(operand) | encodeType(type));
                        if(operand != null) writeIndex(operand instanceof Local ? indexOf(operand.specialSimpleName) : indexAcquire(operand));
                        break;
                    }
                    case O_SCAL_GT:
                    {
                        Type type = (Type) node.operand1;
                        TableItem operand = node.operand2;
                        writeShort(formInstruction |= INST_SCAL_GT | encodeOperand(operand) | encodeType(type));
                        if(operand != null) writeIndex(operand instanceof Local ? indexOf(operand.specialSimpleName) : indexAcquire(operand));
                        break;
                    }
                    case O_SCAL_GE:
                    {
                        Type type = (Type) node.operand1;
                        TableItem operand = node.operand2;
                        writeShort(formInstruction |= INST_SCAL_GE | encodeOperand(operand) | encodeType(type));
                        if(operand != null) writeIndex(operand instanceof Local ? indexOf(operand.specialSimpleName) : indexAcquire(operand));
                        break;
                    }
                    case O_SCAL_LT:
                    {
                        Type type = (Type) node.operand1;
                        TableItem operand = node.operand2;
                        writeShort(formInstruction |= INST_SCAL_LT | encodeOperand(operand) | encodeType(type));
                        if(operand != null) writeIndex(operand instanceof Local ? indexOf(operand.specialSimpleName) : indexAcquire(operand));
                        break;
                    }
                    case O_SCAL_LE:
                    {
                        Type type = (Type) node.operand1;
                        TableItem operand = node.operand2;
                        writeShort(formInstruction |= INST_SCAL_LE | encodeOperand(operand) | encodeType(type));
                        if(operand != null) writeIndex(operand instanceof Local ? indexOf(operand.specialSimpleName) : indexAcquire(operand));
                        break;
                    }
                    case O_VECT_NEG:
                    {
                        Type type = (Type) node.operand1;
                        writeShort(INST_VECT_NEG | encodeType(type));
                        continue;
                    }
                    case CAST_TO:
                    {
                        TableItem newType = node.operand1;
                        Type oldType = (Type) node.operand2;
                        writeShort(INST_CAST_TO | encodeType(oldType));
                        writeIndex(indexAcquire(newType));
                        continue;
                    }
                    case INC_LOCAL:
                    {
                        TypedItem local = (TypedItem) node.operand1;
                        writeShort(INST_INC_LOCAL | encodeType(local.type));
                        writeIndex(indexOf(local.specialSimpleName));
                        continue;
                    }
                    case DEC_LOCAL:
                    {
                        TypedItem local = (TypedItem) node.operand1;
                        writeShort(INST_DEC_LOCAL | encodeType(local.type));
                        writeIndex(indexOf(local.specialSimpleName));
                        continue;
                    }
                    case O_BIT_NOT:
                    {
                        Type type = (Type) node.operand1;
                        writeShort(formInstruction |= INST_BIT_NOT | encodeType(type));
                        break;
                    }
                    case O_BIT_AND:
                    {
                        Type type = (Type) node.operand1;
                        TableItem operand = node.operand2;
                        writeShort(formInstruction |= INST_BIT_AND | encodeOperand(operand) | encodeType(type));
                        if(operand != null) writeIndex(operand instanceof Local ? indexOf(operand.specialSimpleName) : indexAcquire(operand));
                        break;
                    }
                    case O_BIT_OR:
                    {
                        Type type = (Type) node.operand1;
                        TableItem operand = node.operand2;
                        writeShort(formInstruction |= INST_BIT_OR | encodeOperand(operand) | encodeType(type));
                        if(operand != null) writeIndex(operand instanceof Local ? indexOf(operand.specialSimpleName) : indexAcquire(operand));
                        break;
                    }
                    case O_BIT_XOR:
                    {
                        Type type = (Type) node.operand1;
                        TableItem operand = node.operand2;
                        writeShort(formInstruction |= INST_BIT_XOR | encodeOperand(operand) | encodeType(type));
                        if(operand != null) writeIndex(operand instanceof Local ? indexOf(operand.specialSimpleName) : indexAcquire(operand));
                        break;
                    }
                    case DUP1:
                    {
                        Type type = (Type) node.operand1;
                        writeShort(INST_DUP1 | encodeType(type));
                        continue;
                    }
                    case DUP2:
                    {
                        Type type = (Type) node.operand1;
                        writeShort(INST_DUP2 | encodeType(type));
                        continue;
                    }
                    case O_VECT_HMUL:
                    {
                        Type type = (Type) node.operand1;
                        TableItem operand = node.operand2;
                        writeShort(INST_VECT_HMUL | encodeOperand(operand) | encodeType(type));
                        if(operand != null) writeIndex(operand instanceof Local ? indexOf(operand.specialSimpleName) : indexAcquire(operand));
                        continue;
                    }
                    case O_VECT_HMULU:
                    {
                        Type type = (Type) node.operand1;
                        TableItem operand = node.operand2;
                        writeShort(INST_VECT_HMULU | encodeOperand(operand) | encodeType(type));
                        if(operand != null) writeIndex(operand instanceof Local ? indexOf(operand.specialSimpleName) : indexAcquire(operand));
                        continue;
                    }
                    case O_VECT_SADD:
                    {
                        Type type = (Type) node.operand1;
                        TableItem operand = node.operand2;
                        writeShort(INST_VECT_SADD | encodeOperand(operand) | encodeType(type));
                        if(operand != null) writeIndex(operand instanceof Local ? indexOf(operand.specialSimpleName) : indexAcquire(operand));
                        continue;
                    }
                    case O_VECT_SADDU:
                    {
                        Type type = (Type) node.operand1;
                        TableItem operand = node.operand2;
                        writeShort(INST_VECT_SADDU | encodeOperand(operand) | encodeType(type));
                        if(operand != null) writeIndex(operand instanceof Local ? indexOf(operand.specialSimpleName) : indexAcquire(operand));
                        continue;
                    }
                    case O_VECT_SSUB:
                    {
                        Type type = (Type) node.operand1;
                        TableItem operand = node.operand2;
                        writeShort(INST_VECT_SSUB | encodeOperand(operand) | encodeType(type));
                        if(operand != null) writeIndex(operand instanceof Local ? indexOf(operand.specialSimpleName) : indexAcquire(operand));
                        continue;
                    }
                    case O_VECT_SSUBU:
                    {
                        Type type = (Type) node.operand1;
                        TableItem operand = node.operand2;
                        writeShort(INST_VECT_SSUBU | encodeOperand(operand) | encodeType(type));
                        if(operand != null) writeIndex(operand instanceof Local ? indexOf(operand.specialSimpleName) : indexAcquire(operand));
                        continue;
                    }
                    case O_SCAL_NEG:
                    {
                        Type type = (Type) node.operand1;
                        writeShort(INST_SCAL_NEG | encodeType(type));
                        continue;
                    }
                    case INSTANCEOF:
                    {
                        TableItem type = node.operand1;
                        writeShort(formInstruction |= INST_INSTANCE_OF | encodeType(REF));
                        writeIndex(indexAcquire(type));
                        break;
                    }
                    case TEST_EQZ:
                    {
                        Type type = (Type) node.operand1;
                        TableItem operand = node.operand2;
                        writeShort(formInstruction |= INST_TEST_EQZ | encodeOperand(operand) | encodeType(type));
                        if(operand != null) writeIndex(operand instanceof Local ? indexOf(operand.specialSimpleName) : indexAcquire(operand));
                        break;
                    }
                    case TEST_NEZ:
                    {
                        Type type = (Type) node.operand1;
                        TableItem operand = node.operand2;
                        writeShort(formInstruction |= INST_TEST_NEZ | encodeOperand(operand) | encodeType(type));
                        if(operand != null) writeIndex(operand instanceof Local ? indexOf(operand.specialSimpleName) : indexAcquire(operand));
                        break;
                    }
                    case NEW_VECTOR:
                    {
                        Type type = (Type) node.operand1;
                        writeShort(INST_NEW_VECTOR | encodeType(type));
                        continue;
                    }
                    case NEW_INSTANCE:
                    {
                        TableItem type = node.operand1;
                        writeShort(INST_NEW_INSTANCE);
                        writeIndex(indexAcquire(type));
                        continue;
                    }
                    case NEW_ARRAY_MONO:
                    {
                        TableItem type = node.operand1;
                        writeShort(INST_NEW_ARRAY_MONO);
                        writeIndex(indexAcquire(type));
                        continue;
                    }
                    case NEW_ARRAY_MULTI:
                    {
                        TableItem type = node.operand1;
                        writeShort(INST_NEW_ARRAY_MULTI);
                        writeIndex(indexAcquire(type));
                        continue;
                    }
                    case DUP1X1:
                    {
                        Type type = (Type) node.operand1;
                        writeShort(INST_DUP1X1 | encodeType(type));
                        continue;
                    }
                    case DUP1X2:
                    {
                        Type type = (Type) node.operand1;
                        writeShort(INST_DUP1X2 | encodeType(type));
                        continue;
                    }
                    case METHOD_LEAVE:
                    {
                        writeShort(INST_METHOD_LEAVE);
                        continue;
                    }
                    case EXCEPT_ENTER:
                    {
                        writeShort(INST_EXCEPT_ENTER);
                        continue;
                    }
                    case EXCEPT_TRY:
                    {
                        Node begin = (Node) node.reference1;
                        Node end = (Node) node.reference2;
                        writeShort(INST_EXCEPT_TRY);
                        writeLabel(begin);
                        writeLabel(end);
                        continue;
                    }
                    case EXCEPT_CATCH:
                    {
                        Node block = (Node) node.reference1;
                        Object type = node.reference2;
                        writeShort(INST_EXCEPT_CATCH);
                        writeLabel(block);
                        writeIndex(indexAcquire(type));
                        continue;
                    }
                    case EXCEPT_FINALLY:
                    {
                        Node block = (Node) node.reference1;
                        writeShort(INST_EXCEPT_FINALLY);
                        writeLabel(block);
                        continue;
                    }
                    case EXCEPT_LEAVE:
                    {
                        writeShort(INST_EXCEPT_LEAVE);
                        continue;
                    }
                    default:
                    {
                        throw new UnencodableDataException(String.format(package.getResourceString("not-encodable.instruction"), new Object[] { Int.toHexString(nodeInstruction) }));
                    }
                }
                if((formInstruction & FLAG_BOOLEAN_JUMP) != 0)
                {
                    writeLabel(node.jumpIsTrue);
                    writeLabel(node.jumpIsFalse);
                }
            }
        }
        return stream.toByteArray();
    }

    protected void afterConstruction() { append(null); }

    private int indexAcquire(Object element) throws IOException {
        if(element instanceof Constant)
        {
            Constant constant = (Constant) element;
            if(constant.isReference())
            {
                element = constant.asObject();
            } else if(constant.isBoolean())
            {
                element = constant.asBoolean() ? Boolean.TRUE : Boolean.FALSE;
            } else switch(constant.type.kind)
            {
                case CHAR   : element = new Char(constant.asChar()); break;
                case REAL   : element = new Real(constant.asReal()); break;
                case DOUBLE : element = new Double(constant.asDouble()); break;
                case DOUBLE2: element = new Double2(constant.asDouble2()); break;
                case DOUBLE4: element = new Double4(constant.asDouble4()); break;
                case DOUBLE8: element = new Double8(constant.asDouble8()); break;
                case FLOAT  : element = new Float(constant.asFloat()); break;
                case FLOAT2 : element = new Float2(constant.asFloat2()); break;
                case FLOAT4 : element = new Float4(constant.asFloat4()); break;
                case FLOAT8 : element = new Float8(constant.asFloat8()); break;
                case BYTE   : element = new Byte(constant.asByte()); break;
                case BYTE2  : element = new Byte2(constant.asByte2()); break;
                case BYTE4  : element = new Byte4(constant.asByte4()); break;
                case BYTE8  : element = new Byte8(constant.asByte8()); break;
                case SHORT  : element = new Short(constant.asShort()); break;
                case SHORT2 : element = new Short2(constant.asShort2()); break;
                case SHORT4 : element = new Short4(constant.asShort4()); break;
                case SHORT8 : element = new Short8(constant.asShort8()); break;
                case INT    : element = new Int(constant.asInt()); break;
                case INT2   : element = new Int2(constant.asInt2()); break;
                case INT4   : element = new Int4(constant.asInt4()); break;
                case INT8   : element = new Int8(constant.asInt8()); break;
                case LONG   : element = new Long(constant.asLong()); break;
                case LONG2  : element = new Long2(constant.asLong2()); break;
                case LONG4  : element = new Long4(constant.asLong4()); break;
                case LONG8  : element = new Long8(constant.asLong8()); break;
            }
        }
        int result = indexOf(element);
        if(result < 0)
        {
            if(element instanceof String && ((String) element).length > 0xffff)
            {
                throw new UnencodableDataException(package.getResourceString("not-encodable.too-long-string"));
            }
            label0:
            {
                if(element instanceof RequiredReflectItem) with((TableItem) element)
                {
                    indexAcquire(recompilableName);
                    break label0;
                }
                if(element instanceof Fieldoid) with((Member) element)
                {
                    indexAcquire(parentType);
                    indexAcquire(recompilableName);
                    break label0;
                }
                if(element instanceof Callable) with((Callable) element, arguments)
                {
                    indexAcquire(parentType);
                    indexAcquire(recompilableName);
                    for(int length = length, int index = 0; index < length; index++) indexAcquire(operator [](index).type);
                }
            }
            result = append(element).length - 1;
        }
        return result;
    }
}

helper BinarySourceGeneratorCodeDataOutput: DataOutput
{
    public void writeIndex(int index) throws IOException {
        if(index <= Short.MAX_VALUE)
        {
            writeShort(index);
        } else
        {
            writeInt(Int.MIN_VALUE | index);
        }
    }

    public void writeLabel(Node target) throws IOException {
        int index;
        int encoded = AVTOORecompilable.encodeNext();
        if((index = target.debugIndex) >= 0)
        {
            encoded = AVTOORecompilable.encodeUsing(~index);
        } else if((index = target.labelIndex) >= 0)
        {
            encoded = AVTOORecompilable.encodeUsing(index);
        }
        if(AVTOORecompilable.isLongEncoded(encoded))
        {
            writeInt(encoded);
        } else
        {
            writeShort(encoded);
        }
    }
}