KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > proguard > classfile > editor > CodeAttributeComposer


1 /*
2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
3  * of Java bytecode.
4  *
5  * Copyright (c) 2002-2007 Eric Lafortune (eric@graphics.cornell.edu)
6  *
7  * This library is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by the Free
9  * Software Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * This library is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
15  * for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this library; if not, write to the Free Software Foundation,
19  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  */

21 package proguard.classfile.editor;
22
23 import proguard.classfile.*;
24 import proguard.classfile.attribute.*;
25 import proguard.classfile.attribute.preverification.visitor.*;
26 import proguard.classfile.attribute.preverification.*;
27 import proguard.classfile.attribute.visitor.*;
28 import proguard.classfile.instruction.*;
29 import proguard.classfile.instruction.visitor.InstructionVisitor;
30 import proguard.classfile.util.SimplifiedVisitor;
31
32 /**
33  * This AttributeVisitor accumulates instructions and exceptions, and then
34  * copies them into code attributes that it visits.
35  *
36  * @author Eric Lafortune
37  */

38 public class CodeAttributeComposer
39 extends SimplifiedVisitor
40 implements AttributeVisitor,
41              InstructionVisitor,
42              ExceptionInfoVisitor,
43              StackMapFrameVisitor,
44              VerificationTypeVisitor,
45              LineNumberInfoVisitor,
46              LocalVariableInfoVisitor,
47              LocalVariableTypeInfoVisitor
48 {
49     //*
50
private static final boolean DEBUG = false;
51     /*/
52     public static boolean DEBUG = true;
53     //*/

54
55
56     private static final int MAXIMUM_LEVELS = 32;
57
58
59     private int maximumCodeLength;
60     private int codeLength;
61     private int exceptionTableLength;
62     private int level = -1;
63
64     private byte[] code = new byte[ClassConstants.TYPICAL_CODE_LENGTH];
65     private int[] oldInstructionOffsets = new int[ClassConstants.TYPICAL_CODE_LENGTH];
66     private int[] codeFragmentOffsets = new int[MAXIMUM_LEVELS];
67     private int[] codeFragmentLengths = new int[MAXIMUM_LEVELS];
68     private int[][] instructionOffsetMap = new int[MAXIMUM_LEVELS][ClassConstants.TYPICAL_CODE_LENGTH];
69
70     private ExceptionInfo[] exceptionTable = new ExceptionInfo[ClassConstants.TYPICAL_EXCEPTION_TABLE_LENGTH];
71
72     private int expectedStackMapFrameOffset;
73
74     private StackSizeUpdater stackSizeUpdater = new StackSizeUpdater();
75     private VariableSizeUpdater variableSizeUpdater = new VariableSizeUpdater();
76
77
78     /**
79      * Starts a new code definition.
80      */

81     public void reset()
82     {
83         maximumCodeLength = 0;
84         codeLength = 0;
85         exceptionTableLength = 0;
86         level = -1;
87     }
88
89
90     /**
91      * Starts a new code fragment. Branch instructions that are added are
92      * assumed to be relative within such code fragments.
93      * @param maximumCodeFragmentLength the maximum length of the code that will
94      * be added as part of this fragment.
95      */

96     public void beginCodeFragment(int maximumCodeFragmentLength)
97     {
98         level++;
99
100         if (level >= MAXIMUM_LEVELS)
101         {
102             throw new IllegalArgumentException JavaDoc("Maximum number of code fragment levels exceeded ["+level+"]");
103         }
104
105         // Make sure there is sufficient space for adding the code fragment.
106
maximumCodeLength += maximumCodeFragmentLength;
107         if (code.length < maximumCodeLength)
108         {
109             byte[] newCode = new byte[maximumCodeLength];
110             System.arraycopy(code, 0, newCode, 0, codeLength);
111             code = newCode;
112
113             int[] newOldInstructionOffsets = new int[maximumCodeLength];
114             System.arraycopy(oldInstructionOffsets, 0, newOldInstructionOffsets, 0, codeLength);
115             oldInstructionOffsets = newOldInstructionOffsets;
116         }
117
118         // Try to reuse the previous array for this code fragment.
119
if (instructionOffsetMap[level].length <= maximumCodeFragmentLength)
120         {
121             instructionOffsetMap[level] = new int[maximumCodeFragmentLength + 1];
122         }
123
124         // Remember the location of the code fragment.
125
codeFragmentOffsets[level] = codeLength;
126         codeFragmentLengths[level] = maximumCodeFragmentLength;
127     }
128
129
130     /**
131      * Appends the given instruction with the given old offset.
132      * @param oldInstructionOffset the old offset of the instruction, to which
133      * branches and other references in the current
134      * code fragment are pointing.
135      * @param instruction the instruction to be appended.
136      */

137     public void appendInstruction(int oldInstructionOffset,
138                                   Instruction instruction)
139     {
140         if (DEBUG)
141         {
142             println("["+codeLength+"] <- ", instruction.toString(oldInstructionOffset));
143         }
144
145         // Remember the old offset of the appended instruction.
146
oldInstructionOffsets[codeLength] = oldInstructionOffset;
147
148         // Write the instruction.
149
instruction.write(code, codeLength);
150
151         // Fill out the new offset of the appended instruction.
152
instructionOffsetMap[level][oldInstructionOffset] = codeLength;
153
154         // Continue appending at the next instruction offset.
155
codeLength += instruction.length(codeLength);
156     }
157
158
159     /**
160      * Appends the given label with the given old offset.
161      * @param oldInstructionOffset the old offset of the label, to which
162      * branches and other references in the current
163      * code fragment are pointing.
164      */

165     public void appendLabel(int oldInstructionOffset)
166     {
167         if (DEBUG)
168         {
169             println("["+codeLength+"] <- ", "[" + oldInstructionOffset + "] (label)");
170         }
171
172         // Fill out the new offset of the appended instruction.
173
instructionOffsetMap[level][oldInstructionOffset] = codeLength;
174     }
175
176
177     /**
178      * Appends the given exception to the exception table.
179      * @param exceptionInfo the exception to be appended.
180      */

181     public void appendException(ExceptionInfo exceptionInfo)
182     {
183         if (DEBUG)
184         {
185             print(" ", "Exception ["+exceptionInfo.u2startPC+" -> "+exceptionInfo.u2endPC+": "+exceptionInfo.u2handlerPC+"]");
186         }
187
188         // Remap the exception right away.
189
visitExceptionInfo(null, null, null, exceptionInfo);
190
191         if (DEBUG)
192         {
193             System.out.println(" -> ["+exceptionInfo.u2startPC+" -> "+exceptionInfo.u2endPC+": "+exceptionInfo.u2handlerPC+"]");
194         }
195
196         // Don't add the exception if its instruction range is empty.
197
if (exceptionInfo.u2startPC == exceptionInfo.u2endPC)
198         {
199             if (DEBUG)
200             {
201                 println(" ", " (not added because of empty instruction range)");
202             }
203
204             return;
205         }
206
207         // Make sure there is sufficient space in the exception table.
208
if (exceptionTable.length <= exceptionTableLength)
209         {
210             ExceptionInfo[] newExceptionTable = new ExceptionInfo[exceptionTableLength+1];
211             System.arraycopy(exceptionTable, 0, newExceptionTable, 0, exceptionTableLength);
212             exceptionTable = newExceptionTable;
213         }
214
215         // Add the exception.
216
exceptionTable[exceptionTableLength++] = exceptionInfo;
217     }
218
219
220     /**
221      * Wraps up the current code fragment, continuing with the previous one on
222      * the stack.
223      */

224     public void endCodeFragment()
225     {
226         if (level < 0)
227         {
228             throw new IllegalArgumentException JavaDoc("Code fragment not begun ["+level+"]");
229         }
230
231         // Remap the instructions of the code fragment.
232
int instructionOffset = codeFragmentOffsets[level];
233         while (instructionOffset < codeLength)
234         {
235             // Get the next instruction.
236
Instruction instruction = InstructionFactory.create(code, instructionOffset);
237
238             // Does this instruction still have to be remapped?
239
if (oldInstructionOffsets[instructionOffset] >= 0)
240             {
241                 // Adapt the instruction for its new offset.
242
instruction.accept(null, null, null, instructionOffset, this);
243
244                 // Write the instruction back.
245
instruction.write(code, instructionOffset);
246
247                 // Don't remap this instruction again.
248
oldInstructionOffsets[instructionOffset] = -1;
249             }
250
251             // Continue remapping at the next instruction offset.
252
instructionOffset += instruction.length(instructionOffset);
253         }
254
255         // Correct the estimated maximum code length, now that we know the
256
// actual length of this code fragment.
257
maximumCodeLength += codeLength - codeFragmentOffsets[level] -
258                              codeFragmentLengths[level];
259
260         level--;
261     }
262
263
264     // Implementations for AttributeVisitor.
265

266     public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
267
268
269     public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
270     {
271         if (DEBUG)
272         {
273             System.out.println("CodeAttributeComposer: putting results in ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"]");
274         }
275
276         if (level != -1)
277         {
278             throw new IllegalArgumentException JavaDoc("Code fragment not ended ["+level+"]");
279         }
280
281         level++;
282
283         // Make sure the code attribute has sufficient space for the composed
284
// code.
285
if (codeAttribute.u4codeLength < codeLength)
286         {
287             codeAttribute.code = new byte[codeLength];
288         }
289
290         // Copy the composed code over into the code attribute.
291
codeAttribute.u4codeLength = codeLength;
292         System.arraycopy(code, 0, codeAttribute.code, 0, codeLength);
293
294         // Remove exceptions with empty code blocks (done before).
295
//exceptionTableLength =
296
// removeEmptyExceptions(exceptionTable, exceptionTableLength);
297

298         // Make sure the exception table has sufficient space for the composed
299
// exceptions.
300
if (codeAttribute.exceptionTable.length < exceptionTableLength)
301         {
302             codeAttribute.exceptionTable = new ExceptionInfo[exceptionTableLength];
303         }
304
305         // Copy the exception table.
306
codeAttribute.u2exceptionTableLength = exceptionTableLength;
307         System.arraycopy(exceptionTable, 0, codeAttribute.exceptionTable, 0, exceptionTableLength);
308
309         // Update the maximum stack size and local variable frame size.
310
stackSizeUpdater.visitCodeAttribute(clazz, method, codeAttribute);
311         variableSizeUpdater.visitCodeAttribute(clazz, method, codeAttribute);
312
313         // Remap the line number table and the local variable table.
314
codeAttribute.attributesAccept(clazz, method, this);
315
316         // Remap the exception table.
317
//codeAttribute.exceptionsAccept(clazz, method, this);
318

319         // Remove exceptions with empty code blocks (done before).
320
//codeAttribute.u2exceptionTableLength =
321
// removeEmptyExceptions(codeAttribute.exceptionTable,
322
// codeAttribute.u2exceptionTableLength);
323

324         level--;
325     }
326
327
328     public void visitStackMapAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapAttribute stackMapAttribute)
329     {
330         // Remap all stack map entries.
331
expectedStackMapFrameOffset = -1;
332         stackMapAttribute.stackMapFramesAccept(clazz, method, codeAttribute, this);
333     }
334
335
336     public void visitStackMapTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapTableAttribute stackMapTableAttribute)
337     {
338         // Remap all stack map table entries.
339
expectedStackMapFrameOffset = 0;
340         stackMapTableAttribute.stackMapFramesAccept(clazz, method, codeAttribute, this);
341     }
342
343
344     public void visitLineNumberTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberTableAttribute lineNumberTableAttribute)
345     {
346         // Remap all line number table entries.
347
lineNumberTableAttribute.lineNumbersAccept(clazz, method, codeAttribute, this);
348
349         // Remove line numbers with empty code blocks.
350
lineNumberTableAttribute.u2lineNumberTableLength =
351            removeEmptyLineNumbers(lineNumberTableAttribute.lineNumberTable,
352                                   lineNumberTableAttribute.u2lineNumberTableLength,
353                                   codeAttribute.u4codeLength);
354     }
355
356
357     public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute)
358     {
359         // Remap all local variable table entries.
360
localVariableTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this);
361
362         // Remove local variables with empty code blocks.
363
localVariableTableAttribute.u2localVariableTableLength =
364             removeEmptyLocalVariables(localVariableTableAttribute.localVariableTable,
365                                       localVariableTableAttribute.u2localVariableTableLength,
366                                       codeAttribute.u2maxLocals);
367     }
368
369
370     public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute)
371     {
372         // Remap all local variable table entries.
373
localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this);
374
375         // Remove local variables with empty code blocks.
376
localVariableTypeTableAttribute.u2localVariableTypeTableLength =
377             removeEmptyLocalVariableTypes(localVariableTypeTableAttribute.localVariableTypeTable,
378                                           localVariableTypeTableAttribute.u2localVariableTypeTableLength,
379                                           codeAttribute.u2maxLocals);
380     }
381
382
383     // Implementations for InstructionVisitor.
384

