Package org.apache.harmony.pack200

Source Code of org.apache.harmony.pack200.ClassBands

/*
*  Licensed to the Apache Software Foundation (ASF) under one or more
*  contributor license agreements.  See the NOTICE file distributed with
*  this work for additional information regarding copyright ownership.
*  The ASF licenses this file to You under the Apache License, Version 2.0
*  (the "License"); you may not use this file except in compliance with
*  the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*/
package org.apache.harmony.pack200;

import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;

import org.apache.bcel.Constants;
import org.apache.bcel.classfile.Attribute;
import org.apache.bcel.classfile.Code;
import org.apache.bcel.classfile.CodeException;
import org.apache.bcel.classfile.Constant;
import org.apache.bcel.classfile.ConstantValue;
import org.apache.bcel.classfile.Deprecated;
import org.apache.bcel.classfile.ExceptionTable;
import org.apache.bcel.classfile.Field;
import org.apache.bcel.classfile.InnerClasses;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.classfile.LineNumberTable;
import org.apache.bcel.classfile.LocalVariableTable;
import org.apache.bcel.classfile.Method;
import org.apache.bcel.classfile.Signature;
import org.apache.bcel.classfile.SourceFile;
import org.apache.bcel.classfile.Unknown;

public class ClassBands extends BandSet {

    private SegmentHeader header;
    private final CpBands cpBands;
    private AttributeDefinitionBands attrBands;

    private final CPClass[] class_this;
    private final CPClass[] class_super;
    private final CPClass[][] class_interface;
    private final int[] class_interface_count;

    private final int[] major_versions;
    private final int[] minor_versions;

    private long[] class_flags;
    private List classSourceFile = new ArrayList();
    private List classEnclosingMethod = new ArrayList();
    private List classSignature = new ArrayList();

    private List classFileVersionMinor = new ArrayList();
    private List classFileVersionMajor = new ArrayList();


    private final int[] class_field_count;
    private final CPNameAndType[][] field_descr;
    private List fieldFlags = new ArrayList();
    private List fieldConstantValueKQ = new ArrayList();
    private List fieldSignature = new ArrayList();

    private final int[] class_method_count;
    private final CPNameAndType[][] method_descr;
    private List methodFlags = new ArrayList();
    private List methodSignature = new ArrayList();
    private List methodExceptionNumber = new ArrayList();
    private List methodExceptionClasses = new ArrayList();

    private List codeHeaders = new ArrayList();
    private List codeMaxStack = new ArrayList();
    private List codeMaxLocals = new ArrayList();
    private List codeHandlerCount = new ArrayList();
    private List codeHandlerStartP = new ArrayList();
    private List codeHandlerEndPO = new ArrayList();
    private List codeHandlerCatchPO = new ArrayList();
    private List codeHandlerClass = new ArrayList();
    private List codeFlags = new ArrayList();



    public ClassBands(SegmentHeader header, CpBands cpBands, AttributeDefinitionBands attrBands, int numClasses) {
        this.header = header;
        this.cpBands = cpBands;
        this.attrBands = attrBands;
        class_this = new CPClass[numClasses];
        class_super = new CPClass[numClasses];
        class_interface_count = new int[numClasses];
        class_interface = new CPClass[numClasses][];
        class_field_count = new int[numClasses];
        class_method_count = new int[numClasses];
        field_descr = new CPNameAndType[numClasses][];
        method_descr = new CPNameAndType[numClasses][];
        minor_versions = new int[numClasses];
        major_versions = new int[numClasses];
        class_flags = new long[numClasses];
    }

    private int index = 0;

    public void addClass(JavaClass obj) {
        class_this[index] = cpBands.getCPClass(obj.getClassName());
        class_super[index] = cpBands.getCPClass(obj.getSuperclassName());
        String[] interfaces = obj.getInterfaceNames();
        class_interface_count[index] = interfaces.length;
        for (int i = 0; i < interfaces.length; i++) {
            class_interface[index][i] = cpBands.getCPClass(interfaces[i]);
        }
        addClassAttributes(obj);

        addFields(obj.getFields());

        Method[] methods = obj.getMethods();
        addMethods(methods);
        addCode(methods);
        index++;
    }

