    001/*
    002 *  Licensed to the Apache Software Foundation (ASF) under one or more
    003 *  contributor license agreements.  See the NOTICE file distributed with
    004 *  this work for additional information regarding copyright ownership.
    005 *  The ASF licenses this file to You under the Apache License, Version 2.0
    006 *  (the "License"); you may not use this file except in compliance with
    007 *  the License.  You may obtain a copy of the License at
    008 *
    009 *     http://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 *  Unless required by applicable law or agreed to in writing, software
    012 *  distributed under the License is distributed on an "AS IS" BASIS,
    013 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 *  See the License for the specific language governing permissions and
    015 *  limitations under the License.
    016 */
    017package org.apache.commons.compress.harmony.pack200;
    018
    019import java.io.IOException;
    020import java.io.OutputStream;
    021import java.util.ArrayList;
    022import java.util.Arrays;
    023import java.util.Comparator;
    024import java.util.HashMap;
    025import java.util.HashSet;
    026import java.util.List;
    027import java.util.Map;
    028import java.util.Set;
    029
    030import org.apache.commons.compress.harmony.pack200.AttributeDefinitionBands.AttributeDefinition;
    031import org.apache.commons.compress.harmony.pack200.IcBands.IcTuple;
    032import org.objectweb.asm.Label;
    033import org.objectweb.asm.Opcodes;
    034
    035/**
    036 * Class bands (corresponds to the {@code class_bands} set of bands in the pack200 specification)
    037 */
    038public class ClassBands extends BandSet {
    039
    040    private static final long[] EMPTY_LONG_ARRAY = new long[0];
    041
    042    private static final class TempParamAnnotation {
    043
    044        int numParams;
    045        int[] annoN;
    046        IntList pairN = new IntList();
    047        List<String> typeRS = new ArrayList<>();
    048        List<String> nameRU = new ArrayList<>();
    049        List<String> tags = new ArrayList<>();
    050        List<Object> values = new ArrayList<>();
    051        List<Integer> caseArrayN = new ArrayList<>();
    052        List<String> nestTypeRS = new ArrayList<>();
    053        List<String> nestNameRU = new ArrayList<>();
    054        List<Integer> nestPairN = new ArrayList<>();
    055
    056        TempParamAnnotation(final int numParams) {
    057            this.numParams = numParams;
    058            annoN = new int[numParams];
    059        }
    060
    061        void addParameterAnnotation(final int parameter, final String desc, final List<String> nameRU, final List<String> tags,
    062                final List<Object> values, final List<Integer> caseArrayN, final List<String> nestTypeRS, final List<String> nestNameRU,
    063                final List<Integer> nestPairN) {
    064            annoN[parameter]++;
    065            typeRS.add(desc);
    066            pairN.add(nameRU.size());
    067            this.nameRU.addAll(nameRU);
    068            this.tags.addAll(tags);
    069            this.values.addAll(values);
    070            this.caseArrayN.addAll(caseArrayN);
    071            this.nestTypeRS.addAll(nestTypeRS);
    072            this.nestNameRU.addAll(nestNameRU);
    073            this.nestPairN.addAll(nestPairN);
    074        }
    075    }
    076
    077    protected static int countArgs(final String descriptor) {
    078        final int bra = descriptor.indexOf('(');
    079        final int ket = descriptor.indexOf(')');
    080        if (bra == -1 || ket == -1 || ket < bra) {
    081            throw new IllegalArgumentException("No arguments");
    082        }
    083
    084        boolean inType = false;
    085        boolean consumingNextType = false;
    086        int count = 0;
    087        for (int i = bra + 1; i < ket; i++) {
    088            final char charAt = descriptor.charAt(i);
    089            if (inType && charAt == ';') {
    090                inType = false;
    091                consumingNextType = false;
    092            } else if (!inType && charAt == 'L') {
    093                inType = true;
    094                count++;
    095            } else if (charAt == '[') {
    096                consumingNextType = true;
    097            } else if (inType) {
    098                // NOP
    099            } else if (consumingNextType) {
    100                count++;
    101                consumingNextType = false;
    102            } else if (charAt == 'D' || charAt == 'J') {
    103                count += 2;
    104            } else {
    105                count++;
    106            }
    107        }
    108        return count;
    109    }
    110
    111    private final CpBands cpBands;
    112    private final AttributeDefinitionBands attrBands;
    113    private final CPClass[] class_this;
    114    private final CPClass[] class_super;
    115
    116    private final CPClass[][] class_interface;
    117
    118    private final int[] class_interface_count;
    119    private final int[] major_versions;
    120    private final long[] class_flags;
    121    private int[] class_attr_calls;
    122    private final List<CPUTF8> classSourceFile = new ArrayList<>();
    123    private final List<ConstantPoolEntry> classEnclosingMethodClass = new ArrayList<>();
    124
    125    private final List<ConstantPoolEntry> classEnclosingMethodDesc = new ArrayList<>();
    126    private final List<CPSignature> classSignature = new ArrayList<>();
    127
    128    private final IntList classFileVersionMinor = new IntList();
    129    private final IntList classFileVersionMajor = new IntList();
    130    private final int[] class_field_count;
    131    private final CPNameAndType[][] field_descr;
    132    private final long[][] field_flags;
    133    private int[] field_attr_calls;
    134
    135    private final List<CPConstant<?>> fieldConstantValueKQ = new ArrayList<>();
    136    private final List<CPSignature> fieldSignature = new ArrayList<>();
    137    private final int[] class_method_count;
    138    private final CPNameAndType[][] method_descr;
    139    private final long[][] method_flags;
    140    private int[] method_attr_calls;
    141    private final List<CPSignature> methodSignature = new ArrayList<>();
    142
    143    private final IntList methodExceptionNumber = new IntList();
    144    private final List<CPClass> methodExceptionClasses = new ArrayList<>();
    145    private int[] codeHeaders;
    146    private final IntList codeMaxStack = new IntList();
    147    private final IntList codeMaxLocals = new IntList();
    148    private final IntList codeHandlerCount = new IntList();
    149    private final List codeHandlerStartP = new ArrayList();
    150    private final List codeHandlerEndPO = new ArrayList();
    151    private final List codeHandlerCatchPO = new ArrayList();
    152    private final List<CPClass> codeHandlerClass = new ArrayList<>();
    153    private final List<Long> codeFlags = new ArrayList<>();
    154    private int[] code_attr_calls;
    155    private final IntList codeLineNumberTableN = new IntList();
    156    private final List codeLineNumberTableBciP = new ArrayList();
    157    private final IntList codeLineNumberTableLine = new IntList();
    158    private final IntList codeLocalVariableTableN = new IntList();
    159    private final List codeLocalVariableTableBciP = new ArrayList();
    160    private final List codeLocalVariableTableSpanO = new ArrayList();
    161    private final List<ConstantPoolEntry> codeLocalVariableTableNameRU = new ArrayList<>();
    162    private final List<ConstantPoolEntry> codeLocalVariableTableTypeRS = new ArrayList<>();
    163    private final IntList codeLocalVariableTableSlot = new IntList();
    164    private final IntList codeLocalVariableTypeTableN = new IntList();
    165    private final List codeLocalVariableTypeTableBciP = new ArrayList();
    166    private final List codeLocalVariableTypeTableSpanO = new ArrayList();
    167    private final List<ConstantPoolEntry> codeLocalVariableTypeTableNameRU = new ArrayList<>();
    168
    169    private final List<ConstantPoolEntry> codeLocalVariableTypeTableTypeRS = new ArrayList<>();
    170    private final IntList codeLocalVariableTypeTableSlot = new IntList();
    171    private final MetadataBandGroup class_RVA_bands;
    172    private final MetadataBandGroup class_RIA_bands;
    173    private final MetadataBandGroup field_RVA_bands;
    174    private final MetadataBandGroup field_RIA_bands;
    175    private final MetadataBandGroup method_RVA_bands;
    176    private final MetadataBandGroup method_RIA_bands;
    177    private final MetadataBandGroup method_RVPA_bands;
    178
    179    private final MetadataBandGroup method_RIPA_bands;
    180    private final MetadataBandGroup method_AD_bands;
    181    private final List<NewAttributeBands> classAttributeBands = new ArrayList<>();
    182    private final List<NewAttributeBands> methodAttributeBands = new ArrayList<>();
    183
    184    private final List<NewAttributeBands> fieldAttributeBands = new ArrayList<>();
    185    private final List<NewAttributeBands> codeAttributeBands = new ArrayList<>();
    186    private final List<Long> tempFieldFlags = new ArrayList<>();
    187    private final List<CPNameAndType> tempFieldDesc = new ArrayList<>();
    188    private final List<Long> tempMethodFlags = new ArrayList<>();
    189    private final List<CPNameAndType> tempMethodDesc = new ArrayList<>();
    190
    191    private TempParamAnnotation tempMethodRVPA;
    192    private TempParamAnnotation tempMethodRIPA;
    193    private boolean anySyntheticClasses;
    194    private boolean anySyntheticFields;
    195
    196    private boolean anySyntheticMethods;
    197    private final Segment segment;
    198
    199    private final Map<CPClass, Set<CPClass>> classReferencesInnerClass = new HashMap<>();
    200
    201    private final boolean stripDebug;
    202    private int index;
    203    private int numMethodArgs;
    204    private int[] class_InnerClasses_N;
    205    private CPClass[] class_InnerClasses_RC;
    206    private int[] class_InnerClasses_F;
    207
    208    private List<CPClass> classInnerClassesOuterRCN;
    209
    210    private List<CPUTF8> classInnerClassesNameRUN;
    211
    212    public ClassBands(final Segment segment, final int numClasses, final int effort, final boolean stripDebug) throws IOException {
    213        super(effort, segment.getSegmentHeader());
    214        this.stripDebug = stripDebug;
    215        this.segment = segment;
    216        this.cpBands = segment.getCpBands();
    217        this.attrBands = segment.getAttrBands();
    218        class_this = new CPClass[numClasses];
    219        class_super = new CPClass[numClasses];
    220        class_interface_count = new int[numClasses];
    221        class_interface = new CPClass[numClasses][];
    222        class_field_count = new int[numClasses];
    223        class_method_count = new int[numClasses];
    224        field_descr = new CPNameAndType[numClasses][];
    225        field_flags = new long[numClasses][];
    226        method_descr = new CPNameAndType[numClasses][];
    227        method_flags = new long[numClasses][];
    228        for (int i = 0; i < numClasses; i++) {
    229            field_flags[i] = EMPTY_LONG_ARRAY;
    230            method_flags[i] = EMPTY_LONG_ARRAY;
    231        }
    232        // minor_versions = new int[numClasses];
    233        major_versions = new int[numClasses];
    234        class_flags = new long[numClasses];
    235
    236        class_RVA_bands = new MetadataBandGroup("RVA", MetadataBandGroup.CONTEXT_CLASS, cpBands, segmentHeader, effort);
    237        class_RIA_bands = new MetadataBandGroup("RIA", MetadataBandGroup.CONTEXT_CLASS, cpBands, segmentHeader, effort);
    238        field_RVA_bands = new MetadataBandGroup("RVA", MetadataBandGroup.CONTEXT_FIELD, cpBands, segmentHeader, effort);
    239        field_RIA_bands = new MetadataBandGroup("RIA", MetadataBandGroup.CONTEXT_FIELD, cpBands, segmentHeader, effort);
    240        method_RVA_bands = new MetadataBandGroup("RVA", MetadataBandGroup.CONTEXT_METHOD, cpBands, segmentHeader, effort);
    241        method_RIA_bands = new MetadataBandGroup("RIA", MetadataBandGroup.CONTEXT_METHOD, cpBands, segmentHeader, effort);
    242        method_RVPA_bands = new MetadataBandGroup("RVPA", MetadataBandGroup.CONTEXT_METHOD, cpBands, segmentHeader, effort);
    243        method_RIPA_bands = new MetadataBandGroup("RIPA", MetadataBandGroup.CONTEXT_METHOD, cpBands, segmentHeader, effort);
    244        method_AD_bands = new MetadataBandGroup("AD", MetadataBandGroup.CONTEXT_METHOD, cpBands, segmentHeader, effort);
    245
    246        createNewAttributeBands();
    247    }
    248
    249    public void addAnnotation(final int context, final String desc, final boolean visible, final List<String> nameRU, final List<String> tags,
    250            final List<Object> values, final List<Integer> caseArrayN, final List<String> nestTypeRS, final List<String> nestNameRU,
    251            final List<Integer> nestPairN) {
    252        switch (context) {
    253        case MetadataBandGroup.CONTEXT_CLASS:
    254            if (visible) {
    255                class_RVA_bands.addAnnotation(desc, nameRU, tags, values, caseArrayN, nestTypeRS, nestNameRU, nestPairN);
    256                if ((class_flags[index] & 1 << 21) != 0) {
    257                    class_RVA_bands.incrementAnnoN();
    258                } else {
    259                    class_RVA_bands.newEntryInAnnoN();
    260                    class_flags[index] = class_flags[index] | 1 << 21;
    261                }
    262            } else {
    263                class_RIA_bands.addAnnotation(desc, nameRU, tags, values, caseArrayN, nestTypeRS, nestNameRU, nestPairN);
    264                if ((class_flags[index] & 1 << 22) != 0) {
    265                    class_RIA_bands.incrementAnnoN();
    266                } else {
    267                    class_RIA_bands.newEntryInAnnoN();
    268                    class_flags[index] = class_flags[index] | 1 << 22;
    269                }
    270            }
    271            break;
    272        case MetadataBandGroup.CONTEXT_FIELD:
    273            if (visible) {
    274                field_RVA_bands.addAnnotation(desc, nameRU, tags, values, caseArrayN, nestTypeRS, nestNameRU, nestPairN);
    275                final Long flag = tempFieldFlags.remove(tempFieldFlags.size() - 1);
    276                if ((flag.intValue() & 1 << 21) != 0) {
    277                    field_RVA_bands.incrementAnnoN();
    278                } else {
    279                    field_RVA_bands.newEntryInAnnoN();
    280                }
    281                tempFieldFlags.add(Long.valueOf(flag.intValue() | 1 << 21));
    282            } else {
    283                field_RIA_bands.addAnnotation(desc, nameRU, tags, values, caseArrayN, nestTypeRS, nestNameRU, nestPairN);
    284                final Long flag = tempFieldFlags.remove(tempFieldFlags.size() - 1);
    285                if ((flag.intValue() & 1 << 22) != 0) {
    286                    field_RIA_bands.incrementAnnoN();
    287                } else {
    288                    field_RIA_bands.newEntryInAnnoN();
    289                }
    290                tempFieldFlags.add(Long.valueOf(flag.intValue() | 1 << 22));
    291            }
    292            break;
    293        case MetadataBandGroup.CONTEXT_METHOD:
    294            if (visible) {
    295                method_RVA_bands.addAnnotation(desc, nameRU, tags, values, caseArrayN, nestTypeRS, nestNameRU, nestPairN);
    296                final Long flag = tempMethodFlags.remove(tempMethodFlags.size() - 1);
    297                if ((flag.intValue() & 1 << 21) != 0) {
    298                    method_RVA_bands.incrementAnnoN();
    299                } else {
    300                    method_RVA_bands.newEntryInAnnoN();
    301                }
    302                tempMethodFlags.add(Long.valueOf(flag.intValue() | 1 << 21));
    303            } else {
    304                method_RIA_bands.addAnnotation(desc, nameRU, tags, values, caseArrayN, nestTypeRS, nestNameRU, nestPairN);
    305                final Long flag = tempMethodFlags.remove(tempMethodFlags.size() - 1);
    306                if ((flag.intValue() & 1 << 22) != 0) {
    307                    method_RIA_bands.incrementAnnoN();
    308                } else {
    309                    method_RIA_bands.newEntryInAnnoN();
    310                }
    311                tempMethodFlags.add(Long.valueOf(flag.intValue() | 1 << 22));
    312            }
    313            break;
    314        }
    315    }
    316
    317    public void addAnnotationDefault(final List<String> nameRU, final List<String> tags, final List<Object> values, final List<Integer> caseArrayN,
    318            final List<String> nestTypeRS, final List<String> nestNameRU, final List<Integer> nestPairN) {
    319        method_AD_bands.addAnnotation(null, nameRU, tags, values, caseArrayN, nestTypeRS, nestNameRU, nestPairN);
    320        final Long flag = tempMethodFlags.remove(tempMethodFlags.size() - 1);
    321        tempMethodFlags.add(Long.valueOf(flag.longValue() | 1 << 25));
    322    }
    323
    324    public void addClass(final int major, final int flags, final String className, final String signature, final String superName, final String[] interfaces) {
    325        class_this[index] = cpBands.getCPClass(className);
    326        class_super[index] = cpBands.getCPClass(superName);
    327        class_interface_count[index] = interfaces.length;
    328        class_interface[index] = new CPClass[interfaces.length];
    329        Arrays.setAll(class_interface[index], i -> cpBands.getCPClass(interfaces[i]));
    330        major_versions[index] = major;
    331        class_flags[index] = flags;
    332        if (!anySyntheticClasses && (flags & 1 << 12) != 0 && segment.getCurrentClassReader().hasSyntheticAttributes()) {
    333            cpBands.addCPUtf8("Synthetic");
    334            anySyntheticClasses = true;
    335        }
    336//        if ((flags & Opcodes.ACC_DEPRECATED) != 0) { // ASM uses (1<<17) flag for deprecated
    337//            flags &= ~Opcodes.ACC_DEPRECATED;
    338//            flags |= (1 << 20);
    339//        }
    340        if (signature != null) {
    341            class_flags[index] |= 1 << 19;
    342            classSignature.add(cpBands.getCPSignature(signature));
    343        }
    344    }
    345
    346    public void addClassAttribute(final NewAttribute attribute) {
    347        // TODO: backwards calls
    348        final String attributeName = attribute.type;
    349        for (final NewAttributeBands bands : classAttributeBands) {
    350            if (bands.getAttributeName().equals(attributeName)) {
    351                bands.addAttribute(attribute);
    352                final int flagIndex = bands.getFlagIndex();
    353                class_flags[index] |= 1 << flagIndex;
    354                return;
    355            }
    356        }
    357        throw new IllegalArgumentException("No suitable definition for " + attributeName);
    358    }
    359
    360    public void addCode() {
    361        codeHandlerCount.add(0);
    362        if (!stripDebug) {
    363            codeFlags.add(Long.valueOf(1 << 2));
    364            codeLocalVariableTableN.add(0);
    365        }
    366    }
    367
    368    public void addCodeAttribute(final NewAttribute attribute) {
    369        final String attributeName = attribute.type;
    370        for (final NewAttributeBands bands : codeAttributeBands) {
    371            if (bands.getAttributeName().equals(attributeName)) {
    372                bands.addAttribute(attribute);
    373                final int flagIndex = bands.getFlagIndex();
    374                final Long flags = codeFlags.remove(codeFlags.size() - 1);
    375                codeFlags.add(Long.valueOf(flags.longValue() | 1 << flagIndex));
    376                return;
    377            }
    378        }
    379        throw new IllegalArgumentException("No suitable definition for " + attributeName);
    380    }
    381
    382    public void addEnclosingMethod(final String owner, final String name, final String desc) {
    383        class_flags[index] |= 1 << 18;
    384        classEnclosingMethodClass.add(cpBands.getCPClass(owner));
    385        classEnclosingMethodDesc.add(name == null ? null : cpBands.getCPNameAndType(name, desc));
    386    }
    387
    388    public void addField(int flags, final String name, final String desc, final String signature, final Object value) {
    389        flags &= 0xFFFF;
    390        tempFieldDesc.add(cpBands.getCPNameAndType(name, desc));
    391        if (signature != null) {
    392            fieldSignature.add(cpBands.getCPSignature(signature));
    393            flags |= 1 << 19;
    394        }
    395        if ((flags & Opcodes.ACC_DEPRECATED) != 0) { // ASM uses (1<<17) flag for deprecated
    396            flags &= ~Opcodes.ACC_DEPRECATED;
    397            flags |= 1 << 20;
    398        }
    399        if (value != null) {
    400            fieldConstantValueKQ.add(cpBands.getConstant(value));
    401            flags |= 1 << 17;
    402        }
    403        if (!anySyntheticFields && (flags & 1 << 12) != 0 && segment.getCurrentClassReader().hasSyntheticAttributes()) {
    404            cpBands.addCPUtf8("Synthetic");
    405            anySyntheticFields = true;
    406        }
    407        tempFieldFlags.add(Long.valueOf(flags));
    408    }
    409
    410    public void addFieldAttribute(final NewAttribute attribute) {
    411        final String attributeName = attribute.type;
    412        for (final NewAttributeBands bands : fieldAttributeBands) {
    413            if (bands.getAttributeName().equals(attributeName)) {
    414                bands.addAttribute(attribute);
    415                final int flagIndex = bands.getFlagIndex();
    416                final Long flags = tempFieldFlags.remove(tempFieldFlags.size() - 1);
    417                tempFieldFlags.add(Long.valueOf(flags.longValue() | 1 << flagIndex));
    418                return;
    419            }
    420        }
    421        throw new IllegalArgumentException("No suitable definition for " + attributeName);
    422    }
    423
    424    public void addHandler(final Label start, final Label end, final Label handler, final String type) {
    425        final int handlers = codeHandlerCount.remove(codeHandlerCount.size() - 1);
    426        codeHandlerCount.add(handlers + 1);
    427        codeHandlerStartP.add(start);
    428        codeHandlerEndPO.add(end);
    429        codeHandlerCatchPO.add(handler);
    430        codeHandlerClass.add(type == null ? null : cpBands.getCPClass(type));
    431    }
    432
    433    public void addLineNumber(final int line, final Label start) {
    434        final Long latestCodeFlag = codeFlags.get(codeFlags.size() - 1);
    435        if ((latestCodeFlag.intValue() & 1 << 1) == 0) {
    436            codeFlags.remove(codeFlags.size() - 1);
    437            codeFlags.add(Long.valueOf(latestCodeFlag.intValue() | 1 << 1));
    438            codeLineNumberTableN.add(1);
    439        } else {
    440            codeLineNumberTableN.increment(codeLineNumberTableN.size() - 1);
    441        }
    442        codeLineNumberTableLine.add(line);
    443        codeLineNumberTableBciP.add(start);
    444    }
    445
    446    public void addLocalVariable(final String name, final String desc, final String signature, final Label start, final Label end, final int indx) {
    447        if (signature != null) { // LocalVariableTypeTable attribute
    448            final Long latestCodeFlag = codeFlags.get(codeFlags.size() - 1);
    449            if ((latestCodeFlag.intValue() & 1 << 3) == 0) {
    450                codeFlags.remove(codeFlags.size() - 1);
    451                codeFlags.add(Long.valueOf(latestCodeFlag.intValue() | 1 << 3));
    452                codeLocalVariableTypeTableN.add(1);
    453            } else {
    454                codeLocalVariableTypeTableN.increment(codeLocalVariableTypeTableN.size() - 1);
    455            }
    456            codeLocalVariableTypeTableBciP.add(start);
    457            codeLocalVariableTypeTableSpanO.add(end);
    458            codeLocalVariableTypeTableNameRU.add(cpBands.getCPUtf8(name));
    459            codeLocalVariableTypeTableTypeRS.add(cpBands.getCPSignature(signature));
    460            codeLocalVariableTypeTableSlot.add(indx);
    461        }
    462        // LocalVariableTable attribute
    463        codeLocalVariableTableN.increment(codeLocalVariableTableN.size() - 1);
    464        codeLocalVariableTableBciP.add(start);
    465        codeLocalVariableTableSpanO.add(end);
    466        codeLocalVariableTableNameRU.add(cpBands.getCPUtf8(name));
    467        codeLocalVariableTableTypeRS.add(cpBands.getCPSignature(desc));
    468        codeLocalVariableTableSlot.add(indx);
    469    }
    470
    471    public void addMaxStack(final int maxStack, int maxLocals) {
    472        final Long latestFlag = tempMethodFlags.remove(tempMethodFlags.size() - 1);
    473        final Long newFlag = Long.valueOf(latestFlag.intValue() | 1 << 17);
    474        tempMethodFlags.add(newFlag);
    475        codeMaxStack.add(maxStack);
    476        if ((newFlag.longValue() & 1 << 3) == 0) { // not static
    477            maxLocals--; // minus 'this' local
    478        }
    479        maxLocals -= numMethodArgs;
    480        codeMaxLocals.add(maxLocals);
    481    }
    482
    483    public void addMethod(int flags, final String name, final String desc, final String signature, final String[] exceptions) {
    484        final CPNameAndType nt = cpBands.getCPNameAndType(name, desc);
    485        tempMethodDesc.add(nt);
    486        if (signature != null) {
    487            methodSignature.add(cpBands.getCPSignature(signature));
    488            flags |= 1 << 19;
    489        }
    490        if (exceptions != null) {
    491            methodExceptionNumber.add(exceptions.length);
    492            for (final String exception : exceptions) {
    493                methodExceptionClasses.add(cpBands.getCPClass(exception));
    494            }
    495            flags |= 1 << 18;
    496        }
    497        if ((flags & Opcodes.ACC_DEPRECATED) != 0) { // ASM uses (1<<17) flag for deprecated
    498            flags &= ~Opcodes.ACC_DEPRECATED;
    499            flags |= 1 << 20;
    500        }
    501        tempMethodFlags.add(Long.valueOf(flags));
    502        numMethodArgs = countArgs(desc);
    503        if (!anySyntheticMethods && (flags & 1 << 12) != 0 && segment.getCurrentClassReader().hasSyntheticAttributes()) {
    504            cpBands.addCPUtf8("Synthetic");
    505            anySyntheticMethods = true;
    506        }
    507    }
    508
    509    public void addMethodAttribute(final NewAttribute attribute) {
    510        final String attributeName = attribute.type;
    511        for (final NewAttributeBands bands : methodAttributeBands) {
    512            if (bands.getAttributeName().equals(attributeName)) {
    513                bands.addAttribute(attribute);
    514                final int flagIndex = bands.getFlagIndex();
    515                final Long flags = tempMethodFlags.remove(tempMethodFlags.size() - 1);
    516                tempMethodFlags.add(Long.valueOf(flags.longValue() | 1 << flagIndex));
    517                return;
    518            }
    519        }
    520        throw new IllegalArgumentException("No suitable definition for " + attributeName);
    521    }
    522
    523    public void addParameterAnnotation(final int parameter, final String desc, final boolean visible, final List<String> nameRU, final List<String> tags,
    524            final List<Object> values, final List<Integer> caseArrayN, final List<String> nestTypeRS, final List<String> nestNameRU,
    525            final List<Integer> nestPairN) {
    526        if (visible) {
    527            if (tempMethodRVPA == null) {
    528                tempMethodRVPA = new TempParamAnnotation(numMethodArgs);
    529                tempMethodRVPA.addParameterAnnotation(parameter, desc, nameRU, tags, values, caseArrayN, nestTypeRS, nestNameRU, nestPairN);
    530            }
    531            final Long flag = tempMethodFlags.remove(tempMethodFlags.size() - 1);
    532            tempMethodFlags.add(Long.valueOf(flag.longValue() | 1 << 23));
    533        } else {
    534            if (tempMethodRIPA == null) {
    535                tempMethodRIPA = new TempParamAnnotation(numMethodArgs);
    536                tempMethodRIPA.addParameterAnnotation(parameter, desc, nameRU, tags, values, caseArrayN, nestTypeRS, nestNameRU, nestPairN);
    537            }
    538            final Long flag = tempMethodFlags.remove(tempMethodFlags.size() - 1);
    539            tempMethodFlags.add(Long.valueOf(flag.longValue() | 1 << 24));
    540        }
    541    }
    542
    543    public void addSourceFile(final String source) {
    544        String implicitSourceFileName = class_this[index].toString();
    545        if (implicitSourceFileName.indexOf('$') != -1) {
    546            implicitSourceFileName = implicitSourceFileName.substring(0, implicitSourceFileName.indexOf('$'));
    547        }
    548        implicitSourceFileName = implicitSourceFileName.substring(implicitSourceFileName.lastIndexOf('/') + 1) + ".java";
    549        if (source.equals(implicitSourceFileName)) {
    550            classSourceFile.add(null);
    551        } else {
    552            classSourceFile.add(cpBands.getCPUtf8(source));
    553        }
    554        class_flags[index] |= 1 << 17;
    555    }
    556
    557    private void createNewAttributeBands() throws IOException {
    558        for (final AttributeDefinition def : attrBands.getClassAttributeLayouts()) {
    559            classAttributeBands.add(new NewAttributeBands(effort, cpBands, segment.getSegmentHeader(), def));
    560        }
    561        for (final AttributeDefinition def : attrBands.getMethodAttributeLayouts()) {
    562            methodAttributeBands.add(new NewAttributeBands(effort, cpBands, segment.getSegmentHeader(), def));
    563        }
    564        for (final AttributeDefinition def : attrBands.getFieldAttributeLayouts()) {
    565            fieldAttributeBands.add(new NewAttributeBands(effort, cpBands, segment.getSegmentHeader(), def));
    566        }
    567        for (final AttributeDefinition def : attrBands.getCodeAttributeLayouts()) {
    568            codeAttributeBands.add(new NewAttributeBands(effort, cpBands, segment.getSegmentHeader(), def));
    569        }
    570    }
    571
    572    public void currentClassReferencesInnerClass(final CPClass inner) {
    573        if (!(index >= class_this.length)) {
    574            final CPClass currentClass = class_this[index];
    575            if (currentClass != null && !currentClass.equals(inner) && !isInnerClassOf(currentClass.toString(), inner)) {
    576                classReferencesInnerClass.computeIfAbsent(currentClass, c -> new HashSet<>()).add(inner);
    577            }
    578        }
    579    }
    580
    581    public void doBciRenumbering(final IntList bciRenumbering, final Map<Label, Integer> labelsToOffsets) {
    582        renumberBci(codeLineNumberTableBciP, bciRenumbering, labelsToOffsets);
    583        renumberBci(codeLocalVariableTableBciP, bciRenumbering, labelsToOffsets);
    584        renumberOffsetBci(codeLocalVariableTableBciP, codeLocalVariableTableSpanO, bciRenumbering, labelsToOffsets);
    585        renumberBci(codeLocalVariableTypeTableBciP, bciRenumbering, labelsToOffsets);
    586        renumberOffsetBci(codeLocalVariableTypeTableBciP, codeLocalVariableTypeTableSpanO, bciRenumbering, labelsToOffsets);
    587        renumberBci(codeHandlerStartP, bciRenumbering, labelsToOffsets);
    588        renumberOffsetBci(codeHandlerStartP, codeHandlerEndPO, bciRenumbering, labelsToOffsets);
    589        renumberDoubleOffsetBci(codeHandlerStartP, codeHandlerEndPO, codeHandlerCatchPO, bciRenumbering, labelsToOffsets);
    590
    591        for (final NewAttributeBands newAttributeBandSet : classAttributeBands) {
    592            newAttributeBandSet.renumberBci(bciRenumbering, labelsToOffsets);
    593        }
    594        for (final NewAttributeBands newAttributeBandSet : methodAttributeBands) {
    595            newAttributeBandSet.renumberBci(bciRenumbering, labelsToOffsets);
    596        }
    597        for (final NewAttributeBands newAttributeBandSet : fieldAttributeBands) {
    598            newAttributeBandSet.renumberBci(bciRenumbering, labelsToOffsets);
    599        }
    600        for (final NewAttributeBands newAttributeBandSet : codeAttributeBands) {
    601            newAttributeBandSet.renumberBci(bciRenumbering, labelsToOffsets);
    602        }
    603    }
    604
    605    public void endOfClass() { // All the data for the current class has been
    606                               // read
    607        final int numFields = tempFieldDesc.size();
    608        class_field_count[index] = numFields;
    609        field_descr[index] = new CPNameAndType[numFields];
    610        field_flags[index] = new long[numFields];
    611        for (int i = 0; i < numFields; i++) {
    612            field_descr[index][i] = tempFieldDesc.get(i);
    613            field_flags[index][i] = tempFieldFlags.get(i).longValue();
    614        }
    615        final int numMethods = tempMethodDesc.size();
    616        class_method_count[index] = numMethods;
    617        method_descr[index] = new CPNameAndType[numMethods];
    618        method_flags[index] = new long[numMethods];
    619        for (int i = 0; i < numMethods; i++) {
    620            method_descr[index][i] = tempMethodDesc.get(i);
    621            method_flags[index][i] = tempMethodFlags.get(i).longValue();
    622        }
    623        tempFieldDesc.clear();
    624        tempFieldFlags.clear();
    625        tempMethodDesc.clear();
    626        tempMethodFlags.clear();
    627        index++;
    628    }
    629
    630    public void endOfMethod() {
    631        if (tempMethodRVPA != null) {
    632            method_RVPA_bands.addParameterAnnotation(tempMethodRVPA.numParams, tempMethodRVPA.annoN, tempMethodRVPA.pairN, tempMethodRVPA.typeRS,
    633                    tempMethodRVPA.nameRU, tempMethodRVPA.tags, tempMethodRVPA.values, tempMethodRVPA.caseArrayN, tempMethodRVPA.nestTypeRS,
    634                    tempMethodRVPA.nestNameRU, tempMethodRVPA.nestPairN);
    635            tempMethodRVPA = null;
    636        }
    637        if (tempMethodRIPA != null) {
    638            method_RIPA_bands.addParameterAnnotation(tempMethodRIPA.numParams, tempMethodRIPA.annoN, tempMethodRIPA.pairN, tempMethodRIPA.typeRS,
    639                    tempMethodRIPA.nameRU, tempMethodRIPA.tags, tempMethodRIPA.values, tempMethodRIPA.caseArrayN, tempMethodRIPA.nestTypeRS,
    640                    tempMethodRIPA.nestNameRU, tempMethodRIPA.nestPairN);
    641            tempMethodRIPA = null;
    642        }
    643        if (codeFlags.size() > 0) {
    644            final long latestCodeFlag = codeFlags.get(codeFlags.size() - 1).longValue();
    645            final int latestLocalVariableTableN = codeLocalVariableTableN.get(codeLocalVariableTableN.size() - 1);
    646            if (latestCodeFlag == 1 << 2 && latestLocalVariableTableN == 0) {
    647                codeLocalVariableTableN.remove(codeLocalVariableTableN.size() - 1);
    648                codeFlags.remove(codeFlags.size() - 1);
    649                codeFlags.add(Long.valueOf(0));
    650            }
    651        }
    652    }
    653
    654    /**
    655     * All input classes for the segment have now been read in, so this method is called so that this class can calculate/complete anything it could not do
    656     * while classes were being read.
    657     */
    658    public void finaliseBands() {
    659        final int defaultMajorVersion = segmentHeader.getDefaultMajorVersion();
    660        for (int i = 0; i < class_flags.length; i++) {
    661            final int major = major_versions[i];
    662            if (major != defaultMajorVersion) {
    663                class_flags[i] |= 1 << 24;
    664                classFileVersionMajor.add(major);
    665                classFileVersionMinor.add(0);
    666            }
    667        }
    668        // Calculate code headers
    669        codeHeaders = new int[codeHandlerCount.size()];
    670        int removed = 0;
    671        for (int i = 0; i < codeHeaders.length; i++) {
    672            final int numHandlers = codeHandlerCount.get(i - removed);
    673            final int maxLocals = codeMaxLocals.get(i - removed);
    674            final int maxStack = codeMaxStack.get(i - removed);
    675            switch (numHandlers) {
    676            case 0: {
    677                final int header = maxLocals * 12 + maxStack + 1;
    678                if (header < 145 && maxStack < 12) {
    679                    codeHeaders[i] = header;
    680                }
    681                break;
    682            }
    683            case 1: {
    684                final int header = maxLocals * 8 + maxStack + 145;
    685                if (header < 209 && maxStack < 8) {
    686                    codeHeaders[i] = header;
    687                }
    688                break;
    689            }
    690            case 2: {
    691                final int header = maxLocals * 7 + maxStack + 209;
    692                if (header < 256 && maxStack < 7) {
    693                    codeHeaders[i] = header;
    694                }
    695                break;
    696            }
    697            default:
    698                break;
    699            }
    700            if (codeHeaders[i] != 0) { // Remove the redundant values from
    701                                       // codeHandlerCount, codeMaxLocals and
    702                                       // codeMaxStack
    703                codeHandlerCount.remove(i - removed);
    704                codeMaxLocals.remove(i - removed);
    705                codeMaxStack.remove(i - removed);
    706                removed++;
    707            } else if (!segment.getSegmentHeader().have_all_code_flags()) {
    708                codeFlags.add(Long.valueOf(0));
    709            }
    710        }
    711
    712        // Compute any required IcLocals
    713        final IntList innerClassesN = new IntList();
    714        final List<IcTuple> icLocal = new ArrayList<>();
    715        for (int i = 0; i < class_this.length; i++) {
    716            final CPClass cpClass = class_this[i];
    717            final Set<CPClass> referencedInnerClasses = classReferencesInnerClass.get(cpClass);
    718            if (referencedInnerClasses != null) {
    719                int innerN = 0;
    720                final List<IcTuple> innerClasses = segment.getIcBands().getInnerClassesForOuter(cpClass.toString());
    721                if (innerClasses != null) {
    722                    for (final IcTuple element : innerClasses) {
    723                        referencedInnerClasses.remove(element.C);
    724                    }
    725                }
    726                for (final CPClass inner : referencedInnerClasses) {
    727                    final IcTuple icTuple = segment.getIcBands().getIcTuple(inner);
    728                    if (icTuple != null && !icTuple.isAnonymous()) {
    729                        // should transmit an icLocal entry
    730                        icLocal.add(icTuple);
    731                        innerN++;
    732                    }
    733                }
    734                if (innerN != 0) {
    735                    innerClassesN.add(innerN);
    736                    class_flags[i] |= 1 << 23;
    737                }
    738            }
    739        }
    740        class_InnerClasses_N = innerClassesN.toArray();
    741        class_InnerClasses_RC = new CPClass[icLocal.size()];
    742        class_InnerClasses_F = new int[icLocal.size()];
    743        classInnerClassesOuterRCN = new ArrayList<>();
    744        classInnerClassesNameRUN = new ArrayList<>();
    745        for (int i = 0; i < class_InnerClasses_RC.length; i++) {
    746            final IcTuple icTuple = icLocal.get(i);
    747            class_InnerClasses_RC[i] = icTuple.C;
    748            if (icTuple.C2 == null && icTuple.N == null) {
    749                class_InnerClasses_F[i] = 0;
    750            } else {
    751                if (icTuple.F == 0) {
    752                    class_InnerClasses_F[i] = 0x00010000;
    753                } else {
    754                    class_InnerClasses_F[i] = icTuple.F;
    755                }
    756                classInnerClassesOuterRCN.add(icTuple.C2);
    757                classInnerClassesNameRUN.add(icTuple.N);
    758            }
    759        }
    760        // Calculate any backwards calls from metadata bands
    761        final IntList classAttrCalls = new IntList();
    762        final IntList fieldAttrCalls = new IntList();
    763        final IntList methodAttrCalls = new IntList();
    764        final IntList codeAttrCalls = new IntList();
    765
    766        if (class_RVA_bands.hasContent()) {
    767            classAttrCalls.add(class_RVA_bands.numBackwardsCalls());
    768        }
    769        if (class_RIA_bands.hasContent()) {
    770            classAttrCalls.add(class_RIA_bands.numBackwardsCalls());
    771        }
    772        if (field_RVA_bands.hasContent()) {
    773            fieldAttrCalls.add(field_RVA_bands.numBackwardsCalls());
    774        }
    775        if (field_RIA_bands.hasContent()) {
    776            fieldAttrCalls.add(field_RIA_bands.numBackwardsCalls());
    777        }
    778        if (method_RVA_bands.hasContent()) {
    779            methodAttrCalls.add(method_RVA_bands.numBackwardsCalls());
    780        }
    781        if (method_RIA_bands.hasContent()) {
    782            methodAttrCalls.add(method_RIA_bands.numBackwardsCalls());
    783        }
    784        if (method_RVPA_bands.hasContent()) {
    785            methodAttrCalls.add(method_RVPA_bands.numBackwardsCalls());
    786        }
    787        if (method_RIPA_bands.hasContent()) {
    788            methodAttrCalls.add(method_RIPA_bands.numBackwardsCalls());
    789        }
    790        if (method_AD_bands.hasContent()) {
    791            methodAttrCalls.add(method_AD_bands.numBackwardsCalls());
    792        }
    793
    794        // Sort non-predefined attribute bands
    795        final Comparator<NewAttributeBands> comparator = (arg0, arg1) -> arg0.getFlagIndex() - arg1.getFlagIndex();
    796        classAttributeBands.sort(comparator);
    797        methodAttributeBands.sort(comparator);
    798        fieldAttributeBands.sort(comparator);
    799        codeAttributeBands.sort(comparator);
    800
    801        for (final NewAttributeBands bands : classAttributeBands) {
    802            if (bands.isUsedAtLeastOnce()) {
    803                for (final int backwardsCallCount : bands.numBackwardsCalls()) {
    804                    classAttrCalls.add(backwardsCallCount);
    805                }
    806            }
    807        }
    808        for (final NewAttributeBands bands : methodAttributeBands) {
    809            if (bands.isUsedAtLeastOnce()) {
    810                for (final int backwardsCallCount : bands.numBackwardsCalls()) {
    811                    methodAttrCalls.add(backwardsCallCount);
    812                }
    813            }
    814        }
    815        for (final NewAttributeBands bands : fieldAttributeBands) {
    816            if (bands.isUsedAtLeastOnce()) {
    817                for (final int backwardsCallCount : bands.numBackwardsCalls()) {
    818                    fieldAttrCalls.add(backwardsCallCount);
    819                }
    820            }
    821        }
    822        for (final NewAttributeBands bands : codeAttributeBands) {
    823            if (bands.isUsedAtLeastOnce()) {
    824                for (final int backwardsCallCount : bands.numBackwardsCalls()) {
    825                    codeAttrCalls.add(backwardsCallCount);
    826                }
    827            }
    828        }
    829
    830        class_attr_calls = classAttrCalls.toArray();
    831        field_attr_calls = fieldAttrCalls.toArray();
    832        method_attr_calls = methodAttrCalls.toArray();
    833        code_attr_calls = codeAttrCalls.toArray();
    834    }
    835
    836    private int[] getInts(final CPClass[] cpClasses) {
    837        final int[] ints = new int[cpClasses.length];
    838        for (int i = 0; i < ints.length; i++) {
    839            if (cpClasses[i] != null) {
    840                ints[i] = cpClasses[i].getIndex();
    841            }
    842        }
    843        return ints;
    844    }
    845
    846    public boolean isAnySyntheticClasses() {
    847        return anySyntheticClasses;
    848    }
    849
    850    public boolean isAnySyntheticFields() {
    851        return anySyntheticFields;
    852    }
    853
    854    public boolean isAnySyntheticMethods() {
    855        return anySyntheticMethods;
    856    }
    857
    858    private boolean isInnerClass(final String possibleInner) {
    859        return possibleInner.indexOf('$') != -1;
    860    }
    861
    862    private boolean isInnerClassOf(final String possibleInner, final CPClass possibleOuter) {
    863        if (isInnerClass(possibleInner)) {
    864            final String superClassName = possibleInner.substring(0, possibleInner.lastIndexOf('$'));
    865            if (superClassName.equals(possibleOuter.toString())) {
    866                return true;
    867            }
    868            return isInnerClassOf(superClassName, possibleOuter);
    869        }
    870        return false;
    871    }
    872
    873    public int numClassesProcessed() {
    874        return index;
    875    }
    876
    877    @Override
    878    public void pack(final OutputStream out) throws IOException, Pack200Exception {
    879        PackingUtils.log("Writing class bands...");
    880
    881        byte[] encodedBand = encodeBandInt("class_this", getInts(class_this), Codec.DELTA5);
    882        out.write(encodedBand);
    883        PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_this[" + class_this.length + "]");
    884
    885        encodedBand = encodeBandInt("class_super", getInts(class_super), Codec.DELTA5);
    886        out.write(encodedBand);
    887        PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_super[" + class_super.length + "]");
    888
    889        encodedBand = encodeBandInt("class_interface_count", class_interface_count, Codec.DELTA5);
    890        out.write(encodedBand);
    891        PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_interface_count[" + class_interface_count.length + "]");
    892
    893        final int totalInterfaces = sum(class_interface_count);
    894        final int[] classInterface = new int[totalInterfaces];
    895        int k = 0;
    896        for (final CPClass[] element : class_interface) {
    897            if (element != null) {
    898                for (final CPClass cpClass : element) {
    899                    classInterface[k] = cpClass.getIndex();
    900                    k++;
    901                }
    902            }
    903        }
    904
    905        encodedBand = encodeBandInt("class_interface", classInterface, Codec.DELTA5);
    906        out.write(encodedBand);
    907        PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_interface[" + classInterface.length + "]");
    908
    909        encodedBand = encodeBandInt("class_field_count", class_field_count, Codec.DELTA5);
    910        out.write(encodedBand);
    911        PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_field_count[" + class_field_count.length + "]");
    912
    913        encodedBand = encodeBandInt("class_method_count", class_method_count, Codec.DELTA5);
    914        out.write(encodedBand);
    915        PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_method_count[" + class_method_count.length + "]");
    916
    917        final int totalFields = sum(class_field_count);
    918        final int[] fieldDescr = new int[totalFields];
    919        k = 0;
    920        for (int i = 0; i < index; i++) {
    921            for (int j = 0; j < field_descr[i].length; j++) {
    922                final CPNameAndType descr = field_descr[i][j];
    923                fieldDescr[k] = descr.getIndex();
    924                k++;
    925            }
    926        }
    927
    928        encodedBand = encodeBandInt("field_descr", fieldDescr, Codec.DELTA5);
    929        out.write(encodedBand);
    930        PackingUtils.log("Wrote " + encodedBand.length + " bytes from field_descr[" + fieldDescr.length + "]");
    931
    932        writeFieldAttributeBands(out);
    933
    934        final int totalMethods = sum(class_method_count);
    935        final int[] methodDescr = new int[totalMethods];
    936        k = 0;
    937        for (int i = 0; i < index; i++) {
    938            for (int j = 0; j < method_descr[i].length; j++) {
    939                final CPNameAndType descr = method_descr[i][j];
    940                methodDescr[k] = descr.getIndex();
    941                k++;
    942            }
    943        }
    944
    945        encodedBand = encodeBandInt("method_descr", methodDescr, Codec.MDELTA5);
    946        out.write(encodedBand);
    947        PackingUtils.log("Wrote " + encodedBand.length + " bytes from method_descr[" + methodDescr.length + "]");
    948
    949        writeMethodAttributeBands(out);
    950        writeClassAttributeBands(out);
    951        writeCodeBands(out);
    952    }
    953
    954    /**
    955     * Remove all entries for the current class
    956     */
    957    public void removeCurrentClass() {
    958        // Note - this doesn't remove any entries added to the constant pool but
    959        // that shouldn't be a problem
    960        if ((class_flags[index] & 1 << 17) != 0) {
    961            classSourceFile.remove(classSourceFile.size() - 1);
    962        }
    963        if ((class_flags[index] & 1 << 18) != 0) {
    964            classEnclosingMethodClass.remove(classEnclosingMethodClass.size() - 1);
    965            classEnclosingMethodDesc.remove(classEnclosingMethodDesc.size() - 1);
    966        }
    967        if ((class_flags[index] & 1 << 19) != 0) {
    968            classSignature.remove(classSignature.size() - 1);
    969        }
    970        if ((class_flags[index] & 1 << 21) != 0) {
    971            class_RVA_bands.removeLatest();
    972        }
    973        if ((class_flags[index] & 1 << 22) != 0) {
    974            class_RIA_bands.removeLatest();
    975        }
    976        for (final Long flagsL : tempFieldFlags) {
    977            final long flags = flagsL.longValue();
    978            if ((flags & 1 << 19) != 0) {
    979                fieldSignature.remove(fieldSignature.size() - 1);
    980            }
    981            if ((flags & 1 << 17) != 0) {
    982                fieldConstantValueKQ.remove(fieldConstantValueKQ.size() - 1);
    983            }
    984            if ((flags & 1 << 21) != 0) {
    985                field_RVA_bands.removeLatest();
    986            }
    987            if ((flags & 1 << 22) != 0) {
    988                field_RIA_bands.removeLatest();
    989            }
    990        }
    991        for (final Long flagsL : tempMethodFlags) {
    992            final long flags = flagsL.longValue();
    993            if ((flags & 1 << 19) != 0) {
    994                methodSignature.remove(methodSignature.size() - 1);
    995            }
    996            if ((flags & 1 << 18) != 0) {
    997                final int exceptions = methodExceptionNumber.remove(methodExceptionNumber.size() - 1);
    998                for (int i = 0; i < exceptions; i++) {
    999                    methodExceptionClasses.remove(methodExceptionClasses.size() - 1);
    1000                }
    1001            }
    1002            if ((flags & 1 << 17) != 0) { // has code attribute
    1003                codeMaxLocals.remove(codeMaxLocals.size() - 1);
    1004                codeMaxStack.remove(codeMaxStack.size() - 1);
    1005                final int handlers = codeHandlerCount.remove(codeHandlerCount.size() - 1);
    1006                for (int i = 0; i < handlers; i++) {
    1007                    final int index = codeHandlerStartP.size() - 1;
    1008                    codeHandlerStartP.remove(index);
    1009                    codeHandlerEndPO.remove(index);
    1010                    codeHandlerCatchPO.remove(index);
    1011                    codeHandlerClass.remove(index);
    1012                }
    1013                if (!stripDebug) {
    1014                    final long cdeFlags = codeFlags.remove(codeFlags.size() - 1).longValue();
    1015                    final int numLocalVariables = codeLocalVariableTableN.remove(codeLocalVariableTableN.size() - 1);
    1016                    for (int i = 0; i < numLocalVariables; i++) {
    1017                        final int location = codeLocalVariableTableBciP.size() - 1;
    1018                        codeLocalVariableTableBciP.remove(location);
    1019                        codeLocalVariableTableSpanO.remove(location);
    1020                        codeLocalVariableTableNameRU.remove(location);
    1021                        codeLocalVariableTableTypeRS.remove(location);
    1022                        codeLocalVariableTableSlot.remove(location);
    1023                    }
    1024                    if ((cdeFlags & 1 << 3) != 0) {
    1025                        final int numLocalVariablesInTypeTable = codeLocalVariableTypeTableN.remove(codeLocalVariableTypeTableN.size() - 1);
    1026                        for (int i = 0; i < numLocalVariablesInTypeTable; i++) {
    1027                            final int location = codeLocalVariableTypeTableBciP.size() - 1;
    1028                            codeLocalVariableTypeTableBciP.remove(location);
    1029                            codeLocalVariableTypeTableSpanO.remove(location);
    1030                            codeLocalVariableTypeTableNameRU.remove(location);
    1031                            codeLocalVariableTypeTableTypeRS.remove(location);
    1032                            codeLocalVariableTypeTableSlot.remove(location);
    1033                        }
    1034                    }
    1035                    if ((cdeFlags & 1 << 1) != 0) {
    1036                        final int numLineNumbers = codeLineNumberTableN.remove(codeLineNumberTableN.size() - 1);
    1037                        for (int i = 0; i < numLineNumbers; i++) {
    1038                            final int location = codeLineNumberTableBciP.size() - 1;
    1039                            codeLineNumberTableBciP.remove(location);
    1040                            codeLineNumberTableLine.remove(location);
    1041                        }
    1042                    }
    1043                }
    1044            }
    1045            if ((flags & 1 << 21) != 0) {
    1046                method_RVA_bands.removeLatest();
    1047            }
    1048            if ((flags & 1 << 22) != 0) {
    1049                method_RIA_bands.removeLatest();
    1050            }
    1051            if ((flags & 1 << 23) != 0) {
    1052                method_RVPA_bands.removeLatest();
    1053            }
    1054            if ((flags & 1 << 24) != 0) {
    1055                method_RIPA_bands.removeLatest();
    1056            }
    1057            if ((flags & 1 << 25) != 0) {
    1058                method_AD_bands.removeLatest();
    1059            }
    1060        }
    1061        class_this[index] = null;
    1062        class_super[index] = null;
    1063        class_interface_count[index] = 0;
    1064        class_interface[index] = null;
    1065        major_versions[index] = 0;
    1066        class_flags[index] = 0;
    1067        tempFieldDesc.clear();
    1068        tempFieldFlags.clear();
    1069        tempMethodDesc.clear();
    1070        tempMethodFlags.clear();
    1071        if (index > 0) {
    1072            index--;
    1073        }
    1074    }
    1075
    1076    private void renumberBci(final List<Integer> list, final IntList bciRenumbering, final Map<Label, Integer> labelsToOffsets) {
    1077        for (int i = list.size() - 1; i >= 0; i--) {
    1078            final Object label = list.get(i);
    1079            if (label instanceof Integer) {
    1080                break;
    1081            }
    1082            if (label instanceof Label) {
    1083                list.remove(i);
    1084                final Integer bytecodeIndex = labelsToOffsets.get(label);
    1085                list.add(i, Integer.valueOf(bciRenumbering.get(bytecodeIndex.intValue())));
    1086            }
    1087        }
    1088    }
    1089
    1090    private void renumberDoubleOffsetBci(final List<Integer> relative, final List<Integer> firstOffset, final List<Object> list, final IntList bciRenumbering,
    1091            final Map<Label, Integer> labelsToOffsets) {
    1092        // TODO: There's probably a nicer way of doing this...
    1093        for (int i = list.size() - 1; i >= 0; i--) {
    1094            final Object label = list.get(i);
    1095            if (label instanceof Integer) {
    1096                break;
    1097            }
    1098            if (label instanceof Label) {
    1099                list.remove(i);
    1100                final Integer bytecodeIndex = labelsToOffsets.get(label);
    1101                final Integer renumberedOffset = Integer
    1102                        .valueOf(bciRenumbering.get(bytecodeIndex.intValue()) - relative.get(i).intValue() - firstOffset.get(i).intValue());
    1103                list.add(i, renumberedOffset);
    1104            }
    1105        }
    1106    }
    1107
    1108    private void renumberOffsetBci(final List<Integer> relative, final List<Integer> list, final IntList bciRenumbering,
    1109            final Map<Label, Integer> labelsToOffsets) {
    1110        for (int i = list.size() - 1; i >= 0; i--) {
    1111            final Object label = list.get(i);
    1112            if (label instanceof Integer) {
    1113                break;
    1114            }
    1115            if (label instanceof Label) {
    1116                list.remove(i);
    1117                final Integer bytecodeIndex = labelsToOffsets.get(label);
    1118                final Integer renumberedOffset = Integer.valueOf(bciRenumbering.get(bytecodeIndex.intValue()) - relative.get(i).intValue());
    1119                list.add(i, renumberedOffset);
    1120            }
    1121        }
    1122    }
    1123
    1124    private int sum(final int[] ints) {
    1125        int sum = 0;
    1126        for (final int j : ints) {
    1127            sum += j;
    1128        }
    1129        return sum;
    1130    }
    1131
    1132    private void writeClassAttributeBands(final OutputStream out) throws IOException, Pack200Exception {
    1133        byte[] encodedBand = encodeFlags("class_flags", class_flags, Codec.UNSIGNED5, Codec.UNSIGNED5, segmentHeader.have_class_flags_hi());
    1134        out.write(encodedBand);
    1135        PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_flags[" + class_flags.length + "]");
    1136
    1137        // These bands are not needed, but could be used to reduce the size of
    1138        // the archive if there are enough different non-standard attributes
    1139        // defined that segmentHeader.have_class_flags_hi() is true. The same
    1140        // applies to method_attr_count, field_attr_count, code_attr_count etc.
    1141
    1142        // *class_attr_count :UNSIGNED5 [COUNT(1<<16,...)]
    1143        // *class_attr_indexes :UNSIGNED5 [SUM(*class_attr_count)]
    1144
    1145        encodedBand = encodeBandInt("class_attr_calls", class_attr_calls, Codec.UNSIGNED5);
    1146        out.write(encodedBand);
    1147        PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_attr_calls[" + class_attr_calls.length + "]");
    1148
    1149        encodedBand = encodeBandInt("classSourceFile", cpEntryOrNullListToArray(classSourceFile), Codec.UNSIGNED5);
    1150        out.write(encodedBand);
    1151        PackingUtils.log("Wrote " + encodedBand.length + " bytes from classSourceFile[" + classSourceFile.size() + "]");
    1152
    1153        encodedBand = encodeBandInt("class_enclosing_method_RC", cpEntryListToArray(classEnclosingMethodClass), Codec.UNSIGNED5);
    1154        out.write(encodedBand);
    1155        PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_enclosing_method_RC[" + classEnclosingMethodClass.size() + "]");
    1156
    1157        encodedBand = encodeBandInt("class_EnclosingMethod_RDN", cpEntryOrNullListToArray(classEnclosingMethodDesc), Codec.UNSIGNED5);
    1158        out.write(encodedBand);
    1159        PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_EnclosingMethod_RDN[" + classEnclosingMethodDesc.size() + "]");
    1160
    1161        encodedBand = encodeBandInt("class_Signature_RS", cpEntryListToArray(classSignature), Codec.UNSIGNED5);
    1162        out.write(encodedBand);
    1163        PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_Signature_RS[" + classSignature.size() + "]");
    1164
    1165        class_RVA_bands.pack(out);
    1166        class_RIA_bands.pack(out);
    1167
    1168        encodedBand = encodeBandInt("class_InnerClasses_N", class_InnerClasses_N, Codec.UNSIGNED5);
    1169        out.write(encodedBand);
    1170        PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_InnerClasses_N[" + class_InnerClasses_N.length + "]");
    1171
    1172        encodedBand = encodeBandInt("class_InnerClasses_RC", getInts(class_InnerClasses_RC), Codec.UNSIGNED5);
    1173        out.write(encodedBand);
    1174        PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_InnerClasses_RC[" + class_InnerClasses_RC.length + "]");
    1175
    1176        encodedBand = encodeBandInt("class_InnerClasses_F", class_InnerClasses_F, Codec.UNSIGNED5);
    1177        out.write(encodedBand);
    1178        PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_InnerClasses_F[" + class_InnerClasses_F.length + "]");
    1179
    1180        encodedBand = encodeBandInt("class_InnerClasses_outer_RCN", cpEntryOrNullListToArray(classInnerClassesOuterRCN), Codec.UNSIGNED5);
    1181        out.write(encodedBand);
    1182        PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_InnerClasses_outer_RCN[" + classInnerClassesOuterRCN.size() + "]");
    1183
    1184        encodedBand = encodeBandInt("class_InnerClasses_name_RUN", cpEntryOrNullListToArray(classInnerClassesNameRUN), Codec.UNSIGNED5);
    1185        out.write(encodedBand);
    1186        PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_InnerClasses_name_RUN[" + classInnerClassesNameRUN.size() + "]");
    1187
    1188        encodedBand = encodeBandInt("classFileVersionMinor", classFileVersionMinor.toArray(), Codec.UNSIGNED5);
    1189        out.write(encodedBand);
    1190        PackingUtils.log("Wrote " + encodedBand.length + " bytes from classFileVersionMinor[" + classFileVersionMinor.size() + "]");
    1191
    1192        encodedBand = encodeBandInt("classFileVersionMajor", classFileVersionMajor.toArray(), Codec.UNSIGNED5);
    1193        out.write(encodedBand);
    1194        PackingUtils.log("Wrote " + encodedBand.length + " bytes from classFileVersionMajor[" + classFileVersionMajor.size() + "]");
    1195
    1196        for (final NewAttributeBands classAttributeBand : classAttributeBands) {
    1197            classAttributeBand.pack(out);
    1198        }
    1199    }
    1200
    1201    private void writeCodeAttributeBands(final OutputStream out) throws IOException, Pack200Exception {
    1202        byte[] encodedBand = encodeFlags("codeFlags", longListToArray(codeFlags), Codec.UNSIGNED5, Codec.UNSIGNED5, segmentHeader.have_code_flags_hi());
    1203        out.write(encodedBand);
    1204        PackingUtils.log("Wrote " + encodedBand.length + " bytes from codeFlags[" + codeFlags.size() + "]");
    1205
    1206        // *code_attr_count :UNSIGNED5 [COUNT(1<<16,...)]
    1207        // *code_attr_indexes :UNSIGNED5 [SUM(*code_attr_count)]
    1208        encodedBand = encodeBandInt("code_attr_calls", code_attr_calls, Codec.UNSIGNED5);
    1209        out.write(encodedBand);
    1210        PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_attr_calls[" + code_attr_calls.length + "]");
    1211
    1212        encodedBand = encodeBandInt("code_LineNumberTable_N", codeLineNumberTableN.toArray(), Codec.UNSIGNED5);
    1213        out.write(encodedBand);
    1214        PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LineNumberTable_N[" + codeLineNumberTableN.size() + "]");
    1215
    1216        encodedBand = encodeBandInt("code_LineNumberTable_bci_P", integerListToArray(codeLineNumberTableBciP), Codec.BCI5);
    1217        out.write(encodedBand);
    1218        PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LineNumberTable_bci_P[" + codeLineNumberTableBciP.size() + "]");
    1219
    1220        encodedBand = encodeBandInt("code_LineNumberTable_line", codeLineNumberTableLine.toArray(), Codec.UNSIGNED5);
    1221        out.write(encodedBand);
    1222        PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LineNumberTable_line[" + codeLineNumberTableLine.size() + "]");
    1223
    1224        encodedBand = encodeBandInt("code_LocalVariableTable_N", codeLocalVariableTableN.toArray(), Codec.UNSIGNED5);
    1225        out.write(encodedBand);
    1226        PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTable_N[" + codeLocalVariableTableN.size() + "]");
    1227
    1228        encodedBand = encodeBandInt("code_LocalVariableTable_bci_P", integerListToArray(codeLocalVariableTableBciP), Codec.BCI5);
    1229        out.write(encodedBand);
    1230        PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTable_bci_P[" + codeLocalVariableTableBciP.size() + "]");
    1231
    1232        encodedBand = encodeBandInt("code_LocalVariableTable_span_O", integerListToArray(codeLocalVariableTableSpanO), Codec.BRANCH5);
    1233        out.write(encodedBand);
    1234        PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTable_span_O[" + codeLocalVariableTableSpanO.size() + "]");
    1235
    1236        encodedBand = encodeBandInt("code_LocalVariableTable_name_RU", cpEntryListToArray(codeLocalVariableTableNameRU), Codec.UNSIGNED5);
    1237        out.write(encodedBand);
    1238        PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTable_name_RU[" + codeLocalVariableTableNameRU.size() + "]");
    1239
    1240        encodedBand = encodeBandInt("code_LocalVariableTable_type_RS", cpEntryListToArray(codeLocalVariableTableTypeRS), Codec.UNSIGNED5);
    1241        out.write(encodedBand);
    1242        PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTable_type_RS[" + codeLocalVariableTableTypeRS.size() + "]");
    1243
    1244        encodedBand = encodeBandInt("code_LocalVariableTable_slot", codeLocalVariableTableSlot.toArray(), Codec.UNSIGNED5);
    1245        out.write(encodedBand);
    1246        PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTable_slot[" + codeLocalVariableTableSlot.size() + "]");
    1247
    1248        encodedBand = encodeBandInt("code_LocalVariableTypeTable_N", codeLocalVariableTypeTableN.toArray(), Codec.UNSIGNED5);
    1249        out.write(encodedBand);
    1250        PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTypeTable_N[" + codeLocalVariableTypeTableN.size() + "]");
    1251
    1252        encodedBand = encodeBandInt("code_LocalVariableTypeTable_bci_P", integerListToArray(codeLocalVariableTypeTableBciP), Codec.BCI5);
    1253        out.write(encodedBand);
    1254        PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTypeTable_bci_P[" + codeLocalVariableTypeTableBciP.size() + "]");
    1255
    1256        encodedBand = encodeBandInt("code_LocalVariableTypeTable_span_O", integerListToArray(codeLocalVariableTypeTableSpanO), Codec.BRANCH5);
    1257        out.write(encodedBand);
    1258        PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTypeTable_span_O[" + codeLocalVariableTypeTableSpanO.size() + "]");
    1259
    1260        encodedBand = encodeBandInt("code_LocalVariableTypeTable_name_RU", cpEntryListToArray(codeLocalVariableTypeTableNameRU), Codec.UNSIGNED5);
    1261        out.write(encodedBand);
    1262        PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTypeTable_name_RU[" + codeLocalVariableTypeTableNameRU.size() + "]");
    1263
    1264        encodedBand = encodeBandInt("code_LocalVariableTypeTable_type_RS", cpEntryListToArray(codeLocalVariableTypeTableTypeRS), Codec.UNSIGNED5);
    1265        out.write(encodedBand);
    1266        PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTypeTable_type_RS[" + codeLocalVariableTypeTableTypeRS.size() + "]");
    1267
    1268        encodedBand = encodeBandInt("code_LocalVariableTypeTable_slot", codeLocalVariableTypeTableSlot.toArray(), Codec.UNSIGNED5);
    1269        out.write(encodedBand);
    1270        PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTypeTable_slot[" + codeLocalVariableTypeTableSlot.size() + "]");
    1271
    1272        for (final NewAttributeBands bands : codeAttributeBands) {
    1273            bands.pack(out);
    1274        }
    1275    }
    1276
    1277    private void writeCodeBands(final OutputStream out) throws IOException, Pack200Exception {
    1278        byte[] encodedBand = encodeBandInt("codeHeaders", codeHeaders, Codec.BYTE1);
    1279        out.write(encodedBand);
    1280        PackingUtils.log("Wrote " + encodedBand.length + " bytes from codeHeaders[" + codeHeaders.length + "]");
    1281
    1282        encodedBand = encodeBandInt("codeMaxStack", codeMaxStack.toArray(), Codec.UNSIGNED5);
    1283        out.write(encodedBand);
    1284        PackingUtils.log("Wrote " + encodedBand.length + " bytes from codeMaxStack[" + codeMaxStack.size() + "]");
    1285
    1286        encodedBand = encodeBandInt("codeMaxLocals", codeMaxLocals.toArray(), Codec.UNSIGNED5);
    1287        out.write(encodedBand);
    1288        PackingUtils.log("Wrote " + encodedBand.length + " bytes from codeMaxLocals[" + codeMaxLocals.size() + "]");
    1289
    1290        encodedBand = encodeBandInt("codeHandlerCount", codeHandlerCount.toArray(), Codec.UNSIGNED5);
    1291        out.write(encodedBand);
    1292        PackingUtils.log("Wrote " + encodedBand.length + " bytes from codeHandlerCount[" + codeHandlerCount.size() + "]");
    1293
    1294        encodedBand = encodeBandInt("codeHandlerStartP", integerListToArray(codeHandlerStartP), Codec.BCI5);
    1295        out.write(encodedBand);
    1296        PackingUtils.log("Wrote " + encodedBand.length + " bytes from codeHandlerStartP[" + codeHandlerStartP.size() + "]");
    1297
    1298        encodedBand = encodeBandInt("codeHandlerEndPO", integerListToArray(codeHandlerEndPO), Codec.BRANCH5);
    1299        out.write(encodedBand);
    1300        PackingUtils.log("Wrote " + encodedBand.length + " bytes from codeHandlerEndPO[" + codeHandlerEndPO.size() + "]");
    1301
    1302        encodedBand = encodeBandInt("codeHandlerCatchPO", integerListToArray(codeHandlerCatchPO), Codec.BRANCH5);
    1303        out.write(encodedBand);
    1304        PackingUtils.log("Wrote " + encodedBand.length + " bytes from codeHandlerCatchPO[" + codeHandlerCatchPO.size() + "]");
    1305
    1306        encodedBand = encodeBandInt("codeHandlerClass", cpEntryOrNullListToArray(codeHandlerClass), Codec.UNSIGNED5);
    1307        out.write(encodedBand);
    1308        PackingUtils.log("Wrote " + encodedBand.length + " bytes from codeHandlerClass[" + codeHandlerClass.size() + "]");
    1309
    1310        writeCodeAttributeBands(out);
    1311    }
    1312
    1313    private void writeFieldAttributeBands(final OutputStream out) throws IOException, Pack200Exception {
    1314        byte[] encodedBand = encodeFlags("field_flags", field_flags, Codec.UNSIGNED5, Codec.UNSIGNED5, segmentHeader.have_field_flags_hi());
    1315        out.write(encodedBand);
    1316        PackingUtils.log("Wrote " + encodedBand.length + " bytes from field_flags[" + field_flags.length + "]");
    1317
    1318        // *field_attr_count :UNSIGNED5 [COUNT(1<<16,...)]
    1319        // *field_attr_indexes :UNSIGNED5 [SUM(*field_attr_count)]
    1320        encodedBand = encodeBandInt("field_attr_calls", field_attr_calls, Codec.UNSIGNED5);
    1321        out.write(encodedBand);
    1322        PackingUtils.log("Wrote " + encodedBand.length + " bytes from field_attr_calls[" + field_attr_calls.length + "]");
    1323
    1324        encodedBand = encodeBandInt("fieldConstantValueKQ", cpEntryListToArray(fieldConstantValueKQ), Codec.UNSIGNED5);
    1325        out.write(encodedBand);
    1326        PackingUtils.log("Wrote " + encodedBand.length + " bytes from fieldConstantValueKQ[" + fieldConstantValueKQ.size() + "]");
    1327
    1328        encodedBand = encodeBandInt("fieldSignature", cpEntryListToArray(fieldSignature), Codec.UNSIGNED5);
    1329        out.write(encodedBand);
    1330        PackingUtils.log("Wrote " + encodedBand.length + " bytes from fieldSignature[" + fieldSignature.size() + "]");
    1331
    1332        field_RVA_bands.pack(out);
    1333        field_RIA_bands.pack(out);
    1334        for (final NewAttributeBands bands : fieldAttributeBands) {
    1335            bands.pack(out);
    1336        }
    1337    }
    1338
    1339    private void writeMethodAttributeBands(final OutputStream out) throws IOException, Pack200Exception {
    1340        byte[] encodedBand = encodeFlags("method_flags", method_flags, Codec.UNSIGNED5, Codec.UNSIGNED5, segmentHeader.have_method_flags_hi());
    1341        out.write(encodedBand);
    1342        PackingUtils.log("Wrote " + encodedBand.length + " bytes from method_flags[" + method_flags.length + "]");
    1343
    1344        // *method_attr_count :UNSIGNED5 [COUNT(1<<16,...)]
    1345        // *method_attr_indexes :UNSIGNED5 [SUM(*method_attr_count)]
    1346        encodedBand = encodeBandInt("method_attr_calls", method_attr_calls, Codec.UNSIGNED5);
    1347        out.write(encodedBand);
    1348        PackingUtils.log("Wrote " + encodedBand.length + " bytes from method_attr_calls[" + method_attr_calls.length + "]");
    1349
    1350        encodedBand = encodeBandInt("methodExceptionNumber", methodExceptionNumber.toArray(), Codec.UNSIGNED5);
    1351        out.write(encodedBand);
    1352        PackingUtils.log("Wrote " + encodedBand.length + " bytes from methodExceptionNumber[" + methodExceptionNumber.size() + "]");
    1353
    1354        encodedBand = encodeBandInt("methodExceptionClasses", cpEntryListToArray(methodExceptionClasses), Codec.UNSIGNED5);
    1355        out.write(encodedBand);
    1356        PackingUtils.log("Wrote " + encodedBand.length + " bytes from methodExceptionClasses[" + methodExceptionClasses.size() + "]");
    1357
    1358        encodedBand = encodeBandInt("methodSignature", cpEntryListToArray(methodSignature), Codec.UNSIGNED5);
    1359        out.write(encodedBand);
    1360        PackingUtils.log("Wrote " + encodedBand.length + " bytes from methodSignature[" + methodSignature.size() + "]");
    1361
    1362        method_RVA_bands.pack(out);
    1363        method_RIA_bands.pack(out);
    1364        method_RVPA_bands.pack(out);
    1365        method_RIPA_bands.pack(out);
    1366        method_AD_bands.pack(out);
    1367        for (final NewAttributeBands bands : methodAttributeBands) {
    1368            bands.pack(out);
    1369        }
    1370    }
    1371}