385     public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {}
386
387
388     public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction)
389     {
390         // Adjust the branch offset.
391
branchInstruction.branchOffset = remapBranchOffset(offset,
392                                                            branchInstruction.branchOffset);
393     }
394
395
396     public void visitAnySwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SwitchInstruction switchInstruction)
397     {
398         // Adjust the default jump offset.
399
switchInstruction.defaultOffset = remapBranchOffset(offset,
400                                                             switchInstruction.defaultOffset);
401
402         // Adjust the jump offsets.
403
remapJumpOffsets(offset,
404                          switchInstruction.jumpOffsets);
405     }
406
407
408     // Implementations for ExceptionInfoVisitor.
409

410     public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo)
411     {
412         // Remap the code offsets. Note that the instruction offset map also has
413
// an entry for the first offset after the code, for u2endPC.
414
exceptionInfo.u2startPC = remapInstructionOffset(exceptionInfo.u2startPC);
415         exceptionInfo.u2endPC = remapInstructionOffset(exceptionInfo.u2endPC);
416         exceptionInfo.u2handlerPC = remapInstructionOffset(exceptionInfo.u2handlerPC);
417     }
418
419
420     // Implementations for StackMapFrameVisitor.
421

422     public void visitAnyStackMapFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, StackMapFrame stackMapFrame)
423     {
424         // Remap the stack map frame offset.
425
int stackMapFrameOffset = remapInstructionOffset(offset);
426
427         int offsetDelta = stackMapFrameOffset;
428
429         // Compute the offset delta if the frame is part of a stack map frame
430
// table (for JDK 6.0) instead of a stack map (for Java Micro Edition).
431
if (expectedStackMapFrameOffset >= 0)
432         {
433             offsetDelta -= expectedStackMapFrameOffset;
434
435             expectedStackMapFrameOffset = stackMapFrameOffset + 1;
436         }
437
438         stackMapFrame.u2offsetDelta = offsetDelta;
439     }
440
441
442     public void visitSameOneFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SameOneFrame sameOneFrame)
443     {
444         // Remap the stack map frame offset.
445
visitAnyStackMapFrame(clazz, method, codeAttribute, offset, sameOneFrame);
446
447         // Remap the verification type offset.
448
sameOneFrame.stackItemAccept(clazz, method, codeAttribute, offset, this);
449     }
450
451
452     public void visitMoreZeroFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, MoreZeroFrame moreZeroFrame)
453     {
454         // Remap the stack map frame offset.
455
visitAnyStackMapFrame(clazz, method, codeAttribute, offset, moreZeroFrame);
456
457         // Remap the verification type offsets.
458
moreZeroFrame.additionalVariablesAccept(clazz, method, codeAttribute, offset, this);
459     }
460
461
462     public void visitFullFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, FullFrame fullFrame)
463     {
464         // Remap the stack map frame offset.
465
visitAnyStackMapFrame(clazz, method, codeAttribute, offset, fullFrame);
466
467         // Remap the verification type offsets.
468
fullFrame.variablesAccept(clazz, method, codeAttribute, offset, this);
469         fullFrame.stackAccept(clazz, method, codeAttribute, offset, this);
470     }
471
472
473     // Implementations for VerificationTypeVisitor.
474