    private void addClassAttributes(JavaClass obj) {
        int flags = obj.getAccessFlags();
        Attribute[] attributes = obj.getAttributes();
        for (int i = 0; i < attributes.length; i++) {
            if(attributes[i] instanceof SourceFile) {
                flags |= (1<<17);
                String sourceFileName = ((SourceFile)attributes[i]).getSourceFileName();
                if(isPredictableSourceFileName(obj.getClassName(), sourceFileName)) {
                    classSourceFile.add(null);
                } else {
                    classSourceFile.add(cpBands.getCPUtf8(sourceFileName));
                }
//            } else if (attributes[i] instanceof EnclosingMethod) {
//                flags |= (1<<18);
            } else if (attributes[i] instanceof Signature) {
                flags |= (1<<19);
                classSignature.add(cpBands.getCPSignature(((Signature)attributes[i]).getSignature()));
            } else if (attributes[i] instanceof Deprecated) {
                flags |= (1<<20);
//            } else if (attributes[i] instanceof RuntimeVisibleAnnotations) {
//                flags |= (1<<21);
//            } else if (attributes[i] instanceof RuntimeInvisibleAnnotations) {
//                flags |= (1<<22);
            } else if (attributes[i] instanceof InnerClasses) {
                flags |= (1<<23);
            } else if (attributes[i] instanceof Unknown) {
                Unknown attr = (Unknown)attributes[i];
                int index = attrBands.getIndex(attr);
                flags |= (1<<index);

            }
        }
        minor_versions[index] = obj.getMinor();
        major_versions[index] = obj.getMajor();
        class_flags[index] = flags;

    }

    private void addMethods(Method[] methods) {
        class_method_count[index] = methods.length;
        method_descr[index] = new CPNameAndType[methods.length];
        for (int i = 0; i < methods.length; i++) {
            method_descr[index][i] = cpBands.getCPNameAndType(methods[i]
                    .getName(), methods[i].getSignature());

            int flags = methods[i].getAccessFlags();
            Attribute[] attributes = methods[i].getAttributes();
            for (int j = 0; j < attributes.length; j++) {
                if (attributes[j] instanceof Code) {
                    flags |= (1<<17);
                } else if (attributes[j] instanceof ExceptionTable) {
                    flags |= (1<<18);
                    String[] exceptionNames = ((ExceptionTable)attributes[j]).getExceptionNames();
                    methodExceptionNumber.add(new Integer(exceptionNames.length));
                    for (int k = 0; k < exceptionNames.length; k++) {
                        methodExceptionClasses.add(cpBands.getCPClass(exceptionNames[k]));
                    }
                } else if (attributes[j] instanceof Signature) {
                    flags |= (1<<19);
                    methodSignature.add(cpBands.getCPSignature(((Signature)attributes[j]).getSignature()));
                } else if (attributes[j] instanceof Deprecated) {
                    flags |= (1<<20);
//                } else if (attributes[j] instanceof RuntimeVisibleAnnotations) {
//                    flags |= (1<<21);
//                } else if (attributes[j] instanceof RuntimeInvisibleAnnotations) {
//                    flags |= (1<<22);
//                } else if (attributes[j] instanceof RuntimeVisibleParameterAnnotations) {
//                    flags |= (1<<23);
//                } else if (attributes[j] instanceof RuntimeInvisibleParameterAnnotations) {
//                    flags |= (1<<24);
//                } else if (attributes[j] instanceof AnnotationDefault) {
//                    flags |= (1<<25);
                } else if (attributes[j] instanceof Unknown) {
                    Unknown attr = (Unknown)attributes[i];
                    int index = attrBands.getIndex(attr);
                    flags |= (1<<index);

                }
            }
            methodFlags.add(new Long(flags));
        }
    }

