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