475     public void visitAnyVerificationType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VerificationType verificationType) {}
476
477
478     public void visitUninitializedType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, UninitializedType uninitializedType)
479     {
480         // Remap the offset of the 'new' instruction.
481
uninitializedType.u2newInstructionOffset = remapInstructionOffset(uninitializedType.u2newInstructionOffset);
482     }
483
484
485     // Implementations for LineNumberInfoVisitor.
486

487     public void visitLineNumberInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberInfo lineNumberInfo)
488     {
489         // Remap the code offset.
490
lineNumberInfo.u2startPC = remapInstructionOffset(lineNumberInfo.u2startPC);
491     }
492
493
494     // Implementations for LocalVariableInfoVisitor.
495

496     public void visitLocalVariableInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfo localVariableInfo)
497     {
498         // Remap the code offset and length.
499
// TODO: The local variable frame might not be strictly preserved.
500
int startPC = remapInstructionOffset(localVariableInfo.u2startPC);
501         int endPC = remapInstructionOffset(localVariableInfo.u2startPC + localVariableInfo.u2length);
502
503         localVariableInfo.u2startPC = startPC;
504         localVariableInfo.u2length = endPC - startPC;
505     }
506
507     // Implementations for LocalVariableTypeInfoVisitor.
508

509     public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeInfo localVariableTypeInfo)
510     {
511         // Remap the code offset and length.
512
// TODO: The local variable frame might not be strictly preserved.
513
int startPC = remapInstructionOffset(localVariableTypeInfo.u2startPC);
514         int endPC = remapInstructionOffset(localVariableTypeInfo.u2startPC + localVariableTypeInfo.u2length);
515
516         localVariableTypeInfo.u2length = startPC;
517         localVariableTypeInfo.u2startPC = endPC - startPC;
518     }
519
520
521     // Small utility methods.
522

