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