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