001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * https://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.commons.compress.harmony.unpack200; 020 021import java.io.ByteArrayOutputStream; 022import java.io.IOException; 023import java.io.InputStream; 024import java.util.ArrayList; 025import java.util.Collections; 026import java.util.List; 027 028import org.apache.commons.compress.harmony.pack200.Codec; 029import org.apache.commons.compress.harmony.pack200.Pack200Exception; 030import org.apache.commons.compress.harmony.unpack200.bytecode.Attribute; 031import org.apache.commons.compress.harmony.unpack200.bytecode.BCIRenumberedAttribute; 032import org.apache.commons.compress.harmony.unpack200.bytecode.ByteCode; 033import org.apache.commons.compress.harmony.unpack200.bytecode.CPClass; 034import org.apache.commons.compress.harmony.unpack200.bytecode.CodeAttribute; 035import org.apache.commons.compress.harmony.unpack200.bytecode.ExceptionTableEntry; 036import org.apache.commons.compress.harmony.unpack200.bytecode.NewAttribute; 037import org.apache.commons.compress.harmony.unpack200.bytecode.OperandManager; 038 039/** 040 * Bytecode bands. 041 */ 042public class BcBands extends BandSet { 043 044 /** The bytecodes for each method in each class as they come (i.e. in their packed format). */ 045 private byte[][][] methodByteCodePacked; 046 047 // The bands 048 // TODO: Haven't resolved references yet. Do we want to? 049 private int[] bcCaseCount; 050 private int[] bcCaseValue; 051 private int[] bcByte; 052 private int[] bcLocal; 053 private int[] bcShort; 054 private int[] bcLabel; 055 private int[] bcIntRef; 056 private int[] bcFloatRef; 057 private int[] bcLongRef; 058 private int[] bcDoubleRef; 059 private int[] bcStringRef; 060 private int[] bcClassRef; 061 private int[] bcFieldRef; 062 private int[] bcMethodRef; 063 private int[] bcIMethodRef; 064 private int[] bcThisField; 065 private int[] bcSuperField; 066 private int[] bcThisMethod; 067 private int[] bcSuperMethod; 068 private int[] bcInitRef; 069 private int[] bcEscRef; 070 private int[] bcEscRefSize; 071 private int[] bcEscSize; 072 private int[][] bcEscByte; 073 074 private List<Integer> wideByteCodes; 075 076 /** 077 * Constructs a new instance for the given segment. 078 * 079 * @param segment The segment. 080 */ 081 public BcBands(final Segment segment) { 082 super(segment); 083 } 084 085 private boolean endsWithLoad(final int codePacked) { 086 return codePacked >= 21 && codePacked <= 25; 087 } 088 089 private boolean endsWithStore(final int codePacked) { 090 return codePacked >= 54 && codePacked <= 58; 091 } 092 093 public int[] getBcByte() { 094 return bcByte; 095 } 096 097 public int[] getBcCaseCount() { 098 return bcCaseCount; 099 } 100 101 public int[] getBcCaseValue() { 102 return bcCaseValue; 103 } 104 105 public int[] getBcClassRef() { 106 return bcClassRef; 107 } 108 109 public int[] getBcDoubleRef() { 110 return bcDoubleRef; 111 } 112 113 public int[] getBcFieldRef() { 114 return bcFieldRef; 115 } 116 117 public int[] getBcFloatRef() { 118 return bcFloatRef; 119 } 120 121 public int[] getBcIMethodRef() { 122 return bcIMethodRef; 123 } 124 125 public int[] getBcInitRef() { 126 return bcInitRef; 127 } 128 129 public int[] getBcIntRef() { 130 return bcIntRef; 131 } 132 133 public int[] getBcLabel() { 134 return bcLabel; 135 } 136 137 public int[] getBcLocal() { 138 return bcLocal; 139 } 140 141 public int[] getBcLongRef() { 142 return bcLongRef; 143 } 144 145 public int[] getBcMethodRef() { 146 return bcMethodRef; 147 } 148 149 public int[] getBcShort() { 150 return bcShort; 151 } 152 153 public int[] getBcStringRef() { 154 return bcStringRef; 155 } 156 157 public int[] getBcSuperField() { 158 return bcSuperField; 159 } 160 161 public int[] getBcSuperMethod() { 162 return bcSuperMethod; 163 } 164 165 public int[] getBcThisField() { 166 return bcThisField; 167 } 168 169 public int[] getBcThisMethod() { 170 return bcThisMethod; 171 } 172 173 public byte[][][] getMethodByteCodePacked() { 174 return methodByteCodePacked; 175 } 176 177 /* 178 * (non-Javadoc) 179 * 180 * @see org.apache.commons.compress.harmony.unpack200.BandSet#unpack(java.io.InputStream) 181 */ 182 @Override 183 public void read(final InputStream in) throws IOException, Pack200Exception { 184 185 final AttributeLayoutMap attributeDefinitionMap = segment.getAttrDefinitionBands().getAttributeDefinitionMap(); 186 final int classCount = header.getClassCount(); 187 final long[][] methodFlags = segment.getClassBands().getMethodFlags(); 188 189 int bcCaseCountCount = 0; 190 int bcByteCount = 0; 191 int bcShortCount = 0; 192 int bcLocalCount = 0; 193 int bcLabelCount = 0; 194 int bcIntRefCount = 0; 195 int bcFloatRefCount = 0; 196 int bcLongRefCount = 0; 197 int bcDoubleRefCount = 0; 198 int bcStringRefCount = 0; 199 int bcClassRefCount = 0; 200 int bcFieldRefCount = 0; 201 int bcMethodRefCount = 0; 202 int bcIMethodRefCount = 0; 203 int bcThisFieldCount = 0; 204 int bcSuperFieldCount = 0; 205 int bcThisMethodCount = 0; 206 int bcSuperMethodCount = 0; 207 int bcInitRefCount = 0; 208 int bcEscCount = 0; 209 int bcEscRefCount = 0; 210 211 final AttributeLayout abstractModifier = attributeDefinitionMap.getAttributeLayout(AttributeLayout.ACC_ABSTRACT, AttributeLayout.CONTEXT_METHOD); 212 final AttributeLayout nativeModifier = attributeDefinitionMap.getAttributeLayout(AttributeLayout.ACC_NATIVE, AttributeLayout.CONTEXT_METHOD); 213 214 methodByteCodePacked = new byte[classCount][][]; 215 216 final List<Boolean> switchIsTableSwitch = new ArrayList<>(); 217 wideByteCodes = new ArrayList<>(); 218 for (int c = 0; c < classCount; c++) { 219 final int numberOfMethods = methodFlags[c].length; 220 methodByteCodePacked[c] = new byte[numberOfMethods][]; 221 for (int m = 0; m < numberOfMethods; m++) { 222 final long methodFlag = methodFlags[c][m]; 223 if (!abstractModifier.matches(methodFlag) && !nativeModifier.matches(methodFlag)) { 224 final ByteArrayOutputStream codeBytes = new ByteArrayOutputStream(); 225 byte code; 226 while ((code = (byte) (0xff & in.read())) != -1) { 227 codeBytes.write(code); 228 } 229 methodByteCodePacked[c][m] = codeBytes.toByteArray(); 230 final int[] codes = new int[methodByteCodePacked[c][m].length]; 231 for (int i = 0; i < codes.length; i++) { 232 codes[i] = methodByteCodePacked[c][m][i] & 0xff; 233 } 234 for (int i = 0; i < methodByteCodePacked[c][m].length; i++) { 235 final int codePacked = 0xff & methodByteCodePacked[c][m][i]; 236 switch (codePacked) { 237 case 16: // bipush 238 case 188: // newarray 239 bcByteCount++; 240 break; 241 case 17: // sipush 242 bcShortCount++; 243 break; 244 case 18: // (a)ldc 245 case 19: // aldc_w 246 bcStringRefCount++; 247 break; 248 case 234: // ildc 249 case 237: // ildc_w 250 bcIntRefCount++; 251 break; 252 case 235: // fldc 253 case 238: // fldc_w 254 bcFloatRefCount++; 255 break; 256 case 197: // multianewarray 257 bcByteCount++; 258 // falls-through 259 case 233: // cldc 260 case 236: // cldc_w 261 case 187: // new 262 case 189: // anewarray 263 case 192: // checkcast 264 case 193: // instanceof 265 bcClassRefCount++; 266 break; 267 case 20: // lldc2_w 268 bcLongRefCount++; 269 break; 270 case 239: // dldc2_w 271 bcDoubleRefCount++; 272 break; 273 case 169: // ret 274 bcLocalCount++; 275 break; 276 case 167: // goto 277 case 168: // jsr 278 case 200: // goto_w 279 case 201: // jsr_w 280 bcLabelCount++; 281 break; 282 case 170: // tableswitch 283 switchIsTableSwitch.add(Boolean.TRUE); 284 bcCaseCountCount++; 285 bcLabelCount++; 286 break; 287 case 171: // lookupswitch 288 switchIsTableSwitch.add(Boolean.FALSE); 289 bcCaseCountCount++; 290 bcLabelCount++; 291 break; 292 case 178: // getstatic 293 case 179: // putstatic 294 case 180: // getfield 295 case 181: // putfield 296 bcFieldRefCount++; 297 break; 298 case 182: // invokevirtual 299 case 183: // invokespecial 300 case 184: // invokestatic 301 bcMethodRefCount++; 302 break; 303 case 185: // invokeinterface 304 bcIMethodRefCount++; 305 break; 306 case 202: // getstatic_this 307 case 203: // putstatic_this 308 case 204: // getfield_this 309 case 205: // putfield_this 310 case 209: // aload_0_getstatic_this 311 case 210: // aload_0_putstatic_this 312 case 211: // aload_0_putfield_this 313 case 212: // aload_0_putfield_this 314 bcThisFieldCount++; 315 break; 316 case 206: // invokevirtual_this 317 case 207: // invokespecial_this 318 case 208: // invokestatic_this 319 case 213: // aload_0_invokevirtual_this 320 case 214: // aload_0_invokespecial_this 321 case 215: // aload_0_invokestatic_this 322 bcThisMethodCount++; 323 break; 324 case 216: // getstatic_super 325 case 217: // putstatic_super 326 case 218: // getfield_super 327 case 219: // putfield_super 328 case 223: // aload_0_getstatic_super 329 case 224: // aload_0_putstatic_super 330 case 225: // aload_0_getfield_super 331 case 226: // aload_0_putfield_super 332 bcSuperFieldCount++; 333 break; 334 case 220: // invokevirtual_super 335 case 221: // invokespecial_super 336 case 222: // invokestatic_super 337 case 227: // aload_0_invokevirtual_super 338 case 228: // aload_0_invokespecial_super 339 case 229: // aload_0_invokestatic_super 340 bcSuperMethodCount++; 341 break; 342 case 132: // iinc 343 bcLocalCount++; 344 bcByteCount++; 345 break; 346 case 196: // wide 347 final int nextInstruction = 0xff & methodByteCodePacked[c][m][i + 1]; 348 wideByteCodes.add(Integer.valueOf(nextInstruction)); 349 if (nextInstruction == 132) { // iinc 350 bcLocalCount++; 351 bcShortCount++; 352 } else if (endsWithLoad(nextInstruction) || endsWithStore(nextInstruction) || nextInstruction == 169) { 353 bcLocalCount++; 354 } else { 355 segment.log(Segment.LOG_LEVEL_VERBOSE, "Found unhandled " + ByteCode.getByteCode(nextInstruction)); 356 } 357 i++; 358 break; 359 case 230: // invokespecial_this_init 360 case 231: // invokespecial_super_init 361 case 232: // invokespecial_new_init 362 bcInitRefCount++; 363 break; 364 case 253: // ref_escape 365 bcEscRefCount++; 366 break; 367 case 254: // byte_escape 368 bcEscCount++; 369 break; 370 default: 371 if (endsWithLoad(codePacked) || endsWithStore(codePacked)) { 372 bcLocalCount++; 373 } else if (startsWithIf(codePacked)) { 374 bcLabelCount++; 375 } 376 } 377 } 378 } 379 } 380 } 381 // other bytecode bands 382 bcCaseCount = decodeBandInt("bc_case_count", in, Codec.UNSIGNED5, bcCaseCountCount); 383 int bcCaseValueCount = 0; 384 for (int i = 0; i < bcCaseCount.length; i++) { 385 final boolean isTableSwitch = switchIsTableSwitch.get(i).booleanValue(); 386 if (isTableSwitch) { 387 bcCaseValueCount += 1; 388 } else { 389 bcCaseValueCount += bcCaseCount[i]; 390 } 391 } 392 bcCaseValue = decodeBandInt("bc_case_value", in, Codec.DELTA5, bcCaseValueCount); 393 // Every case value needs a label. We weren't able to count these 394 // above, because we didn't know how many cases there were. 395 // Have to correct it now. 396 for (int index = 0; index < bcCaseCountCount; index++) { 397 bcLabelCount += bcCaseCount[index]; 398 } 399 bcByte = decodeBandInt("bc_byte", in, Codec.BYTE1, bcByteCount); 400 bcShort = decodeBandInt("bc_short", in, Codec.DELTA5, bcShortCount); 401 bcLocal = decodeBandInt("bc_local", in, Codec.UNSIGNED5, bcLocalCount); 402 bcLabel = decodeBandInt("bc_label", in, Codec.BRANCH5, bcLabelCount); 403 bcIntRef = decodeBandInt("bc_intref", in, Codec.DELTA5, bcIntRefCount); 404 bcFloatRef = decodeBandInt("bc_floatref", in, Codec.DELTA5, bcFloatRefCount); 405 bcLongRef = decodeBandInt("bc_longref", in, Codec.DELTA5, bcLongRefCount); 406 bcDoubleRef = decodeBandInt("bc_doubleref", in, Codec.DELTA5, bcDoubleRefCount); 407 bcStringRef = decodeBandInt("bc_stringref", in, Codec.DELTA5, bcStringRefCount); 408 bcClassRef = decodeBandInt("bc_classref", in, Codec.UNSIGNED5, bcClassRefCount); 409 bcFieldRef = decodeBandInt("bc_fieldref", in, Codec.DELTA5, bcFieldRefCount); 410 bcMethodRef = decodeBandInt("bc_methodref", in, Codec.UNSIGNED5, bcMethodRefCount); 411 bcIMethodRef = decodeBandInt("bc_imethodref", in, Codec.DELTA5, bcIMethodRefCount); 412 bcThisField = decodeBandInt("bc_thisfield", in, Codec.UNSIGNED5, bcThisFieldCount); 413 bcSuperField = decodeBandInt("bc_superfield", in, Codec.UNSIGNED5, bcSuperFieldCount); 414 bcThisMethod = decodeBandInt("bc_thismethod", in, Codec.UNSIGNED5, bcThisMethodCount); 415 bcSuperMethod = decodeBandInt("bc_supermethod", in, Codec.UNSIGNED5, bcSuperMethodCount); 416 bcInitRef = decodeBandInt("bc_initref", in, Codec.UNSIGNED5, bcInitRefCount); 417 bcEscRef = decodeBandInt("bc_escref", in, Codec.UNSIGNED5, bcEscRefCount); 418 bcEscRefSize = decodeBandInt("bc_escrefsize", in, Codec.UNSIGNED5, bcEscRefCount); 419 bcEscSize = decodeBandInt("bc_escsize", in, Codec.UNSIGNED5, bcEscCount); 420 bcEscByte = decodeBandInt("bc_escbyte", in, Codec.BYTE1, bcEscSize); 421 } 422 423 private boolean startsWithIf(final int codePacked) { 424 return codePacked >= 153 && codePacked <= 166 || codePacked == 198 || codePacked == 199; 425 } 426 427 @Override 428 public void unpack() throws Pack200Exception { 429 final int classCount = header.getClassCount(); 430 final long[][] methodFlags = segment.getClassBands().getMethodFlags(); 431 final int[] codeMaxNALocals = segment.getClassBands().getCodeMaxNALocals(); 432 final int[] codeMaxStack = segment.getClassBands().getCodeMaxStack(); 433 final ArrayList<Attribute>[][] methodAttributes = segment.getClassBands().getMethodAttributes(); 434 final String[][] methodDescr = segment.getClassBands().getMethodDescr(); 435 436 final AttributeLayoutMap attributeDefinitionMap = segment.getAttrDefinitionBands().getAttributeDefinitionMap(); 437 438 final AttributeLayout abstractModifier = attributeDefinitionMap.getAttributeLayout(AttributeLayout.ACC_ABSTRACT, AttributeLayout.CONTEXT_METHOD); 439 final AttributeLayout nativeModifier = attributeDefinitionMap.getAttributeLayout(AttributeLayout.ACC_NATIVE, AttributeLayout.CONTEXT_METHOD); 440 final AttributeLayout staticModifier = attributeDefinitionMap.getAttributeLayout(AttributeLayout.ACC_STATIC, AttributeLayout.CONTEXT_METHOD); 441 442 final int[] wideByteCodeArray = new int[wideByteCodes.size()]; 443 for (int index = 0; index < wideByteCodeArray.length; index++) { 444 wideByteCodeArray[index] = wideByteCodes.get(index).intValue(); 445 } 446 final OperandManager operandManager = new OperandManager(bcCaseCount, bcCaseValue, bcByte, bcShort, bcLocal, bcLabel, bcIntRef, bcFloatRef, bcLongRef, 447 bcDoubleRef, bcStringRef, bcClassRef, bcFieldRef, bcMethodRef, bcIMethodRef, bcThisField, bcSuperField, bcThisMethod, bcSuperMethod, bcInitRef, 448 wideByteCodeArray); 449 operandManager.setSegment(segment); 450 451 int i = 0; 452 final ArrayList<List<Attribute>> orderedCodeAttributes = segment.getClassBands().getOrderedCodeAttributes(); 453 int codeAttributeIndex = 0; 454 455 // Exception table fields 456 final int[] handlerCount = segment.getClassBands().getCodeHandlerCount(); 457 final int[][] handlerStartPCs = segment.getClassBands().getCodeHandlerStartP(); 458 final int[][] handlerEndPCs = segment.getClassBands().getCodeHandlerEndPO(); 459 final int[][] handlerCatchPCs = segment.getClassBands().getCodeHandlerCatchPO(); 460 final int[][] handlerClassTypes = segment.getClassBands().getCodeHandlerClassRCN(); 461 462 final boolean allCodeHasFlags = segment.getSegmentHeader().getOptions().hasAllCodeFlags(); 463 final boolean[] codeHasFlags = segment.getClassBands().getCodeHasAttributes(); 464 465 for (int c = 0; c < classCount; c++) { 466 final int numberOfMethods = methodFlags[c].length; 467 for (int m = 0; m < numberOfMethods; m++) { 468 final long methodFlag = methodFlags[c][m]; 469 if (!abstractModifier.matches(methodFlag) && !nativeModifier.matches(methodFlag)) { 470 final int maxStack = codeMaxStack[i]; 471 int maxLocal = codeMaxNALocals[i]; 472 if (!staticModifier.matches(methodFlag)) { 473 maxLocal++; // one for 'this' parameter 474 } 475 // I believe this has to take wide arguments into account 476 maxLocal += SegmentUtils.countInvokeInterfaceArgs(methodDescr[c][m]); 477 final String[] cpClass = segment.getCpBands().getCpClass(); 478 operandManager.setCurrentClass(cpClass[segment.getClassBands().getClassThisInts()[c]]); 479 operandManager.setSuperClass(cpClass[segment.getClassBands().getClassSuperInts()[c]]); 480 final List<ExceptionTableEntry> exceptionTable = new ArrayList<>(); 481 if (handlerCount != null) { 482 for (int j = 0; j < handlerCount[i]; j++) { 483 final int handlerClass = handlerClassTypes[i][j] - 1; 484 CPClass cpHandlerClass = null; 485 if (handlerClass != -1) { 486 // The handlerClass will be null if the 487 // catch is a finally (that is, the 488 // exception table catch_type should be 0 489 cpHandlerClass = segment.getCpBands().cpClassValue(handlerClass); 490 } 491 final ExceptionTableEntry entry = new ExceptionTableEntry(handlerStartPCs[i][j], handlerEndPCs[i][j], handlerCatchPCs[i][j], 492 cpHandlerClass); 493 exceptionTable.add(entry); 494 } 495 } 496 final CodeAttribute codeAttr = new CodeAttribute(maxStack, maxLocal, methodByteCodePacked[c][m], segment, operandManager, exceptionTable); 497 final List<Attribute> methodAttributesList = methodAttributes[c][m]; 498 // Make sure we add the code attribute in the right place 499 int indexForCodeAttr = 0; 500 for (final Attribute attribute : methodAttributesList) { 501 if (!(attribute instanceof NewAttribute) || ((NewAttribute) attribute).getLayoutIndex() >= 15) { 502 break; 503 } 504 indexForCodeAttr++; 505 } 506 methodAttributesList.add(indexForCodeAttr, codeAttr); 507 codeAttr.renumber(codeAttr.byteCodeOffsets); 508 final List<Attribute> currentAttributes; 509 if (allCodeHasFlags) { 510 currentAttributes = orderedCodeAttributes.get(i); 511 } else if (codeHasFlags[i]) { 512 currentAttributes = orderedCodeAttributes.get(codeAttributeIndex); 513 codeAttributeIndex++; 514 } else { 515 currentAttributes = Collections.EMPTY_LIST; 516 } 517 for (final Attribute currentAttribute : currentAttributes) { 518 codeAttr.addAttribute(currentAttribute); 519 // Fix up the line numbers if needed 520 if (currentAttribute.hasBCIRenumbering()) { 521 ((BCIRenumberedAttribute) currentAttribute).renumber(codeAttr.byteCodeOffsets); 522 } 523 } 524 i++; 525 } 526 } 527 } 528 } 529}