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