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 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 = false; 192 private boolean anySyntheticFields = false; 193 194 private boolean anySyntheticMethods = false; 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 = 0; 201 private int numMethodArgs = 0; 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) 596 && !isInnerClassOf(currentClass.toString(), inner)) { 597 Set<CPClass> referencedInnerClasses = classReferencesInnerClass.get(currentClass); 598 if (referencedInnerClasses == null) { 599 referencedInnerClasses = new HashSet<>(); 600 classReferencesInnerClass.put(currentClass, referencedInnerClasses); 601 } 602 referencedInnerClasses.add(inner); 603 } 604 } 605 } 606 607 public void doBciRenumbering(final IntList bciRenumbering, final Map<Label, Integer> labelsToOffsets) { 608 renumberBci(codeLineNumberTableBciP, bciRenumbering, labelsToOffsets); 609 renumberBci(codeLocalVariableTableBciP, bciRenumbering, labelsToOffsets); 610 renumberOffsetBci(codeLocalVariableTableBciP, codeLocalVariableTableSpanO, bciRenumbering, labelsToOffsets); 611 renumberBci(codeLocalVariableTypeTableBciP, bciRenumbering, labelsToOffsets); 612 renumberOffsetBci(codeLocalVariableTypeTableBciP, codeLocalVariableTypeTableSpanO, bciRenumbering, 613 labelsToOffsets); 614 renumberBci(codeHandlerStartP, bciRenumbering, labelsToOffsets); 615 renumberOffsetBci(codeHandlerStartP, codeHandlerEndPO, bciRenumbering, labelsToOffsets); 616 renumberDoubleOffsetBci(codeHandlerStartP, codeHandlerEndPO, codeHandlerCatchPO, bciRenumbering, 617 labelsToOffsets); 618 619 for (final NewAttributeBands newAttributeBandSet : classAttributeBands) { 620 newAttributeBandSet.renumberBci(bciRenumbering, labelsToOffsets); 621 } 622 for (final NewAttributeBands newAttributeBandSet : methodAttributeBands) { 623 newAttributeBandSet.renumberBci(bciRenumbering, labelsToOffsets); 624 } 625 for (final NewAttributeBands newAttributeBandSet : fieldAttributeBands) { 626 newAttributeBandSet.renumberBci(bciRenumbering, labelsToOffsets); 627 } 628 for (final NewAttributeBands newAttributeBandSet : codeAttributeBands) { 629 newAttributeBandSet.renumberBci(bciRenumbering, labelsToOffsets); 630 } 631 } 632 633 public void endOfClass() { // All the data for the current class has been 634 // read 635 final int numFields = tempFieldDesc.size(); 636 class_field_count[index] = numFields; 637 field_descr[index] = new CPNameAndType[numFields]; 638 field_flags[index] = new long[numFields]; 639 for (int i = 0; i < numFields; i++) { 640 field_descr[index][i] = tempFieldDesc.get(i); 641 field_flags[index][i] = tempFieldFlags.get(i).longValue(); 642 } 643 final int numMethods = tempMethodDesc.size(); 644 class_method_count[index] = numMethods; 645 method_descr[index] = new CPNameAndType[numMethods]; 646 method_flags[index] = new long[numMethods]; 647 for (int i = 0; i < numMethods; i++) { 648 method_descr[index][i] = tempMethodDesc.get(i); 649 method_flags[index][i] = tempMethodFlags.get(i).longValue(); 650 } 651 tempFieldDesc.clear(); 652 tempFieldFlags.clear(); 653 tempMethodDesc.clear(); 654 tempMethodFlags.clear(); 655 index++; 656 } 657 658 public void endOfMethod() { 659 if (tempMethodRVPA != null) { 660 method_RVPA_bands.addParameterAnnotation(tempMethodRVPA.numParams, tempMethodRVPA.annoN, 661 tempMethodRVPA.pairN, tempMethodRVPA.typeRS, tempMethodRVPA.nameRU, tempMethodRVPA.tags, 662 tempMethodRVPA.values, tempMethodRVPA.caseArrayN, tempMethodRVPA.nestTypeRS, 663 tempMethodRVPA.nestNameRU, tempMethodRVPA.nestPairN); 664 tempMethodRVPA = null; 665 } 666 if (tempMethodRIPA != null) { 667 method_RIPA_bands.addParameterAnnotation(tempMethodRIPA.numParams, tempMethodRIPA.annoN, 668 tempMethodRIPA.pairN, tempMethodRIPA.typeRS, tempMethodRIPA.nameRU, tempMethodRIPA.tags, 669 tempMethodRIPA.values, tempMethodRIPA.caseArrayN, tempMethodRIPA.nestTypeRS, 670 tempMethodRIPA.nestNameRU, tempMethodRIPA.nestPairN); 671 tempMethodRIPA = null; 672 } 673 if (codeFlags.size() > 0) { 674 final long latestCodeFlag = codeFlags.get(codeFlags.size() - 1).longValue(); 675 final int latestLocalVariableTableN = codeLocalVariableTableN.get(codeLocalVariableTableN.size() - 1); 676 if (latestCodeFlag == (1 << 2) && latestLocalVariableTableN == 0) { 677 codeLocalVariableTableN.remove(codeLocalVariableTableN.size() - 1); 678 codeFlags.remove(codeFlags.size() - 1); 679 codeFlags.add(Long.valueOf(0)); 680 } 681 } 682 } 683 684 /** 685 * All input classes for the segment have now been read in, so this method is 686 * called so that this class can calculate/complete anything it could not do 687 * while classes were being read. 688 */ 689 public void finaliseBands() { 690 final int defaultMajorVersion = segmentHeader.getDefaultMajorVersion(); 691 for (int i = 0; i < class_flags.length; i++) { 692 final int major = major_versions[i]; 693 if (major != defaultMajorVersion) { 694 class_flags[i] |= 1 << 24; 695 classFileVersionMajor.add(major); 696 classFileVersionMinor.add(0); 697 } 698 } 699 // Calculate code headers 700 codeHeaders = new int[codeHandlerCount.size()]; 701 int removed = 0; 702 for (int i = 0; i < codeHeaders.length; i++) { 703 final int numHandlers = codeHandlerCount.get(i - removed); 704 final int maxLocals = codeMaxLocals.get(i - removed); 705 final int maxStack = codeMaxStack.get(i - removed); 706 switch (numHandlers) { 707 case 0: { 708 final int header = maxLocals * 12 + maxStack + 1; 709 if (header < 145 && maxStack < 12) { 710 codeHeaders[i] = header; 711 } 712 break; 713 } 714 case 1: { 715 final int header = maxLocals * 8 + maxStack + 145; 716 if (header < 209 && maxStack < 8) { 717 codeHeaders[i] = header; 718 } 719 break; 720 } 721 case 2: { 722 final int header = maxLocals * 7 + maxStack + 209; 723 if (header < 256 && maxStack < 7) { 724 codeHeaders[i] = header; 725 } 726 break; 727 } 728 default: 729 break; 730 } 731 if (codeHeaders[i] != 0) { // Remove the redundant values from 732 // codeHandlerCount, codeMaxLocals and 733 // codeMaxStack 734 codeHandlerCount.remove(i - removed); 735 codeMaxLocals.remove(i - removed); 736 codeMaxStack.remove(i - removed); 737 removed++; 738 } else if (!segment.getSegmentHeader().have_all_code_flags()) { 739 codeFlags.add(Long.valueOf(0)); 740 } 741 } 742 743 // Compute any required IcLocals 744 final IntList innerClassesN = new IntList(); 745 final List<IcTuple> icLocal = new ArrayList<>(); 746 for (int i = 0; i < class_this.length; i++) { 747 final CPClass cpClass = class_this[i]; 748 final Set<CPClass> referencedInnerClasses = classReferencesInnerClass.get(cpClass); 749 if (referencedInnerClasses != null) { 750 int innerN = 0; 751 final List<IcTuple> innerClasses = segment.getIcBands().getInnerClassesForOuter(cpClass.toString()); 752 if (innerClasses != null) { 753 for (final IcTuple element : innerClasses) { 754 referencedInnerClasses.remove(element.C); 755 } 756 } 757 for (final CPClass inner : referencedInnerClasses) { 758 final IcTuple icTuple = segment.getIcBands().getIcTuple(inner); 759 if (icTuple != null && !icTuple.isAnonymous()) { 760 // should transmit an icLocal entry 761 icLocal.add(icTuple); 762 innerN++; 763 } 764 } 765 if (innerN != 0) { 766 innerClassesN.add(innerN); 767 class_flags[i] |= (1 << 23); 768 } 769 } 770 } 771 class_InnerClasses_N = innerClassesN.toArray(); 772 class_InnerClasses_RC = new CPClass[icLocal.size()]; 773 class_InnerClasses_F = new int[icLocal.size()]; 774 classInnerClassesOuterRCN = new ArrayList<>(); 775 classInnerClassesNameRUN = new ArrayList<>(); 776 for (int i = 0; i < class_InnerClasses_RC.length; i++) { 777 final IcTuple icTuple = icLocal.get(i); 778 class_InnerClasses_RC[i] = (icTuple.C); 779 if (icTuple.C2 == null && icTuple.N == null) { 780 class_InnerClasses_F[i] = 0; 781 } else { 782 if (icTuple.F == 0) { 783 class_InnerClasses_F[i] = 0x00010000; 784 } else { 785 class_InnerClasses_F[i] = icTuple.F; 786 } 787 classInnerClassesOuterRCN.add(icTuple.C2); 788 classInnerClassesNameRUN.add(icTuple.N); 789 } 790 } 791 // Calculate any backwards calls from metadata bands 792 final IntList classAttrCalls = new IntList(); 793 final IntList fieldAttrCalls = new IntList(); 794 final IntList methodAttrCalls = new IntList(); 795 final IntList codeAttrCalls = new IntList(); 796 797 if (class_RVA_bands.hasContent()) { 798 classAttrCalls.add(class_RVA_bands.numBackwardsCalls()); 799 } 800 if (class_RIA_bands.hasContent()) { 801 classAttrCalls.add(class_RIA_bands.numBackwardsCalls()); 802 } 803 if (field_RVA_bands.hasContent()) { 804 fieldAttrCalls.add(field_RVA_bands.numBackwardsCalls()); 805 } 806 if (field_RIA_bands.hasContent()) { 807 fieldAttrCalls.add(field_RIA_bands.numBackwardsCalls()); 808 } 809 if (method_RVA_bands.hasContent()) { 810 methodAttrCalls.add(method_RVA_bands.numBackwardsCalls()); 811 } 812 if (method_RIA_bands.hasContent()) { 813 methodAttrCalls.add(method_RIA_bands.numBackwardsCalls()); 814 } 815 if (method_RVPA_bands.hasContent()) { 816 methodAttrCalls.add(method_RVPA_bands.numBackwardsCalls()); 817 } 818 if (method_RIPA_bands.hasContent()) { 819 methodAttrCalls.add(method_RIPA_bands.numBackwardsCalls()); 820 } 821 if (method_AD_bands.hasContent()) { 822 methodAttrCalls.add(method_AD_bands.numBackwardsCalls()); 823 } 824 825 // Sort non-predefined attribute bands 826 final Comparator<NewAttributeBands> comparator = (arg0, arg1) -> arg0.getFlagIndex() - arg1.getFlagIndex(); 827 classAttributeBands.sort(comparator); 828 methodAttributeBands.sort(comparator); 829 fieldAttributeBands.sort(comparator); 830 codeAttributeBands.sort(comparator); 831 832 for (final NewAttributeBands bands : classAttributeBands) { 833 if (bands.isUsedAtLeastOnce()) { 834 for (final int backwardsCallCount : bands.numBackwardsCalls()) { 835 classAttrCalls.add(backwardsCallCount); 836 } 837 } 838 } 839 for (final NewAttributeBands bands : methodAttributeBands) { 840 if (bands.isUsedAtLeastOnce()) { 841 for (final int backwardsCallCount : bands.numBackwardsCalls()) { 842 methodAttrCalls.add(backwardsCallCount); 843 } 844 } 845 } 846 for (final NewAttributeBands bands : fieldAttributeBands) { 847 if (bands.isUsedAtLeastOnce()) { 848 for (final int backwardsCallCount : bands.numBackwardsCalls()) { 849 fieldAttrCalls.add(backwardsCallCount); 850 } 851 } 852 } 853 for (final NewAttributeBands bands : codeAttributeBands) { 854 if (bands.isUsedAtLeastOnce()) { 855 for (final int backwardsCallCount : bands.numBackwardsCalls()) { 856 codeAttrCalls.add(backwardsCallCount); 857 } 858 } 859 } 860 861 class_attr_calls = classAttrCalls.toArray(); 862 field_attr_calls = fieldAttrCalls.toArray(); 863 method_attr_calls = methodAttrCalls.toArray(); 864 code_attr_calls = codeAttrCalls.toArray(); 865 } 866 867 private int[] getInts(final CPClass[] cpClasses) { 868 final int[] ints = new int[cpClasses.length]; 869 for (int i = 0; i < ints.length; i++) { 870 if (cpClasses[i] != null) { 871 ints[i] = cpClasses[i].getIndex(); 872 } 873 } 874 return ints; 875 } 876 877 public boolean isAnySyntheticClasses() { 878 return anySyntheticClasses; 879 } 880 881 public boolean isAnySyntheticFields() { 882 return anySyntheticFields; 883 } 884 885 public boolean isAnySyntheticMethods() { 886 return anySyntheticMethods; 887 } 888 889 private boolean isInnerClass(final String possibleInner) { 890 return possibleInner.indexOf('$') != -1; 891 } 892 893 private boolean isInnerClassOf(final String possibleInner, final CPClass possibleOuter) { 894 if (isInnerClass(possibleInner)) { 895 final String superClassName = possibleInner.substring(0, possibleInner.lastIndexOf('$')); 896 if (superClassName.equals(possibleOuter.toString())) { 897 return true; 898 } 899 return isInnerClassOf(superClassName, possibleOuter); 900 } 901 return false; 902 } 903 904 public int numClassesProcessed() { 905 return index; 906 } 907 908 @Override 909 public void pack(final OutputStream out) throws IOException, Pack200Exception { 910 PackingUtils.log("Writing class bands..."); 911 912 byte[] encodedBand = encodeBandInt("class_this", getInts(class_this), Codec.DELTA5); 913 out.write(encodedBand); 914 PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_this[" + class_this.length + "]"); 915 916 encodedBand = encodeBandInt("class_super", getInts(class_super), Codec.DELTA5); 917 out.write(encodedBand); 918 PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_super[" + class_super.length + "]"); 919 920 encodedBand = encodeBandInt("class_interface_count", class_interface_count, Codec.DELTA5); 921 out.write(encodedBand); 922 PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_interface_count[" 923 + class_interface_count.length + "]"); 924 925 final int totalInterfaces = sum(class_interface_count); 926 final int[] classInterface = new int[totalInterfaces]; 927 int k = 0; 928 for (final CPClass[] element : class_interface) { 929 if (element != null) { 930 for (final CPClass cpClass : element) { 931 classInterface[k] = cpClass.getIndex(); 932 k++; 933 } 934 } 935 } 936 937 encodedBand = encodeBandInt("class_interface", classInterface, Codec.DELTA5); 938 out.write(encodedBand); 939 PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_interface[" + classInterface.length + "]"); 940 941 encodedBand = encodeBandInt("class_field_count", class_field_count, Codec.DELTA5); 942 out.write(encodedBand); 943 PackingUtils 944 .log("Wrote " + encodedBand.length + " bytes from class_field_count[" + class_field_count.length + "]"); 945 946 encodedBand = encodeBandInt("class_method_count", class_method_count, Codec.DELTA5); 947 out.write(encodedBand); 948 PackingUtils.log( 949 "Wrote " + encodedBand.length + " bytes from class_method_count[" + class_method_count.length + "]"); 950 951 final int totalFields = sum(class_field_count); 952 final int[] fieldDescr = new int[totalFields]; 953 k = 0; 954 for (int i = 0; i < index; i++) { 955 for (int j = 0; j < field_descr[i].length; j++) { 956 final CPNameAndType descr = field_descr[i][j]; 957 fieldDescr[k] = descr.getIndex(); 958 k++; 959 } 960 } 961 962 encodedBand = encodeBandInt("field_descr", fieldDescr, Codec.DELTA5); 963 out.write(encodedBand); 964 PackingUtils.log("Wrote " + encodedBand.length + " bytes from field_descr[" + fieldDescr.length + "]"); 965 966 writeFieldAttributeBands(out); 967 968 final int totalMethods = sum(class_method_count); 969 final int[] methodDescr = new int[totalMethods]; 970 k = 0; 971 for (int i = 0; i < index; i++) { 972 for (int j = 0; j < method_descr[i].length; j++) { 973 final CPNameAndType descr = method_descr[i][j]; 974 methodDescr[k] = descr.getIndex(); 975 k++; 976 } 977 } 978 979 encodedBand = encodeBandInt("method_descr", methodDescr, Codec.MDELTA5); 980 out.write(encodedBand); 981 PackingUtils.log("Wrote " + encodedBand.length + " bytes from method_descr[" + methodDescr.length + "]"); 982 983 writeMethodAttributeBands(out); 984 writeClassAttributeBands(out); 985 writeCodeBands(out); 986 } 987 988 /** 989 * Remove all entries for the current class 990 */ 991 public void removeCurrentClass() { 992 // Note - this doesn't remove any entries added to the constant pool but 993 // that shouldn't be a problem 994 if ((class_flags[index] & (1 << 17)) != 0) { 995 classSourceFile.remove(classSourceFile.size() - 1); 996 } 997 if ((class_flags[index] & (1 << 18)) != 0) { 998 classEnclosingMethodClass.remove(classEnclosingMethodClass.size() - 1); 999 classEnclosingMethodDesc.remove(classEnclosingMethodDesc.size() - 1); 1000 } 1001 if ((class_flags[index] & (1 << 19)) != 0) { 1002 classSignature.remove(classSignature.size() - 1); 1003 } 1004 if ((class_flags[index] & (1 << 21)) != 0) { 1005 class_RVA_bands.removeLatest(); 1006 } 1007 if ((class_flags[index] & (1 << 22)) != 0) { 1008 class_RIA_bands.removeLatest(); 1009 } 1010 for (final Long flagsL : tempFieldFlags) { 1011 final long flags = flagsL.longValue(); 1012 if ((flags & (1 << 19)) != 0) { 1013 fieldSignature.remove(fieldSignature.size() - 1); 1014 } 1015 if ((flags & (1 << 17)) != 0) { 1016 fieldConstantValueKQ.remove(fieldConstantValueKQ.size() - 1); 1017 } 1018 if ((flags & (1 << 21)) != 0) { 1019 field_RVA_bands.removeLatest(); 1020 } 1021 if ((flags & (1 << 22)) != 0) { 1022 field_RIA_bands.removeLatest(); 1023 } 1024 } 1025 for (final Long flagsL : tempMethodFlags) { 1026 final long flags = flagsL.longValue(); 1027 if ((flags & (1 << 19)) != 0) { 1028 methodSignature.remove(methodSignature.size() - 1); 1029 } 1030 if ((flags & (1 << 18)) != 0) { 1031 final int exceptions = methodExceptionNumber.remove(methodExceptionNumber.size() - 1); 1032 for (int i = 0; i < exceptions; i++) { 1033 methodExceptionClasses.remove(methodExceptionClasses.size() - 1); 1034 } 1035 } 1036 if ((flags & (1 << 17)) != 0) { // has code attribute 1037 codeMaxLocals.remove(codeMaxLocals.size() - 1); 1038 codeMaxStack.remove(codeMaxStack.size() - 1); 1039 final int handlers = codeHandlerCount.remove(codeHandlerCount.size() - 1); 1040 for (int i = 0; i < handlers; i++) { 1041 final int index = codeHandlerStartP.size() - 1; 1042 codeHandlerStartP.remove(index); 1043 codeHandlerEndPO.remove(index); 1044 codeHandlerCatchPO.remove(index); 1045 codeHandlerClass.remove(index); 1046 } 1047 if (!stripDebug) { 1048 final long cdeFlags = codeFlags.remove(codeFlags.size() - 1).longValue(); 1049 final int numLocalVariables = codeLocalVariableTableN.remove(codeLocalVariableTableN.size() - 1); 1050 for (int i = 0; i < numLocalVariables; i++) { 1051 final int location = codeLocalVariableTableBciP.size() - 1; 1052 codeLocalVariableTableBciP.remove(location); 1053 codeLocalVariableTableSpanO.remove(location); 1054 codeLocalVariableTableNameRU.remove(location); 1055 codeLocalVariableTableTypeRS.remove(location); 1056 codeLocalVariableTableSlot.remove(location); 1057 } 1058 if ((cdeFlags & (1 << 3)) != 0) { 1059 final int numLocalVariablesInTypeTable = codeLocalVariableTypeTableN 1060 .remove(codeLocalVariableTypeTableN.size() - 1); 1061 for (int i = 0; i < numLocalVariablesInTypeTable; i++) { 1062 final int location = codeLocalVariableTypeTableBciP.size() - 1; 1063 codeLocalVariableTypeTableBciP.remove(location); 1064 codeLocalVariableTypeTableSpanO.remove(location); 1065 codeLocalVariableTypeTableNameRU.remove(location); 1066 codeLocalVariableTypeTableTypeRS.remove(location); 1067 codeLocalVariableTypeTableSlot.remove(location); 1068 } 1069 } 1070 if ((cdeFlags & (1 << 1)) != 0) { 1071 final int numLineNumbers = codeLineNumberTableN.remove(codeLineNumberTableN.size() - 1); 1072 for (int i = 0; i < numLineNumbers; i++) { 1073 final int location = codeLineNumberTableBciP.size() - 1; 1074 codeLineNumberTableBciP.remove(location); 1075 codeLineNumberTableLine.remove(location); 1076 } 1077 } 1078 } 1079 } 1080 if ((flags & (1 << 21)) != 0) { 1081 method_RVA_bands.removeLatest(); 1082 } 1083 if ((flags & (1 << 22)) != 0) { 1084 method_RIA_bands.removeLatest(); 1085 } 1086 if ((flags & (1 << 23)) != 0) { 1087 method_RVPA_bands.removeLatest(); 1088 } 1089 if ((flags & (1 << 24)) != 0) { 1090 method_RIPA_bands.removeLatest(); 1091 } 1092 if ((flags & (1 << 25)) != 0) { 1093 method_AD_bands.removeLatest(); 1094 } 1095 } 1096 class_this[index] = null; 1097 class_super[index] = null; 1098 class_interface_count[index] = 0; 1099 class_interface[index] = null; 1100 major_versions[index] = 0; 1101 class_flags[index] = 0; 1102 tempFieldDesc.clear(); 1103 tempFieldFlags.clear(); 1104 tempMethodDesc.clear(); 1105 tempMethodFlags.clear(); 1106 if (index > 0) { 1107 index--; 1108 } 1109 } 1110 1111 private void renumberBci(final List<Integer> list, final IntList bciRenumbering, 1112 final Map<Label, Integer> labelsToOffsets) { 1113 for (int i = list.size() - 1; i >= 0; i--) { 1114 final Object label = list.get(i); 1115 if (label instanceof Integer) { 1116 break; 1117 } 1118 if (label instanceof Label) { 1119 list.remove(i); 1120 final Integer bytecodeIndex = labelsToOffsets.get(label); 1121 list.add(i, Integer.valueOf(bciRenumbering.get(bytecodeIndex.intValue()))); 1122 } 1123 } 1124 } 1125 1126 private void renumberDoubleOffsetBci(final List<Integer> relative, final List<Integer> firstOffset, final List<Object> list, 1127 final IntList bciRenumbering, final Map<Label, Integer> labelsToOffsets) { 1128 // TODO: There's probably a nicer way of doing this... 1129 for (int i = list.size() - 1; i >= 0; i--) { 1130 final Object label = list.get(i); 1131 if (label instanceof Integer) { 1132 break; 1133 } 1134 if (label instanceof Label) { 1135 list.remove(i); 1136 final Integer bytecodeIndex = labelsToOffsets.get(label); 1137 final Integer renumberedOffset = Integer.valueOf(bciRenumbering.get(bytecodeIndex.intValue()) 1138 - relative.get(i).intValue() - firstOffset.get(i).intValue()); 1139 list.add(i, renumberedOffset); 1140 } 1141 } 1142 } 1143 1144 private void renumberOffsetBci(final List<Integer> relative, final List<Integer> list, final IntList bciRenumbering, 1145 final Map<Label, Integer> labelsToOffsets) { 1146 for (int i = list.size() - 1; i >= 0; i--) { 1147 final Object label = list.get(i); 1148 if (label instanceof Integer) { 1149 break; 1150 } 1151 if (label instanceof Label) { 1152 list.remove(i); 1153 final Integer bytecodeIndex = labelsToOffsets.get(label); 1154 final Integer renumberedOffset = Integer 1155 .valueOf(bciRenumbering.get(bytecodeIndex.intValue()) - relative.get(i).intValue()); 1156 list.add(i, renumberedOffset); 1157 } 1158 } 1159 } 1160 1161 private int sum(final int[] ints) { 1162 int sum = 0; 1163 for (final int j : ints) { 1164 sum += j; 1165 } 1166 return sum; 1167 } 1168 1169 private void writeClassAttributeBands(final OutputStream out) throws IOException, Pack200Exception { 1170 byte[] encodedBand = encodeFlags("class_flags", class_flags, Codec.UNSIGNED5, Codec.UNSIGNED5, 1171 segmentHeader.have_class_flags_hi()); 1172 out.write(encodedBand); 1173 PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_flags[" + class_flags.length + "]"); 1174 1175 // These bands are not needed, but could be used to reduce the size of 1176 // the archive if there are enough different non-standard attributes 1177 // defined that segmentHeader.have_class_flags_hi() is true. The same 1178 // applies to method_attr_count, field_attr_count, code_attr_count etc. 1179 1180 // *class_attr_count :UNSIGNED5 [COUNT(1<<16,...)] 1181 // *class_attr_indexes :UNSIGNED5 [SUM(*class_attr_count)] 1182 1183 encodedBand = encodeBandInt("class_attr_calls", class_attr_calls, Codec.UNSIGNED5); 1184 out.write(encodedBand); 1185 PackingUtils 1186 .log("Wrote " + encodedBand.length + " bytes from class_attr_calls[" + class_attr_calls.length + "]"); 1187 1188 encodedBand = encodeBandInt("classSourceFile", cpEntryOrNullListToArray(classSourceFile), Codec.UNSIGNED5); 1189 out.write(encodedBand); 1190 PackingUtils.log("Wrote " + encodedBand.length + " bytes from classSourceFile[" + classSourceFile.size() + "]"); 1191 1192 encodedBand = encodeBandInt("class_enclosing_method_RC", cpEntryListToArray(classEnclosingMethodClass), 1193 Codec.UNSIGNED5); 1194 out.write(encodedBand); 1195 PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_enclosing_method_RC[" 1196 + classEnclosingMethodClass.size() + "]"); 1197 1198 encodedBand = encodeBandInt("class_EnclosingMethod_RDN", cpEntryOrNullListToArray(classEnclosingMethodDesc), 1199 Codec.UNSIGNED5); 1200 out.write(encodedBand); 1201 PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_EnclosingMethod_RDN[" 1202 + classEnclosingMethodDesc.size() + "]"); 1203 1204 encodedBand = encodeBandInt("class_Signature_RS", cpEntryListToArray(classSignature), Codec.UNSIGNED5); 1205 out.write(encodedBand); 1206 PackingUtils 1207 .log("Wrote " + encodedBand.length + " bytes from class_Signature_RS[" + classSignature.size() + "]"); 1208 1209 class_RVA_bands.pack(out); 1210 class_RIA_bands.pack(out); 1211 1212 encodedBand = encodeBandInt("class_InnerClasses_N", class_InnerClasses_N, Codec.UNSIGNED5); 1213 out.write(encodedBand); 1214 PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_InnerClasses_N[" 1215 + class_InnerClasses_N.length + "]"); 1216 1217 encodedBand = encodeBandInt("class_InnerClasses_RC", getInts(class_InnerClasses_RC), Codec.UNSIGNED5); 1218 out.write(encodedBand); 1219 PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_InnerClasses_RC[" 1220 + class_InnerClasses_RC.length + "]"); 1221 1222 encodedBand = encodeBandInt("class_InnerClasses_F", class_InnerClasses_F, Codec.UNSIGNED5); 1223 out.write(encodedBand); 1224 PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_InnerClasses_F[" 1225 + class_InnerClasses_F.length + "]"); 1226 1227 encodedBand = encodeBandInt("class_InnerClasses_outer_RCN", cpEntryOrNullListToArray(classInnerClassesOuterRCN), 1228 Codec.UNSIGNED5); 1229 out.write(encodedBand); 1230 PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_InnerClasses_outer_RCN[" 1231 + classInnerClassesOuterRCN.size() + "]"); 1232 1233 encodedBand = encodeBandInt("class_InnerClasses_name_RUN", cpEntryOrNullListToArray(classInnerClassesNameRUN), 1234 Codec.UNSIGNED5); 1235 out.write(encodedBand); 1236 PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_InnerClasses_name_RUN[" 1237 + classInnerClassesNameRUN.size() + "]"); 1238 1239 encodedBand = encodeBandInt("classFileVersionMinor", classFileVersionMinor.toArray(), Codec.UNSIGNED5); 1240 out.write(encodedBand); 1241 PackingUtils.log("Wrote " + encodedBand.length + " bytes from classFileVersionMinor[" 1242 + classFileVersionMinor.size() + "]"); 1243 1244 encodedBand = encodeBandInt("classFileVersionMajor", classFileVersionMajor.toArray(), Codec.UNSIGNED5); 1245 out.write(encodedBand); 1246 PackingUtils.log("Wrote " + encodedBand.length + " bytes from classFileVersionMajor[" 1247 + classFileVersionMajor.size() + "]"); 1248 1249 for (final NewAttributeBands classAttributeBand : classAttributeBands) { 1250 classAttributeBand.pack(out); 1251 } 1252 } 1253 1254 private void writeCodeAttributeBands(final OutputStream out) throws IOException, Pack200Exception { 1255 byte[] encodedBand = encodeFlags("codeFlags", longListToArray(codeFlags), Codec.UNSIGNED5, Codec.UNSIGNED5, 1256 segmentHeader.have_code_flags_hi()); 1257 out.write(encodedBand); 1258 PackingUtils.log("Wrote " + encodedBand.length + " bytes from codeFlags[" + codeFlags.size() + "]"); 1259 1260 // *code_attr_count :UNSIGNED5 [COUNT(1<<16,...)] 1261 // *code_attr_indexes :UNSIGNED5 [SUM(*code_attr_count)] 1262 encodedBand = encodeBandInt("code_attr_calls", code_attr_calls, Codec.UNSIGNED5); 1263 out.write(encodedBand); 1264 PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_attr_calls[" + code_attr_calls.length + "]"); 1265 1266 encodedBand = encodeBandInt("code_LineNumberTable_N", codeLineNumberTableN.toArray(), Codec.UNSIGNED5); 1267 out.write(encodedBand); 1268 PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LineNumberTable_N[" 1269 + codeLineNumberTableN.size() + "]"); 1270 1271 encodedBand = encodeBandInt("code_LineNumberTable_bci_P", integerListToArray(codeLineNumberTableBciP), 1272 Codec.BCI5); 1273 out.write(encodedBand); 1274 PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LineNumberTable_bci_P[" 1275 + codeLineNumberTableBciP.size() + "]"); 1276 1277 encodedBand = encodeBandInt("code_LineNumberTable_line", codeLineNumberTableLine.toArray(), Codec.UNSIGNED5); 1278 out.write(encodedBand); 1279 PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LineNumberTable_line[" 1280 + codeLineNumberTableLine.size() + "]"); 1281 1282 encodedBand = encodeBandInt("code_LocalVariableTable_N", codeLocalVariableTableN.toArray(), Codec.UNSIGNED5); 1283 out.write(encodedBand); 1284 PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTable_N[" 1285 + codeLocalVariableTableN.size() + "]"); 1286 1287 encodedBand = encodeBandInt("code_LocalVariableTable_bci_P", integerListToArray(codeLocalVariableTableBciP), 1288 Codec.BCI5); 1289 out.write(encodedBand); 1290 PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTable_bci_P[" 1291 + codeLocalVariableTableBciP.size() + "]"); 1292 1293 encodedBand = encodeBandInt("code_LocalVariableTable_span_O", integerListToArray(codeLocalVariableTableSpanO), 1294 Codec.BRANCH5); 1295 out.write(encodedBand); 1296 PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTable_span_O[" 1297 + codeLocalVariableTableSpanO.size() + "]"); 1298 1299 encodedBand = encodeBandInt("code_LocalVariableTable_name_RU", cpEntryListToArray(codeLocalVariableTableNameRU), 1300 Codec.UNSIGNED5); 1301 out.write(encodedBand); 1302 PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTable_name_RU[" 1303 + codeLocalVariableTableNameRU.size() + "]"); 1304 1305 encodedBand = encodeBandInt("code_LocalVariableTable_type_RS", cpEntryListToArray(codeLocalVariableTableTypeRS), 1306 Codec.UNSIGNED5); 1307 out.write(encodedBand); 1308 PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTable_type_RS[" 1309 + codeLocalVariableTableTypeRS.size() + "]"); 1310 1311 encodedBand = encodeBandInt("code_LocalVariableTable_slot", codeLocalVariableTableSlot.toArray(), 1312 Codec.UNSIGNED5); 1313 out.write(encodedBand); 1314 PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTable_slot[" 1315 + codeLocalVariableTableSlot.size() + "]"); 1316 1317 encodedBand = encodeBandInt("code_LocalVariableTypeTable_N", codeLocalVariableTypeTableN.toArray(), 1318 Codec.UNSIGNED5); 1319 out.write(encodedBand); 1320 PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTypeTable_N[" 1321 + codeLocalVariableTypeTableN.size() + "]"); 1322 1323 encodedBand = encodeBandInt("code_LocalVariableTypeTable_bci_P", 1324 integerListToArray(codeLocalVariableTypeTableBciP), Codec.BCI5); 1325 out.write(encodedBand); 1326 PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTypeTable_bci_P[" 1327 + codeLocalVariableTypeTableBciP.size() + "]"); 1328 1329 encodedBand = encodeBandInt("code_LocalVariableTypeTable_span_O", 1330 integerListToArray(codeLocalVariableTypeTableSpanO), Codec.BRANCH5); 1331 out.write(encodedBand); 1332 PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTypeTable_span_O[" 1333 + codeLocalVariableTypeTableSpanO.size() + "]"); 1334 1335 encodedBand = encodeBandInt("code_LocalVariableTypeTable_name_RU", 1336 cpEntryListToArray(codeLocalVariableTypeTableNameRU), Codec.UNSIGNED5); 1337 out.write(encodedBand); 1338 PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTypeTable_name_RU[" 1339 + codeLocalVariableTypeTableNameRU.size() + "]"); 1340 1341 encodedBand = encodeBandInt("code_LocalVariableTypeTable_type_RS", 1342 cpEntryListToArray(codeLocalVariableTypeTableTypeRS), Codec.UNSIGNED5); 1343 out.write(encodedBand); 1344 PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTypeTable_type_RS[" 1345 + codeLocalVariableTypeTableTypeRS.size() + "]"); 1346 1347 encodedBand = encodeBandInt("code_LocalVariableTypeTable_slot", codeLocalVariableTypeTableSlot.toArray(), 1348 Codec.UNSIGNED5); 1349 out.write(encodedBand); 1350 PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTypeTable_slot[" 1351 + codeLocalVariableTypeTableSlot.size() + "]"); 1352 1353 for (final NewAttributeBands bands : codeAttributeBands) { 1354 bands.pack(out); 1355 } 1356 } 1357 1358 private void writeCodeBands(final OutputStream out) throws IOException, Pack200Exception { 1359 byte[] encodedBand = encodeBandInt("codeHeaders", codeHeaders, Codec.BYTE1); 1360 out.write(encodedBand); 1361 PackingUtils.log("Wrote " + encodedBand.length + " bytes from codeHeaders[" + codeHeaders.length + "]"); 1362 1363 encodedBand = encodeBandInt("codeMaxStack", codeMaxStack.toArray(), Codec.UNSIGNED5); 1364 out.write(encodedBand); 1365 PackingUtils.log("Wrote " + encodedBand.length + " bytes from codeMaxStack[" + codeMaxStack.size() + "]"); 1366 1367 encodedBand = encodeBandInt("codeMaxLocals", codeMaxLocals.toArray(), Codec.UNSIGNED5); 1368 out.write(encodedBand); 1369 PackingUtils.log("Wrote " + encodedBand.length + " bytes from codeMaxLocals[" + codeMaxLocals.size() + "]"); 1370 1371 encodedBand = encodeBandInt("codeHandlerCount", codeHandlerCount.toArray(), Codec.UNSIGNED5); 1372 out.write(encodedBand); 1373 PackingUtils 1374 .log("Wrote " + encodedBand.length + " bytes from codeHandlerCount[" + codeHandlerCount.size() + "]"); 1375 1376 encodedBand = encodeBandInt("codeHandlerStartP", integerListToArray(codeHandlerStartP), Codec.BCI5); 1377 out.write(encodedBand); 1378 PackingUtils 1379 .log("Wrote " + encodedBand.length + " bytes from codeHandlerStartP[" + codeHandlerStartP.size() + "]"); 1380 1381 encodedBand = encodeBandInt("codeHandlerEndPO", integerListToArray(codeHandlerEndPO), Codec.BRANCH5); 1382 out.write(encodedBand); 1383 PackingUtils 1384 .log("Wrote " + encodedBand.length + " bytes from codeHandlerEndPO[" + codeHandlerEndPO.size() + "]"); 1385 1386 encodedBand = encodeBandInt("codeHandlerCatchPO", integerListToArray(codeHandlerCatchPO), Codec.BRANCH5); 1387 out.write(encodedBand); 1388 PackingUtils.log( 1389 "Wrote " + encodedBand.length + " bytes from codeHandlerCatchPO[" + codeHandlerCatchPO.size() + "]"); 1390 1391 encodedBand = encodeBandInt("codeHandlerClass", cpEntryOrNullListToArray(codeHandlerClass), Codec.UNSIGNED5); 1392 out.write(encodedBand); 1393 PackingUtils 1394 .log("Wrote " + encodedBand.length + " bytes from codeHandlerClass[" + codeHandlerClass.size() + "]"); 1395 1396 writeCodeAttributeBands(out); 1397 } 1398 1399 private void writeFieldAttributeBands(final OutputStream out) throws IOException, Pack200Exception { 1400 byte[] encodedBand = encodeFlags("field_flags", field_flags, Codec.UNSIGNED5, Codec.UNSIGNED5, 1401 segmentHeader.have_field_flags_hi()); 1402 out.write(encodedBand); 1403 PackingUtils.log("Wrote " + encodedBand.length + " bytes from field_flags[" + field_flags.length + "]"); 1404 1405 // *field_attr_count :UNSIGNED5 [COUNT(1<<16,...)] 1406 // *field_attr_indexes :UNSIGNED5 [SUM(*field_attr_count)] 1407 encodedBand = encodeBandInt("field_attr_calls", field_attr_calls, Codec.UNSIGNED5); 1408 out.write(encodedBand); 1409 PackingUtils 1410 .log("Wrote " + encodedBand.length + " bytes from field_attr_calls[" + field_attr_calls.length + "]"); 1411 1412 encodedBand = encodeBandInt("fieldConstantValueKQ", cpEntryListToArray(fieldConstantValueKQ), Codec.UNSIGNED5); 1413 out.write(encodedBand); 1414 PackingUtils.log("Wrote " + encodedBand.length + " bytes from fieldConstantValueKQ[" 1415 + fieldConstantValueKQ.size() + "]"); 1416 1417 encodedBand = encodeBandInt("fieldSignature", cpEntryListToArray(fieldSignature), Codec.UNSIGNED5); 1418 out.write(encodedBand); 1419 PackingUtils.log("Wrote " + encodedBand.length + " bytes from fieldSignature[" + fieldSignature.size() + "]"); 1420 1421 field_RVA_bands.pack(out); 1422 field_RIA_bands.pack(out); 1423 for (final NewAttributeBands bands : fieldAttributeBands) { 1424 bands.pack(out); 1425 } 1426 } 1427 1428 private void writeMethodAttributeBands(final OutputStream out) throws IOException, Pack200Exception { 1429 byte[] encodedBand = encodeFlags("method_flags", method_flags, Codec.UNSIGNED5, Codec.UNSIGNED5, 1430 segmentHeader.have_method_flags_hi()); 1431 out.write(encodedBand); 1432 PackingUtils.log("Wrote " + encodedBand.length + " bytes from method_flags[" + method_flags.length + "]"); 1433 1434 // *method_attr_count :UNSIGNED5 [COUNT(1<<16,...)] 1435 // *method_attr_indexes :UNSIGNED5 [SUM(*method_attr_count)] 1436 encodedBand = encodeBandInt("method_attr_calls", method_attr_calls, Codec.UNSIGNED5); 1437 out.write(encodedBand); 1438 PackingUtils 1439 .log("Wrote " + encodedBand.length + " bytes from method_attr_calls[" + method_attr_calls.length + "]"); 1440 1441 encodedBand = encodeBandInt("methodExceptionNumber", methodExceptionNumber.toArray(), Codec.UNSIGNED5); 1442 out.write(encodedBand); 1443 PackingUtils.log("Wrote " + encodedBand.length + " bytes from methodExceptionNumber[" 1444 + methodExceptionNumber.size() + "]"); 1445 1446 encodedBand = encodeBandInt("methodExceptionClasses", cpEntryListToArray(methodExceptionClasses), 1447 Codec.UNSIGNED5); 1448 out.write(encodedBand); 1449 PackingUtils.log("Wrote " + encodedBand.length + " bytes from methodExceptionClasses[" 1450 + methodExceptionClasses.size() + "]"); 1451 1452 encodedBand = encodeBandInt("methodSignature", cpEntryListToArray(methodSignature), Codec.UNSIGNED5); 1453 out.write(encodedBand); 1454 PackingUtils.log("Wrote " + encodedBand.length + " bytes from methodSignature[" + methodSignature.size() + "]"); 1455 1456 method_RVA_bands.pack(out); 1457 method_RIA_bands.pack(out); 1458 method_RVPA_bands.pack(out); 1459 method_RIPA_bands.pack(out); 1460 method_AD_bands.pack(out); 1461 for (final NewAttributeBands bands : methodAttributeBands) { 1462 bands.pack(out); 1463 } 1464 } 1465}