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