523     /**
524      * Adjusts the given jump offsets for the instruction at the given offset.
525      */

526     private void remapJumpOffsets(int offset, int[] jumpOffsets)
527     {
528         for (int index = 0; index < jumpOffsets.length; index++)
529         {
530             jumpOffsets[index] = remapBranchOffset(offset, jumpOffsets[index]);
531         }
532     }
533
534
535     /**
536      * Computes the new branch offset for the instruction at the given new offset
537      * with the given old branch offset.
538      */

539     private int remapBranchOffset(int newInstructionOffset, int branchOffset)
540     {
541         if (newInstructionOffset < 0 ||
542             newInstructionOffset > codeLength)
543         {
544             throw new IllegalArgumentException JavaDoc("Invalid instruction offset ["+newInstructionOffset +"] in code with length ["+codeLength+"]");
545         }
546
547         int oldInstructionOffset = oldInstructionOffsets[newInstructionOffset];
548
549         return remapInstructionOffset(oldInstructionOffset + branchOffset) -
550                remapInstructionOffset(oldInstructionOffset);
551     }
552
553
554     /**
555      * Computes the new instruction offset for the instruction at the given old
556      * offset.
557      */

558     private int remapInstructionOffset(int oldInstructionOffset)
559     {
560         if (oldInstructionOffset < 0 ||
561             oldInstructionOffset > codeFragmentLengths[level])
562         {
563             throw new IllegalArgumentException JavaDoc("Invalid instruction offset ["+oldInstructionOffset +"] in code fragment with length ["+codeFragmentLengths[level]+"]");
564         }
565
566         return instructionOffsetMap[level][oldInstructionOffset];
567     }
568
569
570     /**
571      * Returns the given list of exceptions, without the ones that have empty
572      * code blocks.
573      */