    private void addFields(Field[] fields) {
        class_field_count[index] = fields.length;
        field_descr[index] = new CPNameAndType[fields.length];
        for (int i = 0; i < fields.length; i++) {
            field_descr[index][i] = cpBands.getCPNameAndType(fields[i]
                    .getName(), fields[i].getSignature());
            int flags = fields[i].getAccessFlags();
            Attribute[] attributes = fields[i].getAttributes();
            for (int j = 0; j < attributes.length; j++) {
                if (attributes[j] instanceof ConstantValue) {
                    flags |= (1<<17);
                    ConstantValue constV = ((ConstantValue)attributes[j]);
                    Constant theConstant = constV.getConstantPool().getConstant(constV.getConstantValueIndex());
                    CPConstant cpConstant = cpBands.getCPConstant(theConstant, constV.getConstantPool());
                    fieldConstantValueKQ.add(cpConstant);
                } else if (attributes[j] instanceof Signature) {
                    flags |= (1<<19);
                    fieldSignature.add(cpBands.getCPSignature(((Signature)attributes[j]).getSignature()));
                } else if (attributes[j] instanceof Deprecated) {
                    flags |= (1<<20);
//                } else if (attributes[j] instanceof RuntimeVisibleAnnotations) {
//                    flags |= (1<<21);
//                } else if (attributes[j] instanceof RuntimeInvisibleAnnotations) {
//                    flags |= (1<<22);
                } else if (attributes[j] instanceof Unknown) {
                    Unknown attr = (Unknown)attributes[i];
                    int index = attrBands.getIndex(attr);
                    flags |= (1<<index);

                }
            }
            fieldFlags.add(new Long(flags));
        }

    }

    private void addCode(Method[] methods) {

        for (int i = 0; i < methods.length; i++) {
            Code code = methods[i].getCode();
            if(code != null) {
                int header = 0;
                int maxLocals = code.getMaxLocals();
                int maxStack = code.getMaxStack();
                CodeException[] exceptions = code.getExceptionTable();
                int handlers = exceptions.length;
                if(handlers <= 2) {
                    if (handlers == 0) {
                        if(maxLocals < 11 && maxStack < 11) {
                            header = 12*maxLocals + maxStack + 1;
                        }
                    } else if (handlers == 1) {
                        if(maxLocals < 7 && maxStack < 7) {
                            header = 8*maxLocals + maxStack + 145;
                        }
                    } else if (handlers == 2) {
                        if(maxLocals < 6 && maxStack < 6) {
                            header = 7*maxLocals + maxStack + 209;
                        }
                    }
                }
                codeHeaders.add(new Integer(header));
                if(header == 0) {
                    codeMaxStack.add(new Integer(maxStack));
                    codeMaxLocals.add(new Integer(maxLocals));
                    codeHandlerCount.add(new Integer(handlers));
                }
                for (int j = 0; j < exceptions.length; j++) {
                    int startPC = exceptions[j].getStartPC();
                    int endPC = exceptions[j].getEndPC();
                    int catchPC = exceptions[j].getHandlerPC();
                    int[] renumbered = renumberBCI(code.getCode());
                    int renumberedStart = renumbered[startPC];
                    int renumberedEnd = renumbered[endPC] - renumberedStart;
                    int renumberedCatch = renumbered[catchPC] - renumberedEnd;
                    codeHandlerStartP.add(new Integer(renumberedStart));
                    codeHandlerEndPO.add(new Integer(renumberedEnd));
                    codeHandlerCatchPO.add(new Integer(renumberedCatch));
                    int catchType = exceptions[j].getCatchType();
                    if(catchType == 0) {
                        codeHandlerClass.add(null);
                    } else {
                        String className = methods[i].getConstantPool().getConstantString(catchType, Constants.CONSTANT_Class);
                        codeHandlerClass.add(cpBands.getCPClass(className));
                    }
                }

                int flags = 0;
                Attribute[] attributes = methods[i].getAttributes();
                for (int j = 0; j < attributes.length; j++) {
                    if (attributes[j] instanceof LineNumberTable) {
                        flags |= (1<<1);
                    } else if (attributes[j] instanceof LocalVariableTable) {
                        flags |= (1<<2);
//                    } else if (attributes[j] instanceof LocalVariableTypeTable) {
//                        flags |= (1<<3);
                    } else if (attributes[j] instanceof Unknown) {
                        Unknown attr = (Unknown)attributes[i];
                        int index = attrBands.getIndex(attr);
                        flags |= (1<<index);

                    }
                }
                codeFlags.add(new Long(flags));
            }
        }
    }

    private int[] renumberBCI(byte[] code) {
        int[] instructionBoundaries = getInstructionBoundaries(code);
        int[] renumbered = new int[code.length];
        int precedence = 1;
        for (int i = 1; i < instructionBoundaries.length; i++) {
            renumbered[instructionBoundaries[i]] = precedence;
            precedence++;
        }
        for (int i = 1; i < renumbered.length; i++) {
            if(renumbered[i] == 0) {
                renumbered[i] = precedence;
                precedence++;
            }
        }
        return renumbered;
    }

