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