574     private int removeEmptyExceptions(ExceptionInfo[] exceptionInfos,
575                                       int exceptionInfoCount)
576     {
577         // Overwrite all empty exceptions.
578
int newIndex = 0;
579         for (int index = 0; index < exceptionInfoCount; index++)
580         {
581             ExceptionInfo exceptionInfo = exceptionInfos[index];
582             if (exceptionInfo.u2startPC < exceptionInfo.u2endPC)
583             {
584                 exceptionInfos[newIndex++] = exceptionInfo;
585             }
586         }
587
588         // Clear the unused array entries.
589
for (int index = newIndex; index < exceptionInfoCount; index++)
590         {
591             exceptionInfos[index] = null;
592         }
593
594         return newIndex;
595     }
596
597
598     /**
599      * Returns the given list of line numbers, without the ones that have empty
600      * code blocks or that exceed the code size.
601      */

602     private int removeEmptyLineNumbers(LineNumberInfo[] lineNumberInfos,
603                                        int lineNumberInfoCount,
604                                        int codeLength)
605     {
606         // Overwrite all empty line number entries.
607
int newIndex = 0;
608         for (int index = 0; index < lineNumberInfoCount; index++)
609         {
610             LineNumberInfo lineNumberInfo = lineNumberInfos[index];
611             int startPC = lineNumberInfo.u2startPC;
612             if (startPC < codeLength &&
613                 (index == 0 || startPC > lineNumberInfos[index-1].u2startPC))
614             {
615                 lineNumberInfos[newIndex++] = lineNumberInfo;
616             }
617         }
618
619         // Clear the unused array entries.
620
for (int index = newIndex; index < lineNumberInfoCount; index++)
621         {
622             lineNumberInfos[index] = null;
623         }
624
625         return newIndex;
626     }
627
628
629     /**
630      * Returns the given list of local variables, without the ones that have empty
631      * code blocks or that exceed the actual number of local variables.
632      */

