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