View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one or more
3    *  contributor license agreements.  See the NOTICE file distributed with
4    *  this work for additional information regarding copyright ownership.
5    *  The ASF licenses this file to You under the Apache License, Version 2.0
6    *  (the "License"); you may not use this file except in compliance with
7    *  the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   *  Unless required by applicable law or agreed to in writing, software
12   *  distributed under the License is distributed on an "AS IS" BASIS,
13   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   *  See the License for the specific language governing permissions and
15   *  limitations under the License.
16   */
17  package org.apache.commons.compress.harmony.pack200;
18  
19  import java.io.IOException;
20  import java.io.OutputStream;
21  import java.util.ArrayList;
22  import java.util.Arrays;
23  import java.util.Comparator;
24  import java.util.HashMap;
25  import java.util.HashSet;
26  import java.util.List;
27  import java.util.Map;
28  import java.util.Set;
29  
30  import org.apache.commons.compress.harmony.pack200.AttributeDefinitionBands.AttributeDefinition;
31  import org.apache.commons.compress.harmony.pack200.IcBands.IcTuple;
32  import org.objectweb.asm.Label;
33  import org.objectweb.asm.Opcodes;
34  
35  /**
36   * Class bands (corresponds to the {@code class_bands} set of bands in the pack200 specification)
37   */
38  public class ClassBands extends BandSet {
39  
40      private static final class TempParamAnnotation {
41  
42          int numParams;
43          int[] annoN;
44          IntList pairN = new IntList();
45          List<String> typeRS = new ArrayList<>();
46          List<String> nameRU = new ArrayList<>();
47          List<String> tags = new ArrayList<>();
48          List<Object> values = new ArrayList<>();
49          List<Integer> caseArrayN = new ArrayList<>();
50          List<String> nestTypeRS = new ArrayList<>();
51          List<String> nestNameRU = new ArrayList<>();
52          List<Integer> nestPairN = new ArrayList<>();
53  
54          TempParamAnnotation(final int numParams) {
55              this.numParams = numParams;
56              annoN = new int[numParams];
57          }
58  
59          void addParameterAnnotation(final int parameter, final String desc, final List<String> nameRU, final List<String> tags,
60                  final List<Object> values, final List<Integer> caseArrayN, final List<String> nestTypeRS, final List<String> nestNameRU,
61                  final List<Integer> nestPairN) {
62              annoN[parameter]++;
63              typeRS.add(desc);
64              pairN.add(nameRU.size());
65              this.nameRU.addAll(nameRU);
66              this.tags.addAll(tags);
67              this.values.addAll(values);
68              this.caseArrayN.addAll(caseArrayN);
69              this.nestTypeRS.addAll(nestTypeRS);
70              this.nestNameRU.addAll(nestNameRU);
71              this.nestPairN.addAll(nestPairN);
72          }
73      }
74  
75      private static final long[] EMPTY_LONG_ARRAY = {};
76  
77      protected static int countArgs(final String descriptor) {
78          final int bra = descriptor.indexOf('(');
79          final int ket = descriptor.indexOf(')');
80          if (bra == -1 || ket == -1 || ket < bra) {
81              throw new IllegalArgumentException("No arguments");
82          }
83  
84          boolean inType = false;
85          boolean consumingNextType = false;
86          int count = 0;
87          for (int i = bra + 1; i < ket; i++) {
88              final char charAt = descriptor.charAt(i);
89              if (inType && charAt == ';') {
90                  inType = false;
91                  consumingNextType = false;
92              } else if (!inType && charAt == 'L') {
93                  inType = true;
94                  count++;
95              } else if (charAt == '[') {
96                  consumingNextType = true;
97              } else if (inType) {
98                  // NOP
99              } 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 }