633     private int removeEmptyLocalVariables(LocalVariableInfo[] localVariableInfos,
634                                           int localVariableInfoCount,
635                                           int maxLocals)
636     {
637         // Overwrite all empty local variable entries.
638
int newIndex = 0;
639         for (int index = 0; index < localVariableInfoCount; index++)
640         {
641             LocalVariableInfo localVariableInfo = localVariableInfos[index];
642             if (localVariableInfo.u2length > 0 &&
643                 localVariableInfo.u2index < maxLocals)
644             {
645                 localVariableInfos[newIndex++] = localVariableInfo;
646             }
647         }
648
649         // Clear the unused array entries.
650
for (int index = newIndex; index < localVariableInfoCount; index++)
651         {
652             localVariableInfos[index] = null;
653         }
654
655         return newIndex;
656     }
657
658
659     /**
660      * Returns the given list of local variable types, without the ones that
661      * have empty code blocks or that exceed the actual number of local variables.
662      */

663     private int removeEmptyLocalVariableTypes(LocalVariableTypeInfo[] localVariableTypeInfos,
664                                               int localVariableTypeInfoCount,
665                                               int maxLocals)
666     {
667         // Overwrite all empty local variable type entries.
668
int newIndex = 0;
669         for (int index = 0; index < localVariableTypeInfoCount; index++)
670         {
671             LocalVariableTypeInfo localVariableTypeInfo = localVariableTypeInfos[index];
672             if (localVariableTypeInfo.u2length > 0 &&
673                 localVariableTypeInfo.u2index < maxLocals)
674             {
675                 localVariableTypeInfos[newIndex++] = localVariableTypeInfo;
676             }
677         }
678
679         // Clear the unused array entries.
680
for (int index = newIndex; index < localVariableTypeInfoCount; index++)
681         {
682             localVariableTypeInfos[index] = null;
683         }
684
685         return newIndex;
686     }
687
688
689     private void println(String JavaDoc string1, String JavaDoc string2)
690     {
691         print(string1, string2);
692
693         System.out.println();
694     }
695
696     private void print(String JavaDoc string1, String JavaDoc string2)
697     {
698         System.out.print(string1);
699
700         for (int index = 0; index < level; index++)
701         {
702             System.out.print(" ");
703         }
704
705         System.out.print(string2);
706     }
707
708
709     public static void main(String JavaDoc[] args)
710     {
711         CodeAttributeComposer composer = new CodeAttributeComposer();
712
713         composer.beginCodeFragment(10);
714         composer.appendInstruction(0, new SimpleInstruction(InstructionConstants.OP_ICONST_0));
715         composer.appendInstruction(1, new VariableInstruction(InstructionConstants.OP_ISTORE, 0));
716         composer.appendInstruction(2, new BranchInstruction(InstructionConstants.OP_GOTO, 1));
717
718         composer.beginCodeFragment(10);
719         composer.appendInstruction(0, new VariableInstruction(InstructionConstants.OP_IINC, 0, 1));
720         composer.appendInstruction(1, new VariableInstruction(InstructionConstants.OP_ILOAD, 0));
721         composer.appendInstruction(2, new SimpleInstruction(InstructionConstants.OP_ICONST_5));
722         composer.appendInstruction(3, new BranchInstruction(InstructionConstants.OP_IFICMPLT, -3));
723         composer.endCodeFragment();
724
725         composer.appendInstruction(3, new SimpleInstruction(InstructionConstants.OP_RETURN));
726         composer.endCodeFragment();
727     }
728 }
729
Popular Tags