    private int[] getInstructionBoundaries(byte[] code) {
        List boundariesList = new ArrayList();
        boolean wide = false;
        for (int i = 0; i < code.length; i++) {
            int b = code[i] & 0xFF;
            boundariesList.add(new Integer(b));
            if(b == Constants.WIDE) {
                wide = true;
            } else if (b == Constants.TABLESWITCH) {
                int padding = (i + 1) % 4 == 0 ? 0 : 4 - i + 1;
                i+= padding;
                i+= 4;
                byte b1 = code[i];
                byte b2 = code[++i];
                byte b3 = code[++i];
                byte b4 = code[++i];
                int low = (b1 << 24) | (b2 << 16) | (b3 << 8) | b4;
                b1 = code[++i];
                b2 = code[++i];
                b3 = code[++i];
                b4 = code[++i];
                int high = (b1 << 24) | (b2 << 16) | (b3 << 8) | b4;
                int jumpTableSize = 4 * (high - low + 1);
                i += jumpTableSize;
            } else if (b == Constants.LOOKUPSWITCH) {
                int padding = (i + 1) % 4 == 0 ? 0 : 4 - i + 1;
                i+= padding;
                i+= 4;
                byte b1 = code[i];
                byte b2 = code[++i];
                byte b3 = code[++i];
                byte b4 = code[++i];
                int npairs = (b1 << 24) | (b2 << 16) | (b3 << 8) | b4;
                i += 8 * npairs;
            } else {
                if(b == 16 || b == 18 || (b >= 21 && b <= 25) || (b >= 54 && b <= 58) || b == 188) {
                    i++;
                    if(wide) {
                        i++;
                        wide = false;
                    }
                } else if (b == 17 || b == 19 || b == 20 || b== 132 || (b >= 153 && b <= 168)|| (b >= 178 && b <= 184) || b == 187 || b == 188 || b == 192 || b == 193 || b == 198 || b == 199) {
                    i+=2;
//                    don't think we need this...
//                    if(wide) {
//                        i+=2;
//                        wide = false;
//                    }
                } else if (b == 185 || b == 200 || b == 201) {
                    i+=4;
                }
            }
        }
        return listToArray(boundariesList);
    }

    public void finaliseBands() {
        int defaultMinorVersion = header.getDefaultMinorVersion();
        int defaultMajorVersion = header.getDefaultMajorVersion();

        for (int i = 0; i < class_flags.length; i++) {
            int major = major_versions[i];
            int minor = minor_versions[i];
            if(major != defaultMajorVersion || minor != defaultMinorVersion) {
                class_flags[i] |= 1 << 24;
                classFileVersionMajor.add(new Integer(major));
                classFileVersionMinor.add(new Integer(minor));
            }
        }
    }

    public void pack(OutputStream out) throws IOException, Pack200Exception {
        int[] classThis = new int[class_this.length];
        for (int i = 0; i < classThis.length; i++) {
            classThis[i] = class_this[i].getIndex();
        }
        out.write(encodeBandInt(classThis, Codec.DELTA5));

        int[] classSuper = new int[class_super.length];
        for (int i = 0; i < classSuper.length; i++) {
            classSuper[i] = class_super[i].getIndex();
        }
        out.write(encodeBandInt(classSuper, Codec.DELTA5));
        out.write(encodeBandInt(class_interface_count, Codec.DELTA5));

        int totalInterfaces = sum(class_interface_count);
        int[] classInterface = new int[totalInterfaces];
        int k = 0;
        for (int i = 0; i < class_interface.length; i++) {
            if(class_interface[i] != null) {
                for (int j = 0; j < class_interface[i].length; j++) {
                    CPClass cpClass = class_interface[i][j];
                    classInterface[k] = cpClass.getIndex();
                    k++;
                }
            }
        }
        out.write(encodeBandInt(classInterface, Codec.DELTA5));
        out.write(encodeBandInt(class_field_count, Codec.DELTA5));
        out.write(encodeBandInt(class_method_count, Codec.DELTA5));

        int totalFields = sum(class_field_count);
        int[] fieldDescr = new int[totalFields];
        k = 0;
        for (int i = 0; i < field_descr.length; i++) {
            for (int j = 0; j < field_descr[i].length; j++) {
                CPNameAndType descr = field_descr[i][j];
                fieldDescr[k] = descr.getIndex();
                k++;
            }
        }
        out.write(encodeBandInt(fieldDescr, Codec.DELTA5));
        writeFieldAttributeBands(out);

        int totalMethods = sum(class_method_count);
        int[] methodDescr = new int[totalMethods];
        k = 0;
        for (int i = 0; i < method_descr.length; i++) {
            for (int j = 0; j < method_descr[i].length; j++) {
                CPNameAndType descr = method_descr[i][j];
                methodDescr[k] = descr.getIndex();
                k++;
            }
        }
        out.write(encodeBandInt(methodDescr, Codec.DELTA5));

        writeMethodAttributeBands(out);
        writeClassAttributeBands(out);
        writeCodeBands(out);
    }

