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, 209 AttributeLayout.CONTEXT_METHOD); 210 final AttributeLayout nativeModifier = attributeDefinitionMap.getAttributeLayout(AttributeLayout.ACC_NATIVE, 211 AttributeLayout.CONTEXT_METHOD); 212 213 methodByteCodePacked = new byte[classCount][][]; 214 int bcParsed = 0; 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 bcParsed += methodByteCodePacked[c][m].length; 231 final int[] codes = new int[methodByteCodePacked[c][m].length]; 232 for (int i = 0; i < codes.length; i++) { 233 codes[i] = methodByteCodePacked[c][m][i] & 0xff; 234 } 235 for (int i = 0; i < methodByteCodePacked[c][m].length; i++) { 236 final int codePacked = 0xff & methodByteCodePacked[c][m][i]; 237 switch (codePacked) { 238 case 16: // bipush 239 case 188: // newarray 240 bcByteCount++; 241 break; 242 case 17: // sipush 243 bcShortCount++; 244 break; 245 case 18: // (a)ldc 246 case 19: // aldc_w 247 bcStringRefCount++; 248 break; 249 case 234: // ildc 250 case 237: // ildc_w 251 bcIntRefCount++; 252 break; 253 case 235: // fldc 254 case 238: // fldc_w 255 bcFloatRefCount++; 256 break; 257 case 197: // multianewarray 258 bcByteCount++; 259 // fallthrough intended 260 case 233: // cldc 261 case 236: // cldc_w 262 case 187: // new 263 case 189: // anewarray 264 case 192: // checkcast 265 case 193: // instanceof 266 bcClassRefCount++; 267 break; 268 case 20: // lldc2_w 269 bcLongRefCount++; 270 break; 271 case 239: // dldc2_w 272 bcDoubleRefCount++; 273 break; 274 case 169: // ret 275 bcLocalCount++; 276 break; 277 case 167: // goto 278 case 168: // jsr 279 case 200: // goto_w 280 case 201: // jsr_w 281 bcLabelCount++; 282 break; 283 case 170: // tableswitch 284 switchIsTableSwitch.add(Boolean.TRUE); 285 bcCaseCountCount++; 286 bcLabelCount++; 287 break; 288 case 171: // lookupswitch 289 switchIsTableSwitch.add(Boolean.FALSE); 290 bcCaseCountCount++; 291 bcLabelCount++; 292 break; 293 case 178: // getstatic 294 case 179: // putstatic 295 case 180: // getfield 296 case 181: // putfield 297 bcFieldRefCount++; 298 break; 299 case 182: // invokevirtual 300 case 183: // invokespecial 301 case 184: // invokestatic 302 bcMethodRefCount++; 303 break; 304 case 185: // invokeinterface 305 bcIMethodRefCount++; 306 break; 307 case 202: // getstatic_this 308 case 203: // putstatic_this 309 case 204: // getfield_this 310 case 205: // putfield_this 311 case 209: // aload_0_getstatic_this 312 case 210: // aload_0_putstatic_this 313 case 211: // aload_0_putfield_this 314 case 212: // aload_0_putfield_this 315 bcThisFieldCount++; 316 break; 317 case 206: // invokevirtual_this 318 case 207: // invokespecial_this 319 case 208: // invokestatic_this 320 case 213: // aload_0_invokevirtual_this 321 case 214: // aload_0_invokespecial_this 322 case 215: // aload_0_invokestatic_this 323 bcThisMethodCount++; 324 break; 325 case 216: // getstatic_super 326 case 217: // putstatic_super 327 case 218: // getfield_super 328 case 219: // putfield_super 329 case 223: // aload_0_getstatic_super 330 case 224: // aload_0_putstatic_super 331 case 225: // aload_0_getfield_super 332 case 226: // aload_0_putfield_super 333 bcSuperFieldCount++; 334 break; 335 case 220: // invokevirtual_super 336 case 221: // invokespecial_super 337 case 222: // invokestatic_super 338 case 227: // aload_0_invokevirtual_super 339 case 228: // aload_0_invokespecial_super 340 case 229: // aload_0_invokestatic_super 341 bcSuperMethodCount++; 342 break; 343 case 132: // iinc 344 bcLocalCount++; 345 bcByteCount++; 346 break; 347 case 196: // wide 348 final int nextInstruction = 0xff & methodByteCodePacked[c][m][i + 1]; 349 wideByteCodes.add(Integer.valueOf(nextInstruction)); 350 if (nextInstruction == 132) { // iinc 351 bcLocalCount++; 352 bcShortCount++; 353 } else if (endsWithLoad(nextInstruction) || endsWithStore(nextInstruction) 354 || nextInstruction == 169) { 355 bcLocalCount++; 356 } else { 357 segment.log(Segment.LOG_LEVEL_VERBOSE, 358 "Found unhandled " + ByteCode.getByteCode(nextInstruction)); 359 } 360 i++; 361 break; 362 case 230: // invokespecial_this_init 363 case 231: // invokespecial_super_init 364 case 232: // invokespecial_new_init 365 bcInitRefCount++; 366 break; 367 case 253: // ref_escape 368 bcEscRefCount++; 369 break; 370 case 254: // byte_escape 371 bcEscCount++; 372 break; 373 default: 374 if (endsWithLoad(codePacked) || endsWithStore(codePacked)) { 375 bcLocalCount++; 376 } else if (startsWithIf(codePacked)) { 377 bcLabelCount++; 378 } 379 } 380 } 381 } 382 } 383 } 384 // other bytecode bands 385 bcCaseCount = decodeBandInt("bc_case_count", in, Codec.UNSIGNED5, bcCaseCountCount); 386 int bcCaseValueCount = 0; 387 for (int i = 0; i < bcCaseCount.length; i++) { 388 final boolean isTableSwitch = switchIsTableSwitch.get(i).booleanValue(); 389 if (isTableSwitch) { 390 bcCaseValueCount += 1; 391 } else { 392 bcCaseValueCount += bcCaseCount[i]; 393 } 394 } 395 bcCaseValue = decodeBandInt("bc_case_value", in, Codec.DELTA5, bcCaseValueCount); 396 // Every case value needs a label. We weren't able to count these 397 // above, because we didn't know how many cases there were. 398 // Have to correct it now. 399 for (int index = 0; index < bcCaseCountCount; index++) { 400 bcLabelCount += bcCaseCount[index]; 401 } 402 bcByte = decodeBandInt("bc_byte", in, Codec.BYTE1, bcByteCount); 403 bcShort = decodeBandInt("bc_short", in, Codec.DELTA5, bcShortCount); 404 bcLocal = decodeBandInt("bc_local", in, Codec.UNSIGNED5, bcLocalCount); 405 bcLabel = decodeBandInt("bc_label", in, Codec.BRANCH5, bcLabelCount); 406 bcIntRef = decodeBandInt("bc_intref", in, Codec.DELTA5, bcIntRefCount); 407 bcFloatRef = decodeBandInt("bc_floatref", in, Codec.DELTA5, bcFloatRefCount); 408 bcLongRef = decodeBandInt("bc_longref", in, Codec.DELTA5, bcLongRefCount); 409 bcDoubleRef = decodeBandInt("bc_doubleref", in, Codec.DELTA5, bcDoubleRefCount); 410 bcStringRef = decodeBandInt("bc_stringref", in, Codec.DELTA5, bcStringRefCount); 411 bcClassRef = decodeBandInt("bc_classref", in, Codec.UNSIGNED5, bcClassRefCount); 412 bcFieldRef = decodeBandInt("bc_fieldref", in, Codec.DELTA5, bcFieldRefCount); 413 bcMethodRef = decodeBandInt("bc_methodref", in, Codec.UNSIGNED5, bcMethodRefCount); 414 bcIMethodRef = decodeBandInt("bc_imethodref", in, Codec.DELTA5, bcIMethodRefCount); 415 bcThisField = decodeBandInt("bc_thisfield", in, Codec.UNSIGNED5, bcThisFieldCount); 416 bcSuperField = decodeBandInt("bc_superfield", in, Codec.UNSIGNED5, bcSuperFieldCount); 417 bcThisMethod = decodeBandInt("bc_thismethod", in, Codec.UNSIGNED5, bcThisMethodCount); 418 bcSuperMethod = decodeBandInt("bc_supermethod", in, Codec.UNSIGNED5, bcSuperMethodCount); 419 bcInitRef = decodeBandInt("bc_initref", in, Codec.UNSIGNED5, bcInitRefCount); 420 bcEscRef = decodeBandInt("bc_escref", in, Codec.UNSIGNED5, bcEscRefCount); 421 bcEscRefSize = decodeBandInt("bc_escrefsize", in, Codec.UNSIGNED5, bcEscRefCount); 422 bcEscSize = decodeBandInt("bc_escsize", in, Codec.UNSIGNED5, bcEscCount); 423 bcEscByte = decodeBandInt("bc_escbyte", in, Codec.BYTE1, bcEscSize); 424 } 425 426 private boolean startsWithIf(final int codePacked) { 427 return codePacked >= 153 && codePacked <= 166 || codePacked == 198 || codePacked == 199; 428 } 429 430 @Override 431 public void unpack() throws Pack200Exception { 432 final int classCount = header.getClassCount(); 433 final long[][] methodFlags = segment.getClassBands().getMethodFlags(); 434 final int[] codeMaxNALocals = segment.getClassBands().getCodeMaxNALocals(); 435 final int[] codeMaxStack = segment.getClassBands().getCodeMaxStack(); 436 final ArrayList<Attribute>[][] methodAttributes = segment.getClassBands().getMethodAttributes(); 437 final String[][] methodDescr = segment.getClassBands().getMethodDescr(); 438 439 final AttributeLayoutMap attributeDefinitionMap = segment.getAttrDefinitionBands().getAttributeDefinitionMap(); 440 441 final AttributeLayout abstractModifier = attributeDefinitionMap.getAttributeLayout(AttributeLayout.ACC_ABSTRACT, 442 AttributeLayout.CONTEXT_METHOD); 443 final AttributeLayout nativeModifier = attributeDefinitionMap.getAttributeLayout(AttributeLayout.ACC_NATIVE, 444 AttributeLayout.CONTEXT_METHOD); 445 final AttributeLayout staticModifier = attributeDefinitionMap.getAttributeLayout(AttributeLayout.ACC_STATIC, 446 AttributeLayout.CONTEXT_METHOD); 447 448 final int[] wideByteCodeArray = new int[wideByteCodes.size()]; 449 for (int index = 0; index < wideByteCodeArray.length; index++) { 450 wideByteCodeArray[index] = wideByteCodes.get(index).intValue(); 451 } 452 final OperandManager operandManager = new OperandManager(bcCaseCount, bcCaseValue, bcByte, bcShort, bcLocal, 453 bcLabel, bcIntRef, bcFloatRef, bcLongRef, bcDoubleRef, bcStringRef, bcClassRef, bcFieldRef, bcMethodRef, 454 bcIMethodRef, bcThisField, bcSuperField, bcThisMethod, bcSuperMethod, bcInitRef, wideByteCodeArray); 455 operandManager.setSegment(segment); 456 457 int i = 0; 458 final ArrayList<List<Attribute>> orderedCodeAttributes = segment.getClassBands().getOrderedCodeAttributes(); 459 int codeAttributeIndex = 0; 460 461 // Exception table fields 462 final int[] handlerCount = segment.getClassBands().getCodeHandlerCount(); 463 final int[][] handlerStartPCs = segment.getClassBands().getCodeHandlerStartP(); 464 final int[][] handlerEndPCs = segment.getClassBands().getCodeHandlerEndPO(); 465 final int[][] handlerCatchPCs = segment.getClassBands().getCodeHandlerCatchPO(); 466 final int[][] handlerClassTypes = segment.getClassBands().getCodeHandlerClassRCN(); 467 468 final boolean allCodeHasFlags = segment.getSegmentHeader().getOptions().hasAllCodeFlags(); 469 final boolean[] codeHasFlags = segment.getClassBands().getCodeHasAttributes(); 470 471 for (int c = 0; c < classCount; c++) { 472 final int numberOfMethods = methodFlags[c].length; 473 for (int m = 0; m < numberOfMethods; m++) { 474 final long methodFlag = methodFlags[c][m]; 475 if (!abstractModifier.matches(methodFlag) && !nativeModifier.matches(methodFlag)) { 476 final int maxStack = codeMaxStack[i]; 477 int maxLocal = codeMaxNALocals[i]; 478 if (!staticModifier.matches(methodFlag)) { 479 maxLocal++; // one for 'this' parameter 480 } 481 // I believe this has to take wide arguments into account 482 maxLocal += SegmentUtils.countInvokeInterfaceArgs(methodDescr[c][m]); 483 final String[] cpClass = segment.getCpBands().getCpClass(); 484 operandManager.setCurrentClass(cpClass[segment.getClassBands().getClassThisInts()[c]]); 485 operandManager.setSuperClass(cpClass[segment.getClassBands().getClassSuperInts()[c]]); 486 final List<ExceptionTableEntry> exceptionTable = new ArrayList<>(); 487 if (handlerCount != null) { 488 for (int j = 0; j < handlerCount[i]; j++) { 489 final int handlerClass = handlerClassTypes[i][j] - 1; 490 CPClass cpHandlerClass = null; 491 if (handlerClass != -1) { 492 // The handlerClass will be null if the 493 // catch is a finally (that is, the 494 // exception table catch_type should be 0 495 cpHandlerClass = segment.getCpBands().cpClassValue(handlerClass); 496 } 497 final ExceptionTableEntry entry = new ExceptionTableEntry(handlerStartPCs[i][j], 498 handlerEndPCs[i][j], handlerCatchPCs[i][j], cpHandlerClass); 499 exceptionTable.add(entry); 500 } 501 } 502 final CodeAttribute codeAttr = new CodeAttribute(maxStack, maxLocal, methodByteCodePacked[c][m], 503 segment, operandManager, exceptionTable); 504 final List<Attribute> methodAttributesList = methodAttributes[c][m]; 505 // Make sure we add the code attribute in the right place 506 int indexForCodeAttr = 0; 507 for (final Attribute attribute : methodAttributesList) { 508 if (!(attribute instanceof NewAttribute) 509 || ((NewAttribute) attribute).getLayoutIndex() >= 15) { 510 break; 511 } 512 indexForCodeAttr++; 513 } 514 methodAttributesList.add(indexForCodeAttr, codeAttr); 515 codeAttr.renumber(codeAttr.byteCodeOffsets); 516 List<Attribute> currentAttributes; 517 if (allCodeHasFlags) { 518 currentAttributes = orderedCodeAttributes.get(i); 519 } else if (codeHasFlags[i]) { 520 currentAttributes = orderedCodeAttributes.get(codeAttributeIndex); 521 codeAttributeIndex++; 522 } else { 523 currentAttributes = Collections.EMPTY_LIST; 524 } 525 for (final Attribute currentAttribute : currentAttributes) { 526 codeAttr.addAttribute(currentAttribute); 527 // Fix up the line numbers if needed 528 if (currentAttribute.hasBCIRenumbering()) { 529 ((BCIRenumberedAttribute) currentAttribute).renumber(codeAttr.byteCodeOffsets); 530 } 531 } 532 i++; 533 } 534 } 535 } 536 } 537}