KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > cojen > classfile > CodeDisassembler


1 /*
2  * Copyright 2004 Brian S O'Neill
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.cojen.classfile;
18
19 import java.util.ArrayList JavaDoc;
20 import java.util.HashMap JavaDoc;
21 import java.util.List JavaDoc;
22 import java.util.Map JavaDoc;
23 import java.util.Vector JavaDoc;
24 import org.cojen.classfile.attribute.CodeAttr;
25 import org.cojen.classfile.constant.ConstantClassInfo;
26 import org.cojen.classfile.constant.ConstantDoubleInfo;
27 import org.cojen.classfile.constant.ConstantFieldInfo;
28 import org.cojen.classfile.constant.ConstantFloatInfo;
29 import org.cojen.classfile.constant.ConstantIntegerInfo;
30 import org.cojen.classfile.constant.ConstantInterfaceMethodInfo;
31 import org.cojen.classfile.constant.ConstantLongInfo;
32 import org.cojen.classfile.constant.ConstantMethodInfo;
33 import org.cojen.classfile.constant.ConstantNameAndTypeInfo;
34 import org.cojen.classfile.constant.ConstantStringInfo;
35
36 /**
37  * Disassembles a method into a CodeAssembler, which acts as a visitor.
38  *
39  * @author Brian S O'Neill
40  */

41 public class CodeDisassembler {
42     private final MethodInfo mMethod;
43     private final String JavaDoc mEnclosingClassName;
44     private final String JavaDoc mSuperClassName;
45     private final CodeAttr mCode;
46     private final ConstantPool mCp;
47     private final byte[] mByteCodes;
48     private final ExceptionHandler[] mExceptionHandlers;
49
50     // Current CodeAssembler in use for disassembly.
51
private CodeAssembler mAssembler;
52
53     // List of all the LocalVariable objects in use.
54
private Vector JavaDoc mLocals;
55
56     // True if the method being decompiled still has a "this" reference.
57
private boolean mHasThis;
58
59     private Location mReturnLocation;
60
61     // Maps Integer address keys to itself, but to Label objects after first
62
// needed.
63
private Map JavaDoc mLabels;
64
65     // Maps Integer catch locations to Lists of ExceptionHandler objects.
66
private Map JavaDoc mCatchLocations;
67
68     // Current address being decompiled.
69
private int mAddress;
70
71     /**
72      * @throws IllegalArgumentException if method has no code
73      */

74     public CodeDisassembler(MethodInfo method) throws IllegalArgumentException JavaDoc {
75         mMethod = method;
76         mEnclosingClassName = method.getClassFile().getClassName();
77         mSuperClassName = method.getClassFile().getSuperClassName();
78         if ((mCode = method.getCodeAttr()) == null) {
79             throw new IllegalArgumentException JavaDoc("Method defines no code");
80         }
81         mCp = mCode.getConstantPool();
82         CodeBuffer buffer = mCode.getCodeBuffer();
83         mByteCodes = buffer.getByteCodes();
84         mExceptionHandlers = buffer.getExceptionHandlers();
85     }
86
87     /**
88      * Disassemble the MethodInfo into the given assembler.
89      *
90      * @see CodeAssemblerPrinter
91      */

92     public void disassemble(CodeAssembler assembler) {
93         disassemble(assembler, null, null);
94     }
95
96     /**
97      * Disassemble the MethodInfo into the given assembler.
98      *
99      * @param params if not null, override the local variables which hold parameter values
100      * @param returnLocation if not null, disassemble will branch to this location upon seeing
101      * a return, leaving any arguments on the stack
102      * @see CodeAssemblerPrinter
103      */

104     public synchronized void disassemble(CodeAssembler assembler,
105                                          LocalVariable[] params, Location returnLocation) {
106         mAssembler = assembler;
107         mLocals = new Vector JavaDoc();
108         if (mHasThis = !mMethod.getModifiers().isStatic()) {
109             // Reserve a slot for "this" parameter.
110
mLocals.add(null);
111         }
112
113         gatherLabels();
114
115         // Gather the local variables of the parameters.
116
{
117             TypeDesc[] paramTypes = mMethod.getMethodDescriptor().getParameterTypes();
118             
119             if (params == null) {
120                 params = new LocalVariable[assembler.getParameterCount()];
121                 for (int i=params.length; --i>=0; ) {
122                     params[i] = assembler.getParameter(i);
123                 }
124             }
125             if (paramTypes.length != params.length) {
126                 throw new IllegalArgumentException JavaDoc
127                     ("Method parameter count doesn't match given parameter count: "
128                      + paramTypes.length + " != " + params.length);
129             }
130         
131             for (int i=0; i<paramTypes.length; i++) {
132                 LocalVariable paramVar = params[i];
133                 if (!compatibleType(paramTypes[i], paramVar.getType())) {
134                     throw new IllegalArgumentException JavaDoc
135                         ("Method parameter type is not compatible with given type: "
136                          + paramTypes[i] + " != " + paramVar.getType());
137                 }
138                 mLocals.add(paramVar);
139                 if (paramVar.getType().isDoubleWord()) {
140                     // Reserve slot for least significant word.
141
mLocals.add(null);
142                 }
143             }
144         }
145
146         mReturnLocation = returnLocation;
147
148         Location currentLoc = new Location() {
149             public int getLocation() {
150                 return mAddress;
151             }
152
153             public int compareTo(Object JavaDoc obj) {
154                 if (this == obj) {
155                     return 0;
156                 }
157                 Location other = (Location)obj;
158                 
159                 int loca = getLocation();
160                 int locb = other.getLocation();
161                 
162                 if (loca < locb) {
163                     return -1;
164                 } else if (loca > locb) {
165                     return 1;
166                 } else {
167                     return 0;
168                 }
169             }
170         };
171
172         int currentLine = -1;
173
174         for (mAddress = 0; mAddress < mByteCodes.length; mAddress++) {
175             int nextLine = mCode.getLineNumber(currentLoc);
176             if (nextLine != currentLine) {
177                 if ((currentLine = nextLine) >= 0) {
178                     mAssembler.mapLineNumber(currentLine);
179                 }
180             }
181
182             // Check if a label needs to be created and/or located.
183
locateLabel();
184
185             byte opcode = mByteCodes[mAddress];
186
187             int index;
188             Location loc;
189             TypeDesc type;
190             ConstantInfo ci;
191
192             switch (opcode) {
193
194             default:
195                 error(opcode, "Unknown opcode: " + (opcode & 0xff));
196                 break;
197
198                 // Opcodes with no operands...
199

200             case Opcode.NOP:
201                 assembler.nop();
202                 break;
203             case Opcode.BREAKPOINT:
204                 assembler.breakpoint();
205                 break;
206
207             case Opcode.ACONST_NULL:
208                 assembler.loadNull();
209                 break;
210             case Opcode.ICONST_M1:
211                 assembler.loadConstant(-1);
212                 break;
213             case Opcode.ICONST_0:
214                 assembler.loadConstant(0);
215                 break;
216             case Opcode.ICONST_1:
217                 assembler.loadConstant(1);
218                 break;
219             case Opcode.ICONST_2:
220                 assembler.loadConstant(2);
221                 break;
222             case Opcode.ICONST_3:
223                 assembler.loadConstant(3);
224                 break;
225             case Opcode.ICONST_4:
226                 assembler.loadConstant(4);
227                 break;
228             case Opcode.ICONST_5:
229                 assembler.loadConstant(5);
230                 break;
231             case Opcode.LCONST_0:
232                 assembler.loadConstant(0L);
233                 break;
234             case Opcode.LCONST_1:
235                 assembler.loadConstant(1L);
236                 break;
237             case Opcode.FCONST_0:
238                 assembler.loadConstant(0f);
239                 break;
240             case Opcode.FCONST_1:
241                 assembler.loadConstant(1f);
242                 break;
243             case Opcode.FCONST_2:
244                 assembler.loadConstant(2f);
245                 break;
246             case Opcode.DCONST_0:
247                 assembler.loadConstant(0d);
248                 break;
249             case Opcode.DCONST_1:
250                 assembler.loadConstant(1d);
251                 break;
252
253             case Opcode.POP:
254                 assembler.pop();
255                 break;
256             case Opcode.POP2:
257                 assembler.pop2();
258                 break;
259             case Opcode.DUP:
260                 assembler.dup();
261                 break;
262             case Opcode.DUP_X1:
263                 assembler.dupX1();
264                 break;
265             case Opcode.DUP_X2:
266                 assembler.dupX2();
267                 break;
268             case Opcode.DUP2:
269                 assembler.dup2();
270                 break;
271             case Opcode.DUP2_X1:
272                 assembler.dup2X2();
273                 break;
274             case Opcode.DUP2_X2:
275                 assembler.dup2X2();
276                 break;
277             case Opcode.SWAP:
278                 assembler.swap();
279                 break;
280
281             case Opcode.IADD: case Opcode.LADD:
282             case Opcode.FADD: case Opcode.DADD:
283             case Opcode.ISUB: case Opcode.LSUB:
284             case Opcode.FSUB: case Opcode.DSUB:
285             case Opcode.IMUL: case Opcode.LMUL:
286             case Opcode.FMUL: case Opcode.DMUL:
287             case Opcode.IDIV: case Opcode.LDIV:
288             case Opcode.FDIV: case Opcode.DDIV:
289             case Opcode.IREM: case Opcode.LREM:
290             case Opcode.FREM: case Opcode.DREM:
291             case Opcode.INEG: case Opcode.LNEG:
292             case Opcode.FNEG: case Opcode.DNEG:
293             case Opcode.ISHL: case Opcode.LSHL:
294             case Opcode.ISHR: case Opcode.LSHR:
295             case Opcode.IUSHR: case Opcode.LUSHR:
296             case Opcode.IAND: case Opcode.LAND:
297             case Opcode.IOR: case Opcode.LOR:
298             case Opcode.IXOR: case Opcode.LXOR:
299             case Opcode.FCMPL: case Opcode.DCMPL:
300             case Opcode.FCMPG: case Opcode.DCMPG:
301             case Opcode.LCMP:
302                 assembler.math(opcode);
303                 break;
304
305             case Opcode.I2L:
306                 assembler.convert(TypeDesc.INT, TypeDesc.LONG);
307                 break;
308             case Opcode.I2F:
309                 assembler.convert(TypeDesc.INT, TypeDesc.FLOAT);
310                 break;
311             case Opcode.I2D:
312                 assembler.convert(TypeDesc.INT, TypeDesc.DOUBLE);
313                 break;
314             case Opcode.L2I:
315                 assembler.convert(TypeDesc.LONG, TypeDesc.INT);
316                 break;
317             case Opcode.L2F:
318                 assembler.convert(TypeDesc.LONG, TypeDesc.FLOAT);
319                 break;
320             case Opcode.L2D:
321                 assembler.convert(TypeDesc.LONG, TypeDesc.DOUBLE);
322                 break;
323             case Opcode.F2I:
324                 assembler.convert(TypeDesc.FLOAT, TypeDesc.INT);
325                 break;
326             case Opcode.F2L:
327                 assembler.convert(TypeDesc.FLOAT, TypeDesc.LONG);
328                 break;
329             case Opcode.F2D:
330                 assembler.convert(TypeDesc.FLOAT, TypeDesc.DOUBLE);
331                 break;
332             case Opcode.D2I:
333                 assembler.convert(TypeDesc.DOUBLE, TypeDesc.INT);
334                 break;
335             case Opcode.D2L:
336                 assembler.convert(TypeDesc.DOUBLE, TypeDesc.LONG);
337                 break;
338             case Opcode.D2F:
339                 assembler.convert(TypeDesc.DOUBLE, TypeDesc.FLOAT);
340                 break;
341             case Opcode.I2B:
342                 assembler.convert(TypeDesc.INT, TypeDesc.BYTE);
343                 break;
344             case Opcode.I2C:
345                 assembler.convert(TypeDesc.INT, TypeDesc.CHAR);
346                 break;
347             case Opcode.I2S:
348                 assembler.convert(TypeDesc.INT, TypeDesc.SHORT);
349                 break;
350
351             case Opcode.IRETURN:
352             case Opcode.LRETURN:
353             case Opcode.FRETURN:
354             case Opcode.DRETURN:
355             case Opcode.ARETURN:
356             case Opcode.RETURN:
357                 if (mReturnLocation != null) {
358                     assembler.branch(mReturnLocation);
359                 } else {
360                     switch (opcode) {
361                     case Opcode.IRETURN:
362                         assembler.returnValue(TypeDesc.INT);
363                         break;
364                     case Opcode.LRETURN:
365                         assembler.returnValue(TypeDesc.LONG);
366                         break;
367                     case Opcode.FRETURN:
368                         assembler.returnValue(TypeDesc.FLOAT);
369                         break;
370                     case Opcode.DRETURN:
371                         assembler.returnValue(TypeDesc.DOUBLE);
372                         break;
373                     case Opcode.ARETURN:
374                         assembler.returnValue(TypeDesc.OBJECT);
375                         break;
376                     case Opcode.RETURN:
377                         assembler.returnVoid();
378                         break;
379                     }
380                 }
381                 break;
382
383             case Opcode.IALOAD:
384                 assembler.loadFromArray(TypeDesc.INT);
385                 break;
386             case Opcode.LALOAD:
387                 assembler.loadFromArray(TypeDesc.LONG);
388                 break;
389             case Opcode.FALOAD:
390                 assembler.loadFromArray(TypeDesc.FLOAT);
391                 break;
392             case Opcode.DALOAD:
393                 assembler.loadFromArray(TypeDesc.DOUBLE);
394                 break;
395             case Opcode.AALOAD:
396                 assembler.loadFromArray(TypeDesc.OBJECT);
397                 break;
398             case Opcode.BALOAD:
399                 assembler.loadFromArray(TypeDesc.BYTE);
400                 break;
401             case Opcode.CALOAD:
402                 assembler.loadFromArray(TypeDesc.CHAR);
403                 break;
404             case Opcode.SALOAD:
405                 assembler.loadFromArray(TypeDesc.SHORT);
406                 break;
407
408             case Opcode.IASTORE:
409                 assembler.storeToArray(TypeDesc.INT);
410                 break;
411             case Opcode.LASTORE:
412                 assembler.storeToArray(TypeDesc.LONG);
413                 break;
414             case Opcode.FASTORE:
415                 assembler.storeToArray(TypeDesc.FLOAT);
416                 break;
417             case Opcode.DASTORE:
418                 assembler.storeToArray(TypeDesc.DOUBLE);
419                 break;
420             case Opcode.AASTORE:
421                 assembler.storeToArray(TypeDesc.OBJECT);
422                 break;
423             case Opcode.BASTORE:
424                 assembler.storeToArray(TypeDesc.BYTE);
425                 break;
426             case Opcode.CASTORE:
427                 assembler.storeToArray(TypeDesc.CHAR);
428                 break;
429             case Opcode.SASTORE:
430                 assembler.storeToArray(TypeDesc.SHORT);
431                 break;
432
433             case Opcode.ARRAYLENGTH:
434                 assembler.arrayLength();
435                 break;
436             case Opcode.ATHROW:
437                 assembler.throwObject();
438                 break;
439             case Opcode.MONITORENTER:
440                 assembler.monitorEnter();
441                 break;
442             case Opcode.MONITOREXIT:
443                 assembler.monitorExit();
444                 break;
445
446                 // End opcodes with no operands.
447

448                 // Opcodes that load a constant from the constant pool...
449

450             case Opcode.LDC:
451             case Opcode.LDC_W:
452             case Opcode.LDC2_W:
453                 switch (opcode) {
454                 case Opcode.LDC:
455                     index = readUnsignedByte();
456                     break;
457                 case Opcode.LDC_W:
458                 case Opcode.LDC2_W:
459                     index = readUnsignedShort();
460                     break;
461                 default:
462                     index = 0;
463                     break;
464                 }
465
466                 try {
467                     ci = mCp.getConstant(index);
468                 } catch (IndexOutOfBoundsException JavaDoc e) {
469                     error(opcode, "Undefined constant at index: " + index);
470                     break;
471                 }
472
473                 if (ci instanceof ConstantStringInfo) {
474                     assembler.loadConstant(((ConstantStringInfo)ci).getValue());
475                 } else if (ci instanceof ConstantIntegerInfo) {
476                     assembler.loadConstant(((ConstantIntegerInfo)ci).getValue());
477                 } else if (ci instanceof ConstantLongInfo) {
478                     assembler.loadConstant(((ConstantLongInfo)ci).getValue());
479                 } else if (ci instanceof ConstantFloatInfo) {
480                     assembler.loadConstant(((ConstantFloatInfo)ci).getValue());
481                 } else if (ci instanceof ConstantDoubleInfo) {
482                     assembler.loadConstant(((ConstantDoubleInfo)ci).getValue());
483                 } else if (ci instanceof ConstantClassInfo) {
484                     assembler.loadConstant(((ConstantClassInfo)ci).getType());
485                 } else {
486                     error(opcode, "Invalid constant type for load: " + ci);
487                 }
488                 break;
489
490             case Opcode.NEW:
491                 index = readUnsignedShort();
492                 try {
493                     ci = mCp.getConstant(index);
494                 } catch (IndexOutOfBoundsException JavaDoc e) {
495                     error(opcode, "Undefined constant at index: " + index);
496                     break;
497                 }
498
499                 if (ci instanceof ConstantClassInfo) {
500                     assembler.newObject(((ConstantClassInfo)ci).getType());
501                 } else {
502                     error(opcode, "Invalid constant type for new: " + ci);
503                 }
504                 break;
505             case Opcode.ANEWARRAY:
506                 index = readUnsignedShort();
507                 try {
508                     ci = mCp.getConstant(index);
509                 } catch (IndexOutOfBoundsException JavaDoc e) {
510                     error(opcode, "Undefined constant at index: " + index);
511                     break;
512                 }
513
514                 if (ci instanceof ConstantClassInfo) {
515                     type = ((ConstantClassInfo)ci).getType().toArrayType();
516                     assembler.newObject(type);
517                 } else {
518                     error(opcode, "Invalid constant type for new: " + ci);
519                 }
520                 break;
521             case Opcode.MULTIANEWARRAY:
522                 index = readUnsignedShort();
523                 try {
524                     ci = mCp.getConstant(index);
525                 } catch (IndexOutOfBoundsException JavaDoc e) {
526                     error(opcode, "Undefined constant at index: " + index);
527                     break;
528                 }
529
530                 int dims = readUnsignedByte();
531                 if (ci instanceof ConstantClassInfo) {
532                     type = ((ConstantClassInfo)ci).getType();
533                     assembler.newObject(type, dims);
534                 } else {
535                     error(opcode, "Invalid constant type for new: " + ci);
536                 }
537                 break;
538
539             case Opcode.CHECKCAST:
540                 index = readUnsignedShort();
541                 try {
542                     ci = mCp.getConstant(index);
543                 } catch (IndexOutOfBoundsException JavaDoc e) {
544                     error(opcode, "Undefined constant at index: " + index);
545                     break;
546                 }
547
548                 if (ci instanceof ConstantClassInfo) {
549                     assembler.checkCast(((ConstantClassInfo)ci).getType());
550                 } else {
551                     error(opcode, "Invalid constant type for checkcast: " + ci);
552                 }
553                 break;
554             case Opcode.INSTANCEOF:
555                 index = readUnsignedShort();
556                 try {
557                     ci = mCp.getConstant(index);
558                 } catch (IndexOutOfBoundsException JavaDoc e) {
559                     error(opcode, "Undefined constant at index: " + index);
560                     break;
561                 }
562
563                 if (ci instanceof ConstantClassInfo) {
564                     assembler.instanceOf(((ConstantClassInfo)ci).getType());
565                 } else {
566                     error(opcode, "Invalid constant type for instanceof: " + ci);
567                 }
568                 break;
569
570             case Opcode.GETSTATIC:
571             case Opcode.PUTSTATIC:
572             case Opcode.GETFIELD:
573             case Opcode.PUTFIELD:
574                 index = readUnsignedShort();
575                 try {
576                     ci = mCp.getConstant(index);
577                 } catch (IndexOutOfBoundsException JavaDoc e) {
578                     error(opcode, "Undefined constant at index: " + index);
579                     break;
580                 }
581
582                 if (!(ci instanceof ConstantFieldInfo)) {
583                     error(opcode, "Invalid constant type for field access: " + ci);
584                     break;
585                 }
586
587                 ConstantFieldInfo field = (ConstantFieldInfo)ci;
588                 String JavaDoc className = field.getParentClass().getType().getFullName();
589                 if (mEnclosingClassName.equals(className)) {
590                     className = null;
591                 }
592                 String JavaDoc fieldName = field.getNameAndType().getName();
593                 Descriptor desc = field.getNameAndType().getType();
594                 if (!(desc instanceof TypeDesc)) {
595                     error(opcode, "Invalid descriptor for field access: " + desc);
596                     break;
597                 } else {
598                     type = (TypeDesc)desc;
599                 }
600
601                 // Implementation note: Although it may seem convenient if the
602
// CodeAssembler had methods that accepted ConstantFieldInfo
603
// objects as parameters, it would cause problems because
604
// ConstantPools are not portable between ClassFiles.
605

606                 switch (opcode) {
607                 case Opcode.GETSTATIC:
608                     if (className == null) {
609                         assembler.loadStaticField(fieldName, type);
610                     } else {
611                         assembler.loadStaticField(className, fieldName, type);
612                     }
613                     break;
614                 case Opcode.PUTSTATIC:
615                     if (className == null) {
616                         assembler.storeStaticField(fieldName, type);
617                     } else {
618                         assembler.storeStaticField(className, fieldName, type);
619                     }
620                     break;
621                 case Opcode.GETFIELD:
622                     if (className == null) {
623                         assembler.loadField(fieldName, type);
624                     } else {
625                         assembler.loadField(className, fieldName, type);
626                     }
627                     break;
628                 case Opcode.PUTFIELD:
629                     if (className == null) {
630                         assembler.storeField(fieldName, type);
631                     } else {
632                         assembler.storeField(className, fieldName, type);
633                     }
634                     break;
635                 }
636                 break;
637
638             case Opcode.INVOKEVIRTUAL:
639             case Opcode.INVOKESPECIAL:
640             case Opcode.INVOKESTATIC:
641             case Opcode.INVOKEINTERFACE:
642                 index = readUnsignedShort();
643                 try {
644                     ci = mCp.getConstant(index);
645                 } catch (IndexOutOfBoundsException JavaDoc e) {
646                     error(opcode, "Undefined constant at index: " + index);
647                     break;
648                 }
649
650                 ConstantNameAndTypeInfo nameAndType;
651
652                 if (opcode == Opcode.INVOKEINTERFACE) {
653                     // Read and ignore nargs and padding byte.
654
readShort();
655                     if (!(ci instanceof ConstantInterfaceMethodInfo)) {
656                         error(opcode, "Invalid constant type for method invocation: " + ci);
657                         break;
658                     }
659                     ConstantInterfaceMethodInfo method = (ConstantInterfaceMethodInfo)ci;
660                     className = method.getParentClass().getType().getFullName();
661                     nameAndType = method.getNameAndType();
662                 } else {
663                     if (!(ci instanceof ConstantMethodInfo)) {
664                         error(opcode, "Invalid constant type for method invocation: " + ci);
665                         break;
666                     }
667                     ConstantMethodInfo method = (ConstantMethodInfo)ci;
668                     className = method.getParentClass().getType().getFullName();
669                     if (mEnclosingClassName.equals(className)) {
670                         className = null;
671                     }
672                     nameAndType = method.getNameAndType();
673                 }
674
675                 String JavaDoc methodName = nameAndType.getName();
676                 desc = nameAndType.getType();
677                 if (!(desc instanceof MethodDesc)) {
678                     error(opcode, "Invalid descriptor for method invocation: " + desc);
679                     break;
680                 }
681                 TypeDesc ret = ((MethodDesc)desc).getReturnType();
682                 if (ret == TypeDesc.VOID) {
683                     ret = null;
684                 }
685                 TypeDesc[] paramTypes = ((MethodDesc)desc).getParameterTypes();
686                 if (paramTypes.length == 0) {
687                     paramTypes = null;
688                 }
689
690                 switch (opcode) {
691                 case Opcode.INVOKEVIRTUAL:
692                     if (className == null) {
693                         assembler.invokeVirtual(methodName, ret, paramTypes);
694                     } else {
695                         assembler.invokeVirtual(className, methodName, ret, paramTypes);
696                     }
697                     break;
698                 case Opcode.INVOKESPECIAL:
699                     if ("<init>".equals(methodName)) {
700                         if (className == null) {
701                             assembler.invokeConstructor(paramTypes);
702                         } else {
703                             if ("<init>".equals(mMethod.getName())
704                                 && className.equals(mSuperClassName)) {
705                                 assembler.invokeSuperConstructor(paramTypes);
706                             } else {
707                                 assembler.invokeConstructor(className, paramTypes);
708                             }
709                         }
710                     } else {
711                         if (className == null) {
712                             assembler.invokePrivate(methodName, ret, paramTypes);
713                         } else {
714                             assembler.invokeSuper(className, methodName, ret, paramTypes);
715                         }
716                     }
717                     break;
718                 case Opcode.INVOKESTATIC:
719                     if (className == null) {
720                         assembler.invokeStatic(methodName, ret, paramTypes);
721                     } else {
722                         assembler.invokeStatic(className, methodName, ret, paramTypes);
723                     }
724                     break;
725                 case Opcode.INVOKEINTERFACE:
726                     assembler.invokeInterface(className, methodName, ret, paramTypes);
727                     break;
728                 }
729                 break;
730
731                 // End opcodes that load a constant from the constant pool.
732

733                 // Opcodes that load or store local variables...
734

735             case Opcode.ILOAD: case Opcode.ISTORE:
736             case Opcode.LLOAD: case Opcode.LSTORE:
737             case Opcode.FLOAD: case Opcode.FSTORE:
738             case Opcode.DLOAD: case Opcode.DSTORE:
739             case Opcode.ALOAD: case Opcode.ASTORE:
740             case Opcode.ILOAD_0: case Opcode.ISTORE_0:
741             case Opcode.ILOAD_1: case Opcode.ISTORE_1:
742             case Opcode.ILOAD_2: case Opcode.ISTORE_2:
743             case Opcode.ILOAD_3: case Opcode.ISTORE_3:
744             case Opcode.LLOAD_0: case Opcode.LSTORE_0:
745             case Opcode.LLOAD_1: case Opcode.LSTORE_1:
746             case Opcode.LLOAD_2: case Opcode.LSTORE_2:
747             case Opcode.LLOAD_3: case Opcode.LSTORE_3:
748             case Opcode.FLOAD_0: case Opcode.FSTORE_0:
749             case Opcode.FLOAD_1: case Opcode.FSTORE_1:
750             case Opcode.FLOAD_2: case Opcode.FSTORE_2:
751             case Opcode.FLOAD_3: case Opcode.FSTORE_3:
752             case Opcode.DLOAD_0: case Opcode.DSTORE_0:
753             case Opcode.DLOAD_1: case Opcode.DSTORE_1:
754             case Opcode.DLOAD_2: case Opcode.DSTORE_2:
755             case Opcode.DLOAD_3: case Opcode.DSTORE_3:
756             case Opcode.ALOAD_0: case Opcode.ASTORE_0:
757             case Opcode.ALOAD_1: case Opcode.ASTORE_1:
758             case Opcode.ALOAD_2: case Opcode.ASTORE_2:
759             case Opcode.ALOAD_3: case Opcode.ASTORE_3:
760                 switch (opcode) {
761                 case Opcode.ILOAD: case Opcode.ISTORE:
762                     index = readUnsignedByte();
763                     type = TypeDesc.INT;
764                     break;
765                 case Opcode.LLOAD: case Opcode.LSTORE:
766                     index = readUnsignedByte();
767                     type = TypeDesc.LONG;
768                     break;
769                 case Opcode.FLOAD: case Opcode.FSTORE:
770                     index = readUnsignedByte();
771                     type = TypeDesc.FLOAT;
772                     break;
773                 case Opcode.DLOAD: case Opcode.DSTORE:
774                     index = readUnsignedByte();
775                     type = TypeDesc.DOUBLE;
776                     break;
777                 case Opcode.ALOAD: case Opcode.ASTORE:
778                     index = readUnsignedByte();
779                     type = TypeDesc.OBJECT;
780                     break;
781                 case Opcode.ILOAD_0: case Opcode.ISTORE_0:
782                     index = 0;
783                     type = TypeDesc.INT;
784                     break;
785                 case Opcode.ILOAD_1: case Opcode.ISTORE_1:
786                     index = 1;
787                     type = TypeDesc.INT;
788                     break;
789                 case Opcode.ILOAD_2: case Opcode.ISTORE_2:
790                     index = 2;
791                     type = TypeDesc.INT;
792                     break;
793                 case Opcode.ILOAD_3: case Opcode.ISTORE_3:
794                     index = 3;
795                     type = TypeDesc.INT;
796                     break;
797                 case Opcode.LLOAD_0: case Opcode.LSTORE_0:
798                     index = 0;
799                     type = TypeDesc.LONG;
800                     break;
801                 case Opcode.LLOAD_1: case Opcode.LSTORE_1:
802                     index = 1;
803                     type = TypeDesc.LONG;
804                     break;
805                 case Opcode.LLOAD_2: case Opcode.LSTORE_2:
806                     index = 2;
807                     type = TypeDesc.LONG;
808                     break;
809                 case Opcode.LLOAD_3: case Opcode.LSTORE_3:
810                     index = 3;
811                     type = TypeDesc.LONG;
812                     break;
813                 case Opcode.FLOAD_0: case Opcode.FSTORE_0:
814                     index = 0;
815                     type = TypeDesc.FLOAT;
816                     break;
817                 case Opcode.FLOAD_1: case Opcode.FSTORE_1:
818                     index = 1;
819                     type = TypeDesc.FLOAT;
820                     break;
821                 case Opcode.FLOAD_2: case Opcode.FSTORE_2:
822                     index = 2;
823                     type = TypeDesc.FLOAT;
824                     break;
825                 case Opcode.FLOAD_3: case Opcode.FSTORE_3:
826                     index = 3;
827                     type = TypeDesc.FLOAT;
828                     break;
829                 case Opcode.DLOAD_0: case Opcode.DSTORE_0:
830                     index = 0;
831                     type = TypeDesc.DOUBLE;
832                     break;
833                 case Opcode.DLOAD_1: case Opcode.DSTORE_1:
834                     index = 1;
835                     type = TypeDesc.DOUBLE;
836                     break;
837                 case Opcode.DLOAD_2: case Opcode.DSTORE_2:
838                     index = 2;
839                     type = TypeDesc.DOUBLE;
840                     break;
841                 case Opcode.DLOAD_3: case Opcode.DSTORE_3:
842                     index = 3;
843                     type = TypeDesc.DOUBLE;
844                     break;
845                 case Opcode.ALOAD_0: case Opcode.ASTORE_0:
846                     index = 0;
847                     type = TypeDesc.OBJECT;
848                     break;
849                 case Opcode.ALOAD_1: case Opcode.ASTORE_1:
850                     index = 1;
851                     type = TypeDesc.OBJECT;
852                     break;
853                 case Opcode.ALOAD_2: case Opcode.ASTORE_2:
854                     index = 2;
855                     type = TypeDesc.OBJECT;
856                     break;
857                 case Opcode.ALOAD_3: case Opcode.ASTORE_3:
858                     index = 3;
859                     type = TypeDesc.OBJECT;
860                     break;
861                 default:
862                     index = 0;
863                     type = null;
864                     break;
865                 }
866
867                 switch (opcode) {
868                 case Opcode.ILOAD:
869                 case Opcode.LLOAD:
870                 case Opcode.FLOAD:
871                 case Opcode.DLOAD:
872                 case Opcode.ALOAD:
873                 case Opcode.ILOAD_0:
874                 case Opcode.ILOAD_1:
875                 case Opcode.ILOAD_2:
876                 case Opcode.ILOAD_3:
877                 case Opcode.LLOAD_0:
878                 case Opcode.LLOAD_1:
879                 case Opcode.LLOAD_2:
880                 case Opcode.LLOAD_3:
881                 case Opcode.FLOAD_0:
882                 case Opcode.FLOAD_1:
883                 case Opcode.FLOAD_2:
884                 case Opcode.FLOAD_3:
885                 case Opcode.DLOAD_0:
886                 case Opcode.DLOAD_1:
887                 case Opcode.DLOAD_2:
888                 case Opcode.DLOAD_3:
889                 case Opcode.ALOAD_0:
890                 case Opcode.ALOAD_1:
891                 case Opcode.ALOAD_2:
892                 case Opcode.ALOAD_3:
893                     if (index == 0 && mHasThis) {
894                         assembler.loadThis();
895                     } else {
896                         assembler.loadLocal(getLocalVariable(index, type));
897                     }
898                     break;
899                 case Opcode.ISTORE:
900                 case Opcode.LSTORE:
901                 case Opcode.FSTORE:
902                 case Opcode.DSTORE:
903                 case Opcode.ASTORE:
904                 case Opcode.ISTORE_0:
905                 case Opcode.ISTORE_1:
906                 case Opcode.ISTORE_2:
907                 case Opcode.ISTORE_3:
908                 case Opcode.LSTORE_0:
909                 case Opcode.LSTORE_1:
910                 case Opcode.LSTORE_2:
911                 case Opcode.LSTORE_3:
912                 case Opcode.FSTORE_0:
913                 case Opcode.FSTORE_1:
914                 case Opcode.FSTORE_2:
915                 case Opcode.FSTORE_3:
916                 case Opcode.DSTORE_0:
917                 case Opcode.DSTORE_1:
918                 case Opcode.DSTORE_2:
919                 case Opcode.DSTORE_3:
920                 case Opcode.ASTORE_0:
921                 case Opcode.ASTORE_1:
922                 case Opcode.ASTORE_2:
923                 case Opcode.ASTORE_3:
924                     if (index == 0 && mHasThis) {
925                         // The "this" reference just got blown away.
926
mHasThis = false;
927                     }
928                     assembler.storeLocal(getLocalVariable(index, type));
929                     break;
930                 }
931                 break;
932
933             case Opcode.RET:
934                 LocalVariable local = getLocalVariable
935                     (readUnsignedByte(), TypeDesc.OBJECT);
936                 assembler.ret(local);
937                 break;
938
939             case Opcode.IINC:
940                 local = getLocalVariable(readUnsignedByte(), TypeDesc.INT);
941                 assembler.integerIncrement(local, readByte());
942                 break;
943
944                 // End opcodes that load or store local variables.
945

946                 // Opcodes that branch to another address.
947

948             case Opcode.GOTO:
949                 loc = getLabel(mAddress + readShort());
950                 assembler.branch(loc);
951                 break;
952             case Opcode.JSR:
953                 loc = getLabel(mAddress + readShort());
954                 assembler.jsr(loc);
955                 break;
956             case Opcode.GOTO_W:
957                 loc = getLabel(mAddress + readInt());
958                 assembler.branch(loc);
959                 break;
960             case Opcode.JSR_W:
961                 loc = getLabel(mAddress + readInt());
962                 assembler.jsr(loc);
963                 break;
964
965             case Opcode.IFNULL:
966                 loc = getLabel(mAddress + readShort());
967                 assembler.ifNullBranch(loc, true);
968                 break;
969             case Opcode.IFNONNULL:
970                 loc = getLabel(mAddress + readShort());
971                 assembler.ifNullBranch(loc, false);
972                 break;
973
974             case Opcode.IF_ACMPEQ:
975                 loc = getLabel(mAddress + readShort());
976                 assembler.ifEqualBranch(loc, true);
977                 break;
978             case Opcode.IF_ACMPNE:
979                 loc = getLabel(mAddress + readShort());
980                 assembler.ifEqualBranch(loc, false);
981                 break;
982
983             case Opcode.IFEQ:
984             case Opcode.IFNE:
985             case Opcode.IFLT:
986             case Opcode.IFGE:
987             case Opcode.IFGT:
988             case Opcode.IFLE:
989                 loc = getLabel(mAddress + readShort());
990                 String JavaDoc choice;
991                 switch (opcode) {
992                 case Opcode.IFEQ:
993                     choice = "==";
994                     break;
995                 case Opcode.IFNE:
996                     choice = "!=";
997                     break;
998                 case Opcode.IFLT:
999                     choice = "<";
1000                    break;
1001                case Opcode.IFGE:
1002                    choice = ">=";
1003                    break;
1004                case Opcode.IFGT:
1005                    choice = ">";
1006                    break;
1007                case Opcode.IFLE:
1008                    choice = "<=";
1009                    break;
1010                default:
1011                    choice = null;
1012                    break;
1013                }
1014                assembler.ifZeroComparisonBranch(loc, choice);
1015                break;
1016
1017            case Opcode.IF_ICMPEQ:
1018            case Opcode.IF_ICMPNE:
1019            case Opcode.IF_ICMPLT:
1020            case Opcode.IF_ICMPGE:
1021            case Opcode.IF_ICMPGT:
1022            case Opcode.IF_ICMPLE:
1023                loc = getLabel(mAddress + readShort());
1024                switch (opcode) {
1025                case Opcode.IF_ICMPEQ:
1026                    choice = "==";
1027                    break;
1028                case Opcode.IF_ICMPNE:
1029                    choice = "!=";
1030                    break;
1031                case Opcode.IF_ICMPLT:
1032                    choice = "<";
1033                    break;
1034                case Opcode.IF_ICMPGE:
1035                    choice = ">=";
1036                    break;
1037                case Opcode.IF_ICMPGT:
1038                    choice = ">";
1039                    break;
1040                case Opcode.IF_ICMPLE:
1041                    choice = "<=";
1042                    break;
1043                default:
1044                    choice = null;
1045                    break;
1046                }
1047                assembler.ifComparisonBranch(loc, choice);
1048                break;
1049
1050                // End opcodes that branch to another address.
1051

1052                // Miscellaneous opcodes...
1053

1054            case Opcode.BIPUSH:
1055                assembler.loadConstant(readByte());
1056                break;
1057            case Opcode.SIPUSH:
1058                assembler.loadConstant(readShort());
1059                break;
1060
1061            case Opcode.NEWARRAY:
1062                int atype = readByte();
1063                type = null;
1064                switch (atype) {
1065                case 4: // T_BOOLEAN
1066
type = TypeDesc.BOOLEAN;
1067                    break;
1068                case 5: // T_CHAR
1069
type = TypeDesc.CHAR;
1070                    break;
1071                case 6: // T_FLOAT
1072
type = TypeDesc.FLOAT;
1073                    break;
1074                case 7: // T_DOUBLE
1075
type = TypeDesc.DOUBLE;
1076                    break;
1077                case 8: // T_BYTE
1078
type = TypeDesc.BYTE;
1079                    break;
1080                case 9: // T_SHORT
1081
type = TypeDesc.SHORT;
1082                    break;
1083                case 10: // T_INT
1084
type = TypeDesc.INT;
1085                    break;
1086                case 11: // T_LONG
1087
type = TypeDesc.LONG;
1088                    break;
1089                }
1090
1091                if (type == null) {
1092                    error(opcode, "Unknown primitive type for new array: " + atype);
1093                    break;
1094                }
1095
1096                assembler.newObject(type.toArrayType());
1097                break;
1098
1099            case Opcode.TABLESWITCH:
1100            case Opcode.LOOKUPSWITCH:
1101                int opcodeAddress = mAddress;
1102                // Read padding until address is 32 bit word aligned.
1103
while (((mAddress + 1) & 3) != 0) {
1104                    ++mAddress;
1105                }
1106                Location defaultLocation = getLabel(opcodeAddress + readInt());
1107                int[] cases;
1108                Location[] locations;
1109                
1110                if (opcode == Opcode.TABLESWITCH) {
1111                    int lowValue = readInt();
1112                    int highValue = readInt();
1113                    int caseCount = highValue - lowValue + 1;
1114                    try {
1115                        cases = new int[caseCount];
1116                    } catch (NegativeArraySizeException JavaDoc e) {
1117                        error(opcode, "Negative case count for switch: " + caseCount);
1118                        break;
1119                    }
1120                    locations = new Location[caseCount];
1121                    for (int i=0; i<caseCount; i++) {
1122                        cases[i] = lowValue + i;
1123                        locations[i] = getLabel(opcodeAddress + readInt());
1124                    }
1125                } else {
1126                    int caseCount = readInt();
1127                    try {
1128                        cases = new int[caseCount];
1129                    } catch (NegativeArraySizeException JavaDoc e) {
1130                        error(opcode, "Negative case count for switch: " + caseCount);
1131                        break;
1132                    }
1133                    locations = new Location[caseCount];
1134                    for (int i=0; i<caseCount; i++) {
1135                        cases[i] = readInt();
1136                        locations[i] = getLabel(opcodeAddress + readInt());
1137                    }
1138                }
1139
1140                assembler.switchBranch(cases, locations, defaultLocation);
1141                break;
1142
1143            case Opcode.WIDE:
1144                opcode = mByteCodes[++mAddress];
1145                switch (opcode) {
1146
1147                default:
1148                    error(opcode, "Unknown wide instruction");
1149                    break;
1150
1151                case Opcode.ILOAD: case Opcode.ISTORE:
1152                case Opcode.LLOAD: case Opcode.LSTORE:
1153                case Opcode.FLOAD: case Opcode.FSTORE:
1154                case Opcode.DLOAD: case Opcode.DSTORE:
1155                case Opcode.ALOAD: case Opcode.ASTORE:
1156
1157                    switch (opcode) {
1158                    case Opcode.ILOAD: case Opcode.ISTORE:
1159                        type = TypeDesc.INT;
1160                        break;
1161                    case Opcode.LLOAD: case Opcode.LSTORE:
1162                        type = TypeDesc.LONG;
1163                        break;
1164                    case Opcode.FLOAD: case Opcode.FSTORE:
1165                        type = TypeDesc.FLOAT;
1166                        break;
1167                    case Opcode.DLOAD: case Opcode.DSTORE:
1168                        type = TypeDesc.DOUBLE;
1169                        break;
1170                    case Opcode.ALOAD: case Opcode.ASTORE:
1171                        type = TypeDesc.OBJECT;
1172                        break;
1173                    default:
1174                        type = null;
1175                        break;
1176                    }
1177                    
1178                    index = readUnsignedShort();
1179
1180                    switch (opcode) {
1181                    case Opcode.ILOAD:
1182                    case Opcode.LLOAD:
1183                    case Opcode.FLOAD:
1184                    case Opcode.DLOAD:
1185                    case Opcode.ALOAD:
1186                        if (index == 0 && mHasThis) {
1187                            assembler.loadThis();
1188                        } else {
1189                            assembler.loadLocal(getLocalVariable(index, type));
1190                        }
1191                        break;
1192                    case Opcode.ISTORE:
1193                    case Opcode.LSTORE:
1194                    case Opcode.FSTORE:
1195                    case Opcode.DSTORE:
1196                    case Opcode.ASTORE:
1197                        if (index == 0 && mHasThis) {
1198                            // The "this" reference just got blown away.
1199
mHasThis = false;
1200                        }
1201                        assembler.storeLocal(getLocalVariable(index, type));
1202                        break;
1203                    }
1204                    break;
1205
1206                case Opcode.RET:
1207                    local = getLocalVariable
1208                        (readUnsignedShort(), TypeDesc.OBJECT);
1209                    assembler.ret(local);
1210                    break;
1211                    
1212                case Opcode.IINC:
1213                    local = getLocalVariable
1214                        (readUnsignedShort(), TypeDesc.INT);
1215                    assembler.integerIncrement(local, readShort());
1216                    break;
1217                }
1218
1219                break;
1220            } // end huge switch
1221
} // end for loop
1222
}
1223
1224    /**
1225     * Invoked on disassembly errors. By default, this method does nothing.
1226     */

1227    protected void error(byte opcode, String JavaDoc message) {
1228    }
1229
1230    private void gatherLabels() {
1231        mLabels = new HashMap JavaDoc();
1232        mCatchLocations = new HashMap JavaDoc(mExceptionHandlers.length * 2 + 1);
1233        Integer JavaDoc labelKey;
1234
1235        // Gather labels for any exception handlers.
1236
for (int i = mExceptionHandlers.length - 1; i >= 0; i--) {
1237            ExceptionHandler handler = mExceptionHandlers[i];
1238            labelKey = new Integer JavaDoc(handler.getStartLocation().getLocation());
1239            mLabels.put(labelKey, labelKey);
1240            labelKey = new Integer JavaDoc(handler.getEndLocation().getLocation());
1241            mLabels.put(labelKey, labelKey);
1242            labelKey = new Integer JavaDoc(handler.getCatchLocation().getLocation());
1243            List JavaDoc list = (List JavaDoc)mCatchLocations.get(labelKey);
1244            if (list == null) {
1245                list = new ArrayList JavaDoc(2);
1246                mCatchLocations.put(labelKey, list);
1247            }
1248            list.add(handler);
1249        }
1250
1251        // Now gather labels that occur within byte code.
1252
for (mAddress = 0; mAddress < mByteCodes.length; mAddress++) {
1253            byte opcode = mByteCodes[mAddress];
1254
1255            switch (opcode) {
1256
1257            default:
1258                error(opcode, "Unknown opcode: " + (opcode & 0xff));
1259                break;
1260
1261                // Opcodes that use labels.
1262

1263            case Opcode.GOTO:
1264            case Opcode.JSR:
1265            case Opcode.IFNULL:
1266            case Opcode.IFNONNULL:
1267            case Opcode.IF_ACMPEQ:
1268            case Opcode.IF_ACMPNE:
1269            case Opcode.IFEQ:
1270            case Opcode.IFNE:
1271            case Opcode.IFLT:
1272            case Opcode.IFGE:
1273            case Opcode.IFGT:
1274            case Opcode.IFLE:
1275            case Opcode.IF_ICMPEQ:
1276            case Opcode.IF_ICMPNE:
1277            case Opcode.IF_ICMPLT:
1278            case Opcode.IF_ICMPGE:
1279            case Opcode.IF_ICMPGT:
1280            case Opcode.IF_ICMPLE:
1281                labelKey = new Integer JavaDoc(mAddress + readShort());
1282                mLabels.put(labelKey, labelKey);
1283                break;
1284
1285            case Opcode.GOTO_W:
1286            case Opcode.JSR_W:
1287                labelKey = new Integer JavaDoc(mAddress + readInt());
1288                mLabels.put(labelKey, labelKey);
1289                break;
1290
1291            case Opcode.TABLESWITCH:
1292            case Opcode.LOOKUPSWITCH:
1293                int opcodeAddress = mAddress;
1294                // Read padding until address is 32 bit word aligned.
1295
while (((mAddress + 1) & 3) != 0) {
1296                    ++mAddress;
1297                }
1298                
1299                // Read the default location.
1300
labelKey = new Integer JavaDoc(opcodeAddress + readInt());
1301                mLabels.put(labelKey, labelKey);
1302                
1303                if (opcode == Opcode.TABLESWITCH) {
1304                    int lowValue = readInt();
1305                    int highValue = readInt();
1306                    int caseCount = highValue - lowValue + 1;
1307
1308                    for (int i=0; i<caseCount; i++) {
1309                        // Read the branch location.
1310
labelKey = new Integer JavaDoc(opcodeAddress + readInt());
1311                        mLabels.put(labelKey, labelKey);
1312                    }
1313                } else {
1314                    int caseCount = readInt();
1315
1316                    for (int i=0; i<caseCount; i++) {
1317                        // Skip the case value.
1318
mAddress += 4;
1319                        // Read the branch location.
1320
labelKey = new Integer JavaDoc(opcodeAddress + readInt());
1321                        mLabels.put(labelKey, labelKey);
1322                    }
1323                }
1324                break;
1325
1326                // All other operations are skipped. The amount to skip
1327
// depends on the operand size.
1328

1329                // Opcodes with no operands...
1330

1331            case Opcode.NOP:
1332            case Opcode.BREAKPOINT:
1333            case Opcode.ACONST_NULL:
1334            case Opcode.ICONST_M1:
1335            case Opcode.ICONST_0:
1336            case Opcode.ICONST_1:
1337            case Opcode.ICONST_2:
1338            case Opcode.ICONST_3:
1339            case Opcode.ICONST_4:
1340            case Opcode.ICONST_5:
1341            case Opcode.LCONST_0:
1342            case Opcode.LCONST_1:
1343            case Opcode.FCONST_0:
1344            case Opcode.FCONST_1:
1345            case Opcode.FCONST_2:
1346            case Opcode.DCONST_0:
1347            case Opcode.DCONST_1:
1348            case Opcode.POP:
1349            case Opcode.POP2:
1350            case Opcode.DUP:
1351            case Opcode.DUP_X1:
1352            case Opcode.DUP_X2:
1353            case Opcode.DUP2:
1354            case Opcode.DUP2_X1:
1355            case Opcode.DUP2_X2:
1356            case Opcode.SWAP:
1357            case Opcode.IADD: case Opcode.LADD:
1358            case Opcode.FADD: case Opcode.DADD:
1359            case Opcode.ISUB: case Opcode.LSUB:
1360            case Opcode.FSUB: case Opcode.DSUB:
1361            case Opcode.IMUL: case Opcode.LMUL:
1362            case Opcode.FMUL: case Opcode.DMUL:
1363            case Opcode.IDIV: case Opcode.LDIV:
1364            case Opcode.FDIV: case Opcode.DDIV:
1365            case Opcode.IREM: case Opcode.LREM:
1366            case Opcode.FREM: case Opcode.DREM:
1367            case Opcode.INEG: case Opcode.LNEG:
1368            case Opcode.FNEG: case Opcode.DNEG:
1369            case Opcode.ISHL: case Opcode.LSHL:
1370            case Opcode.ISHR: case Opcode.LSHR:
1371            case Opcode.IUSHR: case Opcode.LUSHR:
1372            case Opcode.IAND: case Opcode.LAND:
1373            case Opcode.IOR: case Opcode.LOR:
1374            case Opcode.IXOR: case Opcode.LXOR:
1375            case Opcode.FCMPL: case Opcode.DCMPL:
1376            case Opcode.FCMPG: case Opcode.DCMPG:
1377            case Opcode.LCMP:
1378            case Opcode.I2L:
1379            case Opcode.I2F:
1380            case Opcode.I2D:
1381            case Opcode.L2I:
1382            case Opcode.L2F:
1383            case Opcode.L2D:
1384            case Opcode.F2I:
1385            case Opcode.F2L:
1386            case Opcode.F2D:
1387            case Opcode.D2I:
1388            case Opcode.D2L:
1389            case Opcode.D2F:
1390            case Opcode.I2B:
1391            case Opcode.I2C:
1392            case Opcode.I2S:
1393            case Opcode.IRETURN:
1394            case Opcode.LRETURN:
1395            case Opcode.FRETURN:
1396            case Opcode.DRETURN:
1397            case Opcode.ARETURN:
1398            case Opcode.RETURN:
1399            case Opcode.IALOAD:
1400            case Opcode.LALOAD:
1401            case Opcode.FALOAD:
1402            case Opcode.DALOAD:
1403            case Opcode.AALOAD:
1404            case Opcode.BALOAD:
1405            case Opcode.CALOAD:
1406            case Opcode.SALOAD:
1407            case Opcode.IASTORE:
1408            case Opcode.LASTORE:
1409            case Opcode.FASTORE:
1410            case Opcode.DASTORE:
1411            case Opcode.AASTORE:
1412            case Opcode.BASTORE:
1413            case Opcode.CASTORE:
1414            case Opcode.SASTORE:
1415            case Opcode.ARRAYLENGTH:
1416            case Opcode.ATHROW:
1417            case Opcode.MONITORENTER:
1418            case Opcode.MONITOREXIT:
1419            case Opcode.ILOAD_0: case Opcode.ISTORE_0:
1420            case Opcode.ILOAD_1: case Opcode.ISTORE_1:
1421            case Opcode.ILOAD_2: case Opcode.ISTORE_2:
1422            case Opcode.ILOAD_3: case Opcode.ISTORE_3:
1423            case Opcode.LLOAD_0: case Opcode.LSTORE_0:
1424            case Opcode.LLOAD_1: case Opcode.LSTORE_1:
1425            case Opcode.LLOAD_2: case Opcode.LSTORE_2:
1426            case Opcode.LLOAD_3: case Opcode.LSTORE_3:
1427            case Opcode.FLOAD_0: case Opcode.FSTORE_0:
1428            case Opcode.FLOAD_1: case Opcode.FSTORE_1:
1429            case Opcode.FLOAD_2: case Opcode.FSTORE_2:
1430            case Opcode.FLOAD_3: case Opcode.FSTORE_3:
1431            case Opcode.DLOAD_0: case Opcode.DSTORE_0:
1432            case Opcode.DLOAD_1: case Opcode.DSTORE_1:
1433            case Opcode.DLOAD_2: case Opcode.DSTORE_2:
1434            case Opcode.DLOAD_3: case Opcode.DSTORE_3:
1435            case Opcode.ALOAD_0: case Opcode.ASTORE_0:
1436            case Opcode.ALOAD_1: case Opcode.ASTORE_1:
1437            case Opcode.ALOAD_2: case Opcode.ASTORE_2:
1438            case Opcode.ALOAD_3: case Opcode.ASTORE_3:
1439                break;
1440
1441                // Opcodes with one operand byte...
1442

1443            case Opcode.LDC:
1444            case Opcode.ILOAD: case Opcode.ISTORE:
1445            case Opcode.LLOAD: case Opcode.LSTORE:
1446            case Opcode.FLOAD: case Opcode.FSTORE:
1447            case Opcode.DLOAD: case Opcode.DSTORE:
1448            case Opcode.ALOAD: case Opcode.ASTORE:
1449            case Opcode.RET:
1450            case Opcode.BIPUSH:
1451            case Opcode.NEWARRAY:
1452                mAddress += 1;
1453                break;
1454
1455                // Opcodes with two operand bytes...
1456

1457            case Opcode.LDC_W:
1458            case Opcode.LDC2_W:
1459            case Opcode.NEW:
1460            case Opcode.ANEWARRAY:
1461            case Opcode.CHECKCAST:
1462            case Opcode.INSTANCEOF:
1463            case Opcode.GETSTATIC:
1464            case Opcode.PUTSTATIC:
1465            case Opcode.GETFIELD:
1466            case Opcode.PUTFIELD:
1467            case Opcode.INVOKEVIRTUAL:
1468            case Opcode.INVOKESPECIAL:
1469            case Opcode.INVOKESTATIC:
1470            case Opcode.SIPUSH:
1471            case Opcode.IINC:
1472                mAddress += 2;
1473                break;
1474
1475                // Opcodes with three operand bytes...
1476

1477            case Opcode.MULTIANEWARRAY:
1478                mAddress += 3;
1479                break;
1480
1481                // Opcodes with four operand bytes...
1482

1483            case Opcode.INVOKEINTERFACE:
1484                mAddress += 4;
1485                break;
1486
1487                // Wide opcode has a variable sized operand.
1488

1489            case Opcode.WIDE:
1490                opcode = mByteCodes[++mAddress];
1491                mAddress += 2;
1492                if (opcode == Opcode.IINC) {
1493                    mAddress += 2;
1494                }
1495                break;
1496            } // end huge switch
1497
} // end for loop
1498
}
1499
1500    private int readByte() {
1501        return mByteCodes[++mAddress];
1502    }
1503
1504    private int readUnsignedByte() {
1505        return mByteCodes[++mAddress] & 0xff;
1506    }
1507
1508    private int readShort() {
1509        return (mByteCodes[++mAddress] << 8) | (mByteCodes[++mAddress] & 0xff);
1510    }
1511
1512    private int readUnsignedShort() {
1513        return
1514            ((mByteCodes[++mAddress] & 0xff) << 8) |
1515            ((mByteCodes[++mAddress] & 0xff) << 0);
1516    }
1517
1518    private int readInt() {
1519        return
1520            (mByteCodes[++mAddress] << 24) |
1521            ((mByteCodes[++mAddress] & 0xff) << 16) |
1522            ((mByteCodes[++mAddress] & 0xff) << 8) |
1523            ((mByteCodes[++mAddress] & 0xff) << 0);
1524    }
1525
1526    private LocalVariable getLocalVariable(final int index, final TypeDesc type) {
1527        LocalVariable local;
1528
1529        if (index >= mLocals.size()) {
1530            mLocals.setSize(index + 1);
1531            local = mAssembler.createLocalVariable(null, type);
1532            mLocals.set(index, local);
1533            return local;
1534        }
1535
1536        Object JavaDoc obj = mLocals.get(index);
1537
1538        if (obj == null) {
1539            local = mAssembler.createLocalVariable(null, type);
1540            mLocals.set(index, local);
1541            return local;
1542        }
1543
1544        if (obj instanceof LocalVariable) {
1545            local = (LocalVariable)obj;
1546            if (compatibleType(type, local.getType())) {
1547                return local;
1548            }
1549            // Variable takes on multiple types, so convert entry to a list.
1550
List JavaDoc locals = new ArrayList JavaDoc(4);
1551            locals.add(local);
1552            local = mAssembler.createLocalVariable(null, type);
1553            locals.add(local);
1554            mLocals.set(index, locals);
1555            return local;
1556        }
1557        
1558        List JavaDoc locals = (List JavaDoc)obj;
1559        for (int i=locals.size(); --i>=0; ) {
1560            local = (LocalVariable)locals.get(i);
1561            if (compatibleType(type, local.getType())) {
1562                return local;
1563            }
1564        }
1565        
1566        local = mAssembler.createLocalVariable(null, type);
1567        locals.add(local);
1568        return local;
1569    }
1570
1571    private boolean compatibleType(TypeDesc a, TypeDesc b) {
1572        if (a == b || (!a.isPrimitive() && !b.isPrimitive())) {
1573            return true;
1574        }
1575        if (isIntType(a) && isIntType(b)) {
1576            return true;
1577        }
1578        return false;
1579    }
1580
1581    private boolean isIntType(TypeDesc type) {
1582        switch (type.getTypeCode()) {
1583        case TypeDesc.INT_CODE:
1584        case TypeDesc.BOOLEAN_CODE:
1585        case TypeDesc.BYTE_CODE:
1586        case TypeDesc.SHORT_CODE:
1587        case TypeDesc.CHAR_CODE:
1588            return true;
1589        }
1590        return false;
1591    }
1592
1593    private void locateLabel() {
1594        Integer JavaDoc labelKey = new Integer JavaDoc(mAddress);
1595        Object JavaDoc labelValue = mLabels.get(labelKey);
1596        if (labelValue != null) {
1597            if (labelValue instanceof Label) {
1598                ((Label)labelValue).setLocation();
1599            } else {
1600                labelValue = mAssembler.createLabel().setLocation();
1601                mLabels.put(labelKey, labelValue);
1602            }
1603        }
1604
1605        List JavaDoc handlers = (List JavaDoc)mCatchLocations.get(labelKey);
1606
1607        if (handlers != null) {
1608            for (int i=0; i<handlers.size(); i++) {
1609                ExceptionHandler handler = (ExceptionHandler)handlers.get(i);
1610                Label start =
1611                    getLabel(handler.getStartLocation().getLocation());
1612                Label end =
1613                    getLabel(handler.getEndLocation().getLocation());
1614                String JavaDoc catchClassName;
1615                if (handler.getCatchType() == null) {
1616                    catchClassName = null;
1617                } else {
1618                    catchClassName = handler.getCatchType().getType().getFullName();
1619                }
1620                mAssembler.exceptionHandler(start, end, catchClassName);
1621            }
1622        }
1623    }
1624
1625    private Label getLabel(int address) {
1626        Integer JavaDoc labelKey = new Integer JavaDoc(address);
1627        Object JavaDoc labelValue = mLabels.get(labelKey);
1628        // labelValue will never be null unless gatherLabels is broken.
1629
if (!(labelValue instanceof Label)) {
1630            labelValue = mAssembler.createLabel();
1631            mLabels.put(labelKey, labelValue);
1632        }
1633        return (Label)labelValue;
1634    }
1635}
1636
Popular Tags