    private int sum(int[] ints) {
        int sum = 0;
        for (int i = 0; i < ints.length; i++) {
            sum += ints[i];
        }
        return sum;
    }

    private void writeFieldAttributeBands(OutputStream out) throws IOException, Pack200Exception {
        out.write(encodeFlags(longListToArray(fieldFlags), Codec.UNSIGNED5, Codec.UNSIGNED5, header.have_field_flags_hi()));
        out.write(encodeBandInt(cpEntryListToArray(fieldConstantValueKQ), Codec.UNSIGNED5));
        out.write(encodeBandInt(cpEntryListToArray(fieldSignature), Codec.UNSIGNED5));
    }

    private void writeMethodAttributeBands(OutputStream out) throws IOException, Pack200Exception {
        out.write(encodeFlags(longListToArray(methodFlags), Codec.UNSIGNED5, Codec.UNSIGNED5, header.have_method_flags_hi()));
        out.write(encodeBandInt(listToArray(methodExceptionNumber), Codec.UNSIGNED5));
        out.write(encodeBandInt(cpEntryListToArray(methodExceptionClasses), Codec.UNSIGNED5));
        out.write(encodeBandInt(cpEntryListToArray(methodSignature), Codec.UNSIGNED5));

    }

    private void writeClassAttributeBands(OutputStream out) throws IOException, Pack200Exception {
        out.write(encodeFlags(class_flags, Codec.UNSIGNED5, Codec.UNSIGNED5, header.have_class_flags_hi()));
        out.write(encodeBandInt(cpEntryOrNullListToArray(classSourceFile), Codec.UNSIGNED5));
        out.write(encodeBandInt(cpEntryListToArray(classSignature), Codec.UNSIGNED5));
        out.write(encodeBandInt(listToArray(classFileVersionMinor), Codec.UNSIGNED5));
        out.write(encodeBandInt(listToArray(classFileVersionMajor), Codec.UNSIGNED5));
    }

    private void writeCodeBands(OutputStream out) throws IOException, Pack200Exception {
        out.write(encodeBandInt(listToArray(codeHeaders), Codec.BYTE1));
        out.write(encodeBandInt(listToArray(codeMaxStack), Codec.UNSIGNED5));
        out.write(encodeBandInt(listToArray(codeMaxLocals), Codec.UNSIGNED5));
        out.write(encodeBandInt(listToArray(codeHandlerCount), Codec.UNSIGNED5));
        out.write(encodeBandInt(listToArray(codeHandlerStartP), Codec.BCI5));
        out.write(encodeBandInt(listToArray(codeHandlerEndPO), Codec.BRANCH5));
        out.write(encodeBandInt(listToArray(codeHandlerCatchPO), Codec.BRANCH5));
        out.write(encodeBandInt(cpEntryOrNullListToArray(codeHandlerClass), Codec.UNSIGNED5));
        writeCodeAttributeBands(out);
    }

    private void writeCodeAttributeBands(OutputStream out) throws IOException, Pack200Exception {
        out.write(encodeFlags(longListToArray(codeFlags), Codec.UNSIGNED5, Codec.UNSIGNED5, header.have_code_flags_hi()));
    }

}
TOP

Related Classes of org.apache.harmony.pack200.ClassBands

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.