comparison src/com/go/trove/classfile/CodeDisassembler.java @ 0:3dc0c5604566

Initial checkin of blitz 2.0 fcs - no installer yet.
author Dan Creswell <dan.creswell@gmail.com>
date Sat, 21 Mar 2009 11:00:06 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:3dc0c5604566
1 /* ====================================================================
2 * Trove - Copyright (c) 1997-2000 Walt Disney Internet Group
3 * ====================================================================
4 * The Tea Software License, Version 1.1
5 *
6 * Copyright (c) 2000 Walt Disney Internet Group. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in
17 * the documentation and/or other materials provided with the
18 * distribution.
19 *
20 * 3. The end-user documentation included with the redistribution,
21 * if any, must include the following acknowledgment:
22 * "This product includes software developed by the
23 * Walt Disney Internet Group (http://opensource.go.com/)."
24 * Alternately, this acknowledgment may appear in the software itself,
25 * if and wherever such third-party acknowledgments normally appear.
26 *
27 * 4. The names "Tea", "TeaServlet", "Kettle", "Trove" and "BeanDoc" must
28 * not be used to endorse or promote products derived from this
29 * software without prior written permission. For written
30 * permission, please contact opensource@dig.com.
31 *
32 * 5. Products derived from this software may not be called "Tea",
33 * "TeaServlet", "Kettle" or "Trove", nor may "Tea", "TeaServlet",
34 * "Kettle", "Trove" or "BeanDoc" appear in their name, without prior
35 * written permission of the Walt Disney Internet Group.
36 *
37 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40 * DISCLAIMED. IN NO EVENT SHALL THE WALT DISNEY INTERNET GROUP OR ITS
41 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
42 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
43 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
44 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
45 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
46 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
47 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48 * ====================================================================
49 *
50 * For more information about Tea, please see http://opensource.go.com/.
51 */
52
53 package com.go.trove.classfile;
54
55 import java.util.*;
56
57 /******************************************************************************
58 *
59 * @author Brian S O'Neill
60 * @version
61 * <!--$$Revision: 1.1 $-->, <!--$$JustDate:--> 00/12/27 <!-- $-->
62 */
63 public class CodeDisassembler {
64 private final MethodInfo mMethod;
65 private final String mEnclosingClassName;
66 private final String mSuperClassName;
67 private final CodeAttr mCode;
68 private final ConstantPool mCp;
69 private final byte[] mByteCodes;
70 private final ExceptionHandler[] mExceptionHandlers;
71
72 // Current CodeAssembler in use for disassembly.
73 private CodeAssembler mAssembler;
74
75 // List of all the LocalVariable objects in use.
76 private Vector mLocals;
77
78 // True if the method being decompiled still has a "this" reference.
79 private boolean mHasThis;
80
81 // Maps Integer address keys to itself, but to Label objects after first
82 // needed.
83 private Map mLabels;
84
85 // Maps Integer catch locations to Lists of ExceptionHandler objects.
86 private Map mCatchLocations;
87
88 // Current address being decompiled.
89 private int mAddress;
90
91 public CodeDisassembler(MethodInfo method) {
92 mMethod = method;
93 mEnclosingClassName = method.getClassFile().getClassName();
94 mSuperClassName = method.getClassFile().getSuperClassName();
95 mCode = method.getCodeAttr();
96 mCp = mCode.getConstantPool();
97 CodeBuffer buffer = mCode.getCodeBuffer();
98 mByteCodes = buffer.getByteCodes();
99 mExceptionHandlers = buffer.getExceptionHandlers();
100 }
101
102 /**
103 * Disassemble the MethodInfo into the given assembler.
104 *
105 * @see CodeAssemblerPrinter
106 */
107 public synchronized void disassemble(CodeAssembler assembler) {
108 mAssembler = assembler;
109 mLocals = new Vector();
110 mHasThis = !mMethod.getAccessFlags().isStatic();
111
112 gatherLabels();
113
114 // Gather the local variables of the parameters.
115 LocalVariable[] paramVars = assembler.getParameters();
116 for (int i=0; i<paramVars.length; i++) {
117 LocalVariable paramVar = paramVars[i];
118 int number = paramVar.getNumber();
119 if (number >= mLocals.size()) {
120 mLocals.setSize(number + 1);
121 }
122 mLocals.setElementAt(paramVar, number);
123 }
124
125 Location currentLoc = new Location() {
126 public int getLocation() {
127 return mAddress;
128 }
129
130 public int compareTo(Object obj) {
131 if (this == obj) {
132 return 0;
133 }
134 Location other = (Location)obj;
135
136 int loca = getLocation();
137 int locb = other.getLocation();
138
139 if (loca < locb) {
140 return -1;
141 }
142 else if (loca > locb) {
143 return 1;
144 }
145 else {
146 return 0;
147 }
148 }
149 };
150
151 int currentLine = -1;
152
153 for (mAddress = 0; mAddress < mByteCodes.length; mAddress++) {
154 int nextLine = mCode.getLineNumber(currentLoc);
155 if (nextLine != currentLine) {
156 if ((currentLine = nextLine) >= 0) {
157 mAssembler.mapLineNumber(currentLine);
158 }
159 }
160
161 // Check if a label needs to be created and/or located.
162 locateLabel();
163
164 byte opcode = mByteCodes[mAddress];
165
166 int index;
167 Location loc;
168 Class clazz;
169 ConstantInfo ci;
170
171 switch (opcode) {
172
173 default:
174 // TODO: raise an error.
175 break;
176
177 // Opcodes with no operands...
178
179 case Opcode.NOP:
180 assembler.nop();
181 break;
182 case Opcode.BREAKPOINT:
183 assembler.breakpoint();
184 break;
185
186 case Opcode.ACONST_NULL:
187 assembler.loadConstant(null);
188 break;
189 case Opcode.ICONST_M1:
190 assembler.loadConstant(-1);
191 break;
192 case Opcode.ICONST_0:
193 assembler.loadConstant(0);
194 break;
195 case Opcode.ICONST_1:
196 assembler.loadConstant(1);
197 break;
198 case Opcode.ICONST_2:
199 assembler.loadConstant(2);
200 break;
201 case Opcode.ICONST_3:
202 assembler.loadConstant(3);
203 break;
204 case Opcode.ICONST_4:
205 assembler.loadConstant(4);
206 break;
207 case Opcode.ICONST_5:
208 assembler.loadConstant(5);
209 break;
210 case Opcode.LCONST_0:
211 assembler.loadConstant(0L);
212 break;
213 case Opcode.LCONST_1:
214 assembler.loadConstant(1L);
215 break;
216 case Opcode.FCONST_0:
217 assembler.loadConstant(0f);
218 break;
219 case Opcode.FCONST_1:
220 assembler.loadConstant(1f);
221 break;
222 case Opcode.FCONST_2:
223 assembler.loadConstant(2f);
224 break;
225 case Opcode.DCONST_0:
226 assembler.loadConstant(0d);
227 break;
228 case Opcode.DCONST_1:
229 assembler.loadConstant(1d);
230 break;
231
232 case Opcode.POP:
233 assembler.pop();
234 break;
235 case Opcode.POP2:
236 assembler.pop2();
237 break;
238 case Opcode.DUP:
239 assembler.dup();
240 break;
241 case Opcode.DUP_X1:
242 assembler.dupX1();
243 break;
244 case Opcode.DUP_X2:
245 assembler.dupX2();
246 break;
247 case Opcode.DUP2:
248 assembler.dup2();
249 break;
250 case Opcode.DUP2_X1:
251 assembler.dup2X2();
252 break;
253 case Opcode.DUP2_X2:
254 assembler.dup2X2();
255 break;
256 case Opcode.SWAP:
257 assembler.swap();
258 break;
259
260 case Opcode.IADD: case Opcode.LADD:
261 case Opcode.FADD: case Opcode.DADD:
262 case Opcode.ISUB: case Opcode.LSUB:
263 case Opcode.FSUB: case Opcode.DSUB:
264 case Opcode.IMUL: case Opcode.LMUL:
265 case Opcode.FMUL: case Opcode.DMUL:
266 case Opcode.IDIV: case Opcode.LDIV:
267 case Opcode.FDIV: case Opcode.DDIV:
268 case Opcode.IREM: case Opcode.LREM:
269 case Opcode.FREM: case Opcode.DREM:
270 case Opcode.INEG: case Opcode.LNEG:
271 case Opcode.FNEG: case Opcode.DNEG:
272 case Opcode.ISHL: case Opcode.LSHL:
273 case Opcode.ISHR: case Opcode.LSHR:
274 case Opcode.IUSHR: case Opcode.LUSHR:
275 case Opcode.IAND: case Opcode.LAND:
276 case Opcode.IOR: case Opcode.LOR:
277 case Opcode.IXOR: case Opcode.LXOR:
278 case Opcode.FCMPL: case Opcode.DCMPL:
279 case Opcode.FCMPG: case Opcode.DCMPG:
280 case Opcode.LCMP:
281 assembler.math(opcode);
282 break;
283
284 case Opcode.I2L:
285 assembler.convert(int.class, long.class);
286 break;
287 case Opcode.I2F:
288 assembler.convert(int.class, float.class);
289 break;
290 case Opcode.I2D:
291 assembler.convert(int.class, double.class);
292 break;
293 case Opcode.L2I:
294 assembler.convert(long.class, int.class);
295 break;
296 case Opcode.L2F:
297 assembler.convert(long.class, float.class);
298 break;
299 case Opcode.L2D:
300 assembler.convert(long.class, double.class);
301 break;
302 case Opcode.F2I:
303 assembler.convert(float.class, int.class);
304 break;
305 case Opcode.F2L:
306 assembler.convert(float.class, long.class);
307 break;
308 case Opcode.F2D:
309 assembler.convert(float.class, double.class);
310 break;
311 case Opcode.D2I:
312 assembler.convert(double.class, int.class);
313 break;
314 case Opcode.D2L:
315 assembler.convert(double.class, long.class);
316 break;
317 case Opcode.D2F:
318 assembler.convert(double.class, float.class);
319 break;
320 case Opcode.I2B:
321 assembler.convert(int.class, byte.class);
322 break;
323 case Opcode.I2C:
324 assembler.convert(int.class, char.class);
325 break;
326 case Opcode.I2S:
327 assembler.convert(int.class, short.class);
328 break;
329
330 case Opcode.IRETURN:
331 assembler.returnValue(int.class);
332 break;
333 case Opcode.LRETURN:
334 assembler.returnValue(long.class);
335 break;
336 case Opcode.FRETURN:
337 assembler.returnValue(float.class);
338 break;
339 case Opcode.DRETURN:
340 assembler.returnValue(double.class);
341 break;
342 case Opcode.ARETURN:
343 assembler.returnValue(Object.class);
344 break;
345 case Opcode.RETURN:
346 assembler.returnVoid();
347 break;
348
349 case Opcode.IALOAD:
350 assembler.loadFromArray(int.class);
351 break;
352 case Opcode.LALOAD:
353 assembler.loadFromArray(long.class);
354 break;
355 case Opcode.FALOAD:
356 assembler.loadFromArray(float.class);
357 break;
358 case Opcode.DALOAD:
359 assembler.loadFromArray(double.class);
360 break;
361 case Opcode.AALOAD:
362 assembler.loadFromArray(Object.class);
363 break;
364 case Opcode.BALOAD:
365 assembler.loadFromArray(byte.class);
366 break;
367 case Opcode.CALOAD:
368 assembler.loadFromArray(char.class);
369 break;
370 case Opcode.SALOAD:
371 assembler.loadFromArray(short.class);
372 break;
373
374 case Opcode.IASTORE:
375 assembler.storeToArray(int.class);
376 break;
377 case Opcode.LASTORE:
378 assembler.storeToArray(long.class);
379 break;
380 case Opcode.FASTORE:
381 assembler.storeToArray(float.class);
382 break;
383 case Opcode.DASTORE:
384 assembler.storeToArray(double.class);
385 break;
386 case Opcode.AASTORE:
387 assembler.storeToArray(Object.class);
388 break;
389 case Opcode.BASTORE:
390 assembler.storeToArray(byte.class);
391 break;
392 case Opcode.CASTORE:
393 assembler.storeToArray(char.class);
394 break;
395 case Opcode.SASTORE:
396 assembler.storeToArray(short.class);
397 break;
398
399 case Opcode.ARRAYLENGTH:
400 assembler.arrayLength();
401 break;
402 case Opcode.ATHROW:
403 assembler.throwObject();
404 break;
405 case Opcode.MONITORENTER:
406 assembler.monitorEnter();
407 break;
408 case Opcode.MONITOREXIT:
409 assembler.monitorExit();
410 break;
411
412 // End opcodes with no operands.
413
414 // Opcodes that load a constant from the constant pool...
415
416 case Opcode.LDC:
417 case Opcode.LDC_W:
418 case Opcode.LDC2_W:
419 switch (opcode) {
420 case Opcode.LDC:
421 index = readUnsignedByte();
422 break;
423 case Opcode.LDC_W:
424 case Opcode.LDC2_W:
425 index = readUnsignedShort();
426 break;
427 default:
428 index = 0;
429 break;
430 }
431
432 ci = mCp.getConstant(index);
433
434 if (ci instanceof ConstantStringInfo) {
435 assembler.loadConstant
436 (((ConstantStringInfo)ci).getValue());
437 }
438 else if (ci instanceof ConstantIntegerInfo) {
439 assembler.loadConstant
440 (((ConstantIntegerInfo)ci).getValue().intValue());
441 }
442 else if (ci instanceof ConstantLongInfo) {
443 assembler.loadConstant
444 (((ConstantLongInfo)ci).getValue().longValue());
445 }
446 else if (ci instanceof ConstantFloatInfo) {
447 assembler.loadConstant
448 (((ConstantFloatInfo)ci).getValue().floatValue());
449 }
450 else if (ci instanceof ConstantDoubleInfo) {
451 assembler.loadConstant
452 (((ConstantDoubleInfo)ci).getValue().doubleValue());
453 }
454 else {
455 // TODO: raise an error.
456 }
457 break;
458
459 case Opcode.NEW:
460 ci = mCp.getConstant(readUnsignedShort());
461
462 if (ci instanceof ConstantClassInfo) {
463 assembler.newObject
464 (((ConstantClassInfo)ci).getTypeDescriptor());
465 }
466 else {
467 // TODO: raise an error.
468 }
469 break;
470 case Opcode.ANEWARRAY:
471 ci = mCp.getConstant(readUnsignedShort());
472
473 if (ci instanceof ConstantClassInfo) {
474 TypeDescriptor type =
475 ((ConstantClassInfo)ci).getTypeDescriptor();
476 type = new TypeDescriptor(type, 1);
477 assembler.newObject(type);
478 }
479 else {
480 // TODO: raise an error.
481 }
482 break;
483 case Opcode.MULTIANEWARRAY:
484 ci = mCp.getConstant(readUnsignedShort());
485 int dims = readUnsignedByte();
486
487 if (ci instanceof ConstantClassInfo) {
488 assembler.newObject
489 (((ConstantClassInfo)ci).getTypeDescriptor());
490 }
491 else {
492 // TODO: raise an error.
493 }
494 break;
495
496 case Opcode.CHECKCAST:
497 ci = mCp.getConstant(readUnsignedShort());
498
499 if (ci instanceof ConstantClassInfo) {
500 assembler.checkCast
501 (((ConstantClassInfo)ci).getTypeDescriptor());
502 }
503 else {
504 // TODO: raise an error.
505 }
506 break;
507 case Opcode.INSTANCEOF:
508 ci = mCp.getConstant(readUnsignedShort());
509
510 if (ci instanceof ConstantClassInfo) {
511 assembler.instanceOf
512 (((ConstantClassInfo)ci).getTypeDescriptor());
513 }
514 else {
515 // TODO: raise an error.
516 }
517 break;
518
519 case Opcode.GETSTATIC:
520 case Opcode.PUTSTATIC:
521 case Opcode.GETFIELD:
522 case Opcode.PUTFIELD:
523 ci = mCp.getConstant(readUnsignedShort());
524 if (!(ci instanceof ConstantFieldInfo)) {
525 // TODO: raise an error.
526 break;
527 }
528 ConstantFieldInfo field = (ConstantFieldInfo)ci;
529 String className = field.getParentClass().getClassName();
530 if (mEnclosingClassName.equals(className)) {
531 className = null;
532 }
533 String fieldName = field.getNameAndType().getName();
534 Descriptor type = field.getNameAndType().getType();
535 if (!(type instanceof TypeDescriptor)) {
536 // TODO: raise an error.
537 break;
538 }
539
540 // Implementation note: Although it may seem convenient if the
541 // CodeAssembler had methods that accepted ConstantFieldInfo
542 // objects as parameters, it would cause problems because
543 // ConstantPools are not portable between ClassFiles.
544
545 switch (opcode) {
546 case Opcode.GETSTATIC:
547 if (className == null) {
548 assembler.loadStaticField
549 (fieldName, (TypeDescriptor)type);
550 }
551 else {
552 assembler.loadStaticField
553 (className, fieldName, (TypeDescriptor)type);
554 }
555 break;
556 case Opcode.PUTSTATIC:
557 if (className == null) {
558 assembler.storeStaticField
559 (fieldName, (TypeDescriptor)type);
560 }
561 else {
562 assembler.storeStaticField
563 (className, fieldName, (TypeDescriptor)type);
564 }
565 break;
566 case Opcode.GETFIELD:
567 if (className == null) {
568 assembler.loadField
569 (fieldName, (TypeDescriptor)type);
570 }
571 else {
572 assembler.loadField
573 (className, fieldName, (TypeDescriptor)type);
574 }
575 break;
576 case Opcode.PUTFIELD:
577 if (className == null) {
578 assembler.storeField
579 (fieldName, (TypeDescriptor)type);
580 }
581 else {
582 assembler.storeField
583 (className, fieldName, (TypeDescriptor)type);
584 }
585 break;
586 }
587 break;
588
589 case Opcode.INVOKEVIRTUAL:
590 case Opcode.INVOKESPECIAL:
591 case Opcode.INVOKESTATIC:
592 case Opcode.INVOKEINTERFACE:
593 ci = mCp.getConstant(readUnsignedShort());
594
595 ConstantNameAndTypeInfo nameAndType;
596
597 if (opcode == Opcode.INVOKEINTERFACE) {
598 // Read and ignore nargs and padding byte.
599 readShort();
600 if (!(ci instanceof ConstantInterfaceMethodInfo)) {
601 // TODO: raise an error.
602 break;
603 }
604 ConstantInterfaceMethodInfo method =
605 (ConstantInterfaceMethodInfo)ci;
606 className = method.getParentClass().getClassName();
607 nameAndType = method.getNameAndType();
608 }
609 else {
610 if (!(ci instanceof ConstantMethodInfo)) {
611 // TODO: raise an error.
612 break;
613 }
614 ConstantMethodInfo method =
615 (ConstantMethodInfo)ci;
616 className = method.getParentClass().getClassName();
617 if (mEnclosingClassName.equals(className)) {
618 className = null;
619 }
620 nameAndType = method.getNameAndType();
621 }
622
623 String methodName = nameAndType.getName();
624 type = nameAndType.getType();
625 if (!(type instanceof MethodDescriptor)) {
626 // TODO: raise an error.
627 break;
628 }
629 TypeDescriptor ret = ((MethodDescriptor)type).getReturnType();
630 if (ret.getClassArg() == void.class) {
631 ret = null;
632 }
633 TypeDescriptor[] params =
634 ((MethodDescriptor)type).getParameterTypes();
635 if (params.length == 0) {
636 params = null;
637 }
638
639 switch (opcode) {
640 case Opcode.INVOKEVIRTUAL:
641 if (className == null) {
642 assembler.invokeVirtual(methodName, ret, params);
643 }
644 else {
645 assembler.invokeVirtual
646 (className, methodName, ret, params);
647 }
648 break;
649 case Opcode.INVOKESPECIAL:
650 if ("<init>".equals(methodName)) {
651 if (className == null) {
652 assembler.invokeConstructor(params);
653 }
654 else {
655 if (className.equals(mSuperClassName)) {
656 assembler.invokeSuperConstructor(params);
657 }
658 else {
659 assembler.invokeConstructor(className, params);
660 }
661 }
662 }
663 else {
664 if (className == null) {
665 assembler.invokePrivate(methodName, ret, params);
666 }
667 else {
668 assembler.invokeSuper
669 (className, methodName, ret, params);
670 }
671 }
672 break;
673 case Opcode.INVOKESTATIC:
674 if (className == null) {
675 assembler.invokeStatic(methodName, ret, params);
676 }
677 else {
678 assembler.invokeStatic
679 (className, methodName, ret, params);
680 }
681 break;
682 case Opcode.INVOKEINTERFACE:
683 assembler.invokeInterface
684 (className, methodName, ret, params);
685 break;
686 }
687 break;
688
689 // End opcodes that load a constant from the constant pool.
690
691 // Opcodes that load or store local variables...
692
693 case Opcode.ILOAD: case Opcode.ISTORE:
694 case Opcode.LLOAD: case Opcode.LSTORE:
695 case Opcode.FLOAD: case Opcode.FSTORE:
696 case Opcode.DLOAD: case Opcode.DSTORE:
697 case Opcode.ALOAD: case Opcode.ASTORE:
698 case Opcode.ILOAD_0: case Opcode.ISTORE_0:
699 case Opcode.ILOAD_1: case Opcode.ISTORE_1:
700 case Opcode.ILOAD_2: case Opcode.ISTORE_2:
701 case Opcode.ILOAD_3: case Opcode.ISTORE_3:
702 case Opcode.LLOAD_0: case Opcode.LSTORE_0:
703 case Opcode.LLOAD_1: case Opcode.LSTORE_1:
704 case Opcode.LLOAD_2: case Opcode.LSTORE_2:
705 case Opcode.LLOAD_3: case Opcode.LSTORE_3:
706 case Opcode.FLOAD_0: case Opcode.FSTORE_0:
707 case Opcode.FLOAD_1: case Opcode.FSTORE_1:
708 case Opcode.FLOAD_2: case Opcode.FSTORE_2:
709 case Opcode.FLOAD_3: case Opcode.FSTORE_3:
710 case Opcode.DLOAD_0: case Opcode.DSTORE_0:
711 case Opcode.DLOAD_1: case Opcode.DSTORE_1:
712 case Opcode.DLOAD_2: case Opcode.DSTORE_2:
713 case Opcode.DLOAD_3: case Opcode.DSTORE_3:
714 case Opcode.ALOAD_0: case Opcode.ASTORE_0:
715 case Opcode.ALOAD_1: case Opcode.ASTORE_1:
716 case Opcode.ALOAD_2: case Opcode.ASTORE_2:
717 case Opcode.ALOAD_3: case Opcode.ASTORE_3:
718 switch (opcode) {
719 case Opcode.ILOAD: case Opcode.ISTORE:
720 index = readUnsignedByte();
721 clazz = int.class;
722 break;
723 case Opcode.LLOAD: case Opcode.LSTORE:
724 index = readUnsignedByte();
725 clazz = long.class;
726 break;
727 case Opcode.FLOAD: case Opcode.FSTORE:
728 index = readUnsignedByte();
729 clazz = float.class;
730 break;
731 case Opcode.DLOAD: case Opcode.DSTORE:
732 index = readUnsignedByte();
733 clazz = double.class;
734 break;
735 case Opcode.ALOAD: case Opcode.ASTORE:
736 index = readUnsignedByte();
737 clazz = Object.class;
738 break;
739 case Opcode.ILOAD_0: case Opcode.ISTORE_0:
740 index = 0;
741 clazz = int.class;
742 break;
743 case Opcode.ILOAD_1: case Opcode.ISTORE_1:
744 index = 1;
745 clazz = int.class;
746 break;
747 case Opcode.ILOAD_2: case Opcode.ISTORE_2:
748 index = 2;
749 clazz = int.class;
750 break;
751 case Opcode.ILOAD_3: case Opcode.ISTORE_3:
752 index = 3;
753 clazz = int.class;
754 break;
755 case Opcode.LLOAD_0: case Opcode.LSTORE_0:
756 index = 0;
757 clazz = long.class;
758 break;
759 case Opcode.LLOAD_1: case Opcode.LSTORE_1:
760 index = 1;
761 clazz = long.class;
762 break;
763 case Opcode.LLOAD_2: case Opcode.LSTORE_2:
764 index = 2;
765 clazz = long.class;
766 break;
767 case Opcode.LLOAD_3: case Opcode.LSTORE_3:
768 index = 3;
769 clazz = long.class;
770 break;
771 case Opcode.FLOAD_0: case Opcode.FSTORE_0:
772 index = 0;
773 clazz = float.class;
774 break;
775 case Opcode.FLOAD_1: case Opcode.FSTORE_1:
776 index = 1;
777 clazz = float.class;
778 break;
779 case Opcode.FLOAD_2: case Opcode.FSTORE_2:
780 index = 2;
781 clazz = float.class;
782 break;
783 case Opcode.FLOAD_3: case Opcode.FSTORE_3:
784 index = 3;
785 clazz = float.class;
786 break;
787 case Opcode.DLOAD_0: case Opcode.DSTORE_0:
788 index = 0;
789 clazz = double.class;
790 break;
791 case Opcode.DLOAD_1: case Opcode.DSTORE_1:
792 index = 1;
793 clazz = double.class;
794 break;
795 case Opcode.DLOAD_2: case Opcode.DSTORE_2:
796 index = 2;
797 clazz = double.class;
798 break;
799 case Opcode.DLOAD_3: case Opcode.DSTORE_3:
800 index = 3;
801 clazz = double.class;
802 break;
803 case Opcode.ALOAD_0: case Opcode.ASTORE_0:
804 index = 0;
805 clazz = Object.class;
806 break;
807 case Opcode.ALOAD_1: case Opcode.ASTORE_1:
808 index = 1;
809 clazz = Object.class;
810 break;
811 case Opcode.ALOAD_2: case Opcode.ASTORE_2:
812 index = 2;
813 clazz = Object.class;
814 break;
815 case Opcode.ALOAD_3: case Opcode.ASTORE_3:
816 index = 3;
817 clazz = Object.class;
818 break;
819 default:
820 index = 0;
821 clazz = null;
822 break;
823 }
824
825 switch (opcode) {
826 case Opcode.ILOAD:
827 case Opcode.LLOAD:
828 case Opcode.FLOAD:
829 case Opcode.DLOAD:
830 case Opcode.ALOAD:
831 case Opcode.ILOAD_0:
832 case Opcode.ILOAD_1:
833 case Opcode.ILOAD_2:
834 case Opcode.ILOAD_3:
835 case Opcode.LLOAD_0:
836 case Opcode.LLOAD_1:
837 case Opcode.LLOAD_2:
838 case Opcode.LLOAD_3:
839 case Opcode.FLOAD_0:
840 case Opcode.FLOAD_1:
841 case Opcode.FLOAD_2:
842 case Opcode.FLOAD_3:
843 case Opcode.DLOAD_0:
844 case Opcode.DLOAD_1:
845 case Opcode.DLOAD_2:
846 case Opcode.DLOAD_3:
847 case Opcode.ALOAD_0:
848 case Opcode.ALOAD_1:
849 case Opcode.ALOAD_2:
850 case Opcode.ALOAD_3:
851 if (index == 0 && mHasThis) {
852 assembler.loadThis();
853 }
854 else {
855 assembler.loadLocal(getLocalVariable(index, clazz));
856 }
857 break;
858 case Opcode.ISTORE:
859 case Opcode.LSTORE:
860 case Opcode.FSTORE:
861 case Opcode.DSTORE:
862 case Opcode.ASTORE:
863 case Opcode.ISTORE_0:
864 case Opcode.ISTORE_1:
865 case Opcode.ISTORE_2:
866 case Opcode.ISTORE_3:
867 case Opcode.LSTORE_0:
868 case Opcode.LSTORE_1:
869 case Opcode.LSTORE_2:
870 case Opcode.LSTORE_3:
871 case Opcode.FSTORE_0:
872 case Opcode.FSTORE_1:
873 case Opcode.FSTORE_2:
874 case Opcode.FSTORE_3:
875 case Opcode.DSTORE_0:
876 case Opcode.DSTORE_1:
877 case Opcode.DSTORE_2:
878 case Opcode.DSTORE_3:
879 case Opcode.ASTORE_0:
880 case Opcode.ASTORE_1:
881 case Opcode.ASTORE_2:
882 case Opcode.ASTORE_3:
883 if (index == 0 && mHasThis) {
884 // The "this" reference just got blown away.
885 mHasThis = false;
886 }
887 assembler.storeLocal(getLocalVariable(index, clazz));
888 break;
889 }
890 break;
891
892 case Opcode.RET:
893 LocalVariable local = getLocalVariable
894 (readUnsignedByte(), Object.class);
895 assembler.ret(local);
896 break;
897
898 case Opcode.IINC:
899 local = getLocalVariable(readUnsignedByte(), int.class);
900 assembler.integerIncrement(local, readByte());
901 break;
902
903 // End opcodes that load or store local variables.
904
905 // Opcodes that branch to another address.
906
907 case Opcode.GOTO:
908 loc = getLabel(mAddress + readShort());
909 assembler.branch(loc);
910 break;
911 case Opcode.JSR:
912 loc = getLabel(mAddress + readShort());
913 assembler.jsr(loc);
914 break;
915 case Opcode.GOTO_W:
916 loc = getLabel(mAddress + readInt());
917 assembler.branch(loc);
918 break;
919 case Opcode.JSR_W:
920 loc = getLabel(mAddress + readInt());
921 assembler.jsr(loc);
922 break;
923
924 case Opcode.IFNULL:
925 loc = getLabel(mAddress + readShort());
926 assembler.ifNullBranch(loc, true);
927 break;
928 case Opcode.IFNONNULL:
929 loc = getLabel(mAddress + readShort());
930 assembler.ifNullBranch(loc, false);
931 break;
932
933 case Opcode.IF_ACMPEQ:
934 loc = getLabel(mAddress + readShort());
935 assembler.ifEqualBranch(loc, true);
936 break;
937 case Opcode.IF_ACMPNE:
938 loc = getLabel(mAddress + readShort());
939 assembler.ifEqualBranch(loc, false);
940 break;
941
942 case Opcode.IFEQ:
943 case Opcode.IFNE:
944 case Opcode.IFLT:
945 case Opcode.IFGE:
946 case Opcode.IFGT:
947 case Opcode.IFLE:
948 loc = getLabel(mAddress + readShort());
949 String choice;
950 switch (opcode) {
951 case Opcode.IFEQ:
952 choice = "==";
953 break;
954 case Opcode.IFNE:
955 choice = "!=";
956 break;
957 case Opcode.IFLT:
958 choice = "<";
959 break;
960 case Opcode.IFGE:
961 choice = ">=";
962 break;
963 case Opcode.IFGT:
964 choice = ">";
965 break;
966 case Opcode.IFLE:
967 choice = "<=";
968 break;
969 default:
970 choice = null;
971 break;
972 }
973 assembler.ifZeroComparisonBranch(loc, choice);
974 break;
975
976 case Opcode.IF_ICMPEQ:
977 case Opcode.IF_ICMPNE:
978 case Opcode.IF_ICMPLT:
979 case Opcode.IF_ICMPGE:
980 case Opcode.IF_ICMPGT:
981 case Opcode.IF_ICMPLE:
982 loc = getLabel(mAddress + readShort());
983 switch (opcode) {
984 case Opcode.IF_ICMPEQ:
985 choice = "==";
986 break;
987 case Opcode.IF_ICMPNE:
988 choice = "!=";
989 break;
990 case Opcode.IF_ICMPLT:
991 choice = "<";
992 break;
993 case Opcode.IF_ICMPGE:
994 choice = ">=";
995 break;
996 case Opcode.IF_ICMPGT:
997 choice = ">";
998 break;
999 case Opcode.IF_ICMPLE:
1000 choice = "<=";
1001 break;
1002 default:
1003 choice = null;
1004 break;
1005 }
1006 assembler.ifComparisonBranch(loc, choice);
1007 break;
1008
1009 // End opcodes that branch to another address.
1010
1011 // Miscellaneous opcodes...
1012
1013 case Opcode.BIPUSH:
1014 assembler.loadConstant(readByte());
1015 break;
1016 case Opcode.SIPUSH:
1017 assembler.loadConstant(readShort());
1018 break;
1019
1020 case Opcode.NEWARRAY:
1021 int atype = readByte();
1022 clazz = null;
1023 switch (atype) {
1024 case 4: // T_BOOLEAN
1025 clazz = boolean.class;
1026 break;
1027 case 5: // T_CHAR
1028 clazz = char.class;
1029 break;
1030 case 6: // T_FLOAT
1031 clazz = float.class;
1032 break;
1033 case 7: // T_DOUBLE
1034 clazz = double.class;
1035 break;
1036 case 8: // T_BYTE
1037 clazz = byte.class;
1038 break;
1039 case 9: // T_SHORT
1040 clazz = short.class;
1041 break;
1042 case 10: // T_INT
1043 clazz = int.class;
1044 break;
1045 case 11: // T_LONG
1046 clazz = long.class;
1047 break;
1048 }
1049
1050 if (clazz == null) {
1051 // TODO: raise an error.
1052 break;
1053 }
1054
1055 assembler.newObject
1056 (new TypeDescriptor(new TypeDescriptor(clazz), 1));
1057 break;
1058
1059 case Opcode.TABLESWITCH:
1060 case Opcode.LOOKUPSWITCH:
1061 int opcodeAddress = mAddress;
1062 // Read padding until address is 32 bit word aligned.
1063 while (((mAddress + 1) & 3) != 0) {
1064 ++mAddress;
1065 }
1066 Location defaultLocation = getLabel(opcodeAddress + readInt());
1067 int[] cases;
1068 Location[] locations;
1069
1070 if (opcode == Opcode.TABLESWITCH) {
1071 int lowValue = readInt();
1072 int highValue = readInt();
1073 int caseCount = highValue - lowValue + 1;
1074 try {
1075 cases = new int[caseCount];
1076 }
1077 catch (NegativeArraySizeException e) {
1078 // TODO: raise an error.
1079 break;
1080 }
1081 locations = new Location[caseCount];
1082 for (int i=0; i<caseCount; i++) {
1083 cases[i] = lowValue + i;
1084 locations[i] = getLabel(opcodeAddress + readInt());
1085 }
1086 }
1087 else {
1088 int caseCount = readInt();
1089 try {
1090 cases = new int[caseCount];
1091 }
1092 catch (NegativeArraySizeException e) {
1093 // TODO: raise an error.
1094 break;
1095 }
1096 locations = new Location[caseCount];
1097 for (int i=0; i<caseCount; i++) {
1098 cases[i] = readInt();
1099 locations[i] = getLabel(opcodeAddress + readInt());
1100 }
1101 }
1102
1103 assembler.switchBranch(cases, locations, defaultLocation);
1104 break;
1105
1106 case Opcode.WIDE:
1107 opcode = mByteCodes[++mAddress];
1108 switch (opcode) {
1109
1110 default:
1111 // TODO: raise an error.
1112 break;
1113
1114 case Opcode.ILOAD: case Opcode.ISTORE:
1115 case Opcode.LLOAD: case Opcode.LSTORE:
1116 case Opcode.FLOAD: case Opcode.FSTORE:
1117 case Opcode.DLOAD: case Opcode.DSTORE:
1118 case Opcode.ALOAD: case Opcode.ASTORE:
1119
1120 switch (opcode) {
1121 case Opcode.ILOAD: case Opcode.ISTORE:
1122 clazz = int.class;
1123 break;
1124 case Opcode.LLOAD: case Opcode.LSTORE:
1125 clazz = long.class;
1126 break;
1127 case Opcode.FLOAD: case Opcode.FSTORE:
1128 clazz = float.class;
1129 break;
1130 case Opcode.DLOAD: case Opcode.DSTORE:
1131 clazz = double.class;
1132 break;
1133 case Opcode.ALOAD: case Opcode.ASTORE:
1134 clazz = Object.class;
1135 break;
1136 default:
1137 clazz = null;
1138 break;
1139 }
1140
1141 index = readUnsignedShort();
1142
1143 switch (opcode) {
1144 case Opcode.ILOAD:
1145 case Opcode.LLOAD:
1146 case Opcode.FLOAD:
1147 case Opcode.DLOAD:
1148 case Opcode.ALOAD:
1149 if (index == 0 && mHasThis) {
1150 assembler.loadThis();
1151 }
1152 else {
1153 assembler.loadLocal
1154 (getLocalVariable(index, clazz));
1155 }
1156 break;
1157 case Opcode.ISTORE:
1158 case Opcode.LSTORE:
1159 case Opcode.FSTORE:
1160 case Opcode.DSTORE:
1161 case Opcode.ASTORE:
1162 if (index == 0 && mHasThis) {
1163 // The "this" reference just got blown away.
1164 mHasThis = false;
1165 }
1166 assembler.storeLocal(getLocalVariable(index, clazz));
1167 break;
1168 }
1169 break;
1170
1171 case Opcode.RET:
1172 local = getLocalVariable
1173 (readUnsignedShort(), Object.class);
1174 assembler.ret(local);
1175 break;
1176
1177 case Opcode.IINC:
1178 local = getLocalVariable(readUnsignedShort(), int.class);
1179 assembler.integerIncrement(local, readShort());
1180 break;
1181 }
1182
1183 break;
1184 } // end huge switch
1185 } // end for loop
1186 }
1187
1188 private void gatherLabels() {
1189 mLabels = new HashMap();
1190 mCatchLocations = new HashMap(mExceptionHandlers.length * 2 + 1);
1191 Integer labelKey;
1192
1193 // Gather labels for any exception handlers.
1194 for (int i = mExceptionHandlers.length - 1; i >= 0; i--) {
1195 ExceptionHandler handler = mExceptionHandlers[i];
1196 labelKey = new Integer(handler.getStartLocation().getLocation());
1197 mLabels.put(labelKey, labelKey);
1198 labelKey = new Integer(handler.getEndLocation().getLocation());
1199 mLabels.put(labelKey, labelKey);
1200 labelKey = new Integer(handler.getCatchLocation().getLocation());
1201 List list = (List)mCatchLocations.get(labelKey);
1202 if (list == null) {
1203 list = new ArrayList(2);
1204 mCatchLocations.put(labelKey, list);
1205 }
1206 list.add(handler);
1207 }
1208
1209 // Now gather labels that occur within byte code.
1210 for (mAddress = 0; mAddress < mByteCodes.length; mAddress++) {
1211 byte opcode = mByteCodes[mAddress];
1212
1213 switch (opcode) {
1214
1215 default:
1216 // TODO: raise an error.
1217 break;
1218
1219 // Opcodes that use labels.
1220
1221 case Opcode.GOTO:
1222 case Opcode.JSR:
1223 case Opcode.IFNULL:
1224 case Opcode.IFNONNULL:
1225 case Opcode.IF_ACMPEQ:
1226 case Opcode.IF_ACMPNE:
1227 case Opcode.IFEQ:
1228 case Opcode.IFNE:
1229 case Opcode.IFLT:
1230 case Opcode.IFGE:
1231 case Opcode.IFGT:
1232 case Opcode.IFLE:
1233 case Opcode.IF_ICMPEQ:
1234 case Opcode.IF_ICMPNE:
1235 case Opcode.IF_ICMPLT:
1236 case Opcode.IF_ICMPGE:
1237 case Opcode.IF_ICMPGT:
1238 case Opcode.IF_ICMPLE:
1239 labelKey = new Integer(mAddress + readShort());
1240 mLabels.put(labelKey, labelKey);
1241 break;
1242
1243 case Opcode.GOTO_W:
1244 case Opcode.JSR_W:
1245 labelKey = new Integer(mAddress + readInt());
1246 mLabels.put(labelKey, labelKey);
1247 break;
1248
1249 case Opcode.TABLESWITCH:
1250 case Opcode.LOOKUPSWITCH:
1251 int opcodeAddress = mAddress;
1252 // Read padding until address is 32 bit word aligned.
1253 while (((mAddress + 1) & 3) != 0) {
1254 ++mAddress;
1255 }
1256
1257 // Read the default location.
1258 labelKey = new Integer(opcodeAddress + readInt());
1259 mLabels.put(labelKey, labelKey);
1260
1261 if (opcode == Opcode.TABLESWITCH) {
1262 int lowValue = readInt();
1263 int highValue = readInt();
1264 int caseCount = highValue - lowValue + 1;
1265
1266 for (int i=0; i<caseCount; i++) {
1267 // Read the branch location.
1268 labelKey = new Integer(opcodeAddress + readInt());
1269 mLabels.put(labelKey, labelKey);
1270 }
1271 }
1272 else {
1273 int caseCount = readInt();
1274
1275 for (int i=0; i<caseCount; i++) {
1276 // Skip the case value.
1277 mAddress += 4;
1278 // Read the branch location.
1279 labelKey = new Integer(opcodeAddress + readInt());
1280 mLabels.put(labelKey, labelKey);
1281 }
1282 }
1283 break;
1284
1285 // All other operations are skipped. The amount to skip
1286 // depends on the operand size.
1287
1288 // Opcodes with no operands...
1289
1290 case Opcode.NOP:
1291 case Opcode.BREAKPOINT:
1292 case Opcode.ACONST_NULL:
1293 case Opcode.ICONST_M1:
1294 case Opcode.ICONST_0:
1295 case Opcode.ICONST_1:
1296 case Opcode.ICONST_2:
1297 case Opcode.ICONST_3:
1298 case Opcode.ICONST_4:
1299 case Opcode.ICONST_5:
1300 case Opcode.LCONST_0:
1301 case Opcode.LCONST_1:
1302 case Opcode.FCONST_0:
1303 case Opcode.FCONST_1:
1304 case Opcode.FCONST_2:
1305 case Opcode.DCONST_0:
1306 case Opcode.DCONST_1:
1307 case Opcode.POP:
1308 case Opcode.POP2:
1309 case Opcode.DUP:
1310 case Opcode.DUP_X1:
1311 case Opcode.DUP_X2:
1312 case Opcode.DUP2:
1313 case Opcode.DUP2_X1:
1314 case Opcode.DUP2_X2:
1315 case Opcode.SWAP:
1316 case Opcode.IADD: case Opcode.LADD:
1317 case Opcode.FADD: case Opcode.DADD:
1318 case Opcode.ISUB: case Opcode.LSUB:
1319 case Opcode.FSUB: case Opcode.DSUB:
1320 case Opcode.IMUL: case Opcode.LMUL:
1321 case Opcode.FMUL: case Opcode.DMUL:
1322 case Opcode.IDIV: case Opcode.LDIV:
1323 case Opcode.FDIV: case Opcode.DDIV:
1324 case Opcode.IREM: case Opcode.LREM:
1325 case Opcode.FREM: case Opcode.DREM:
1326 case Opcode.INEG: case Opcode.LNEG:
1327 case Opcode.FNEG: case Opcode.DNEG:
1328 case Opcode.ISHL: case Opcode.LSHL:
1329 case Opcode.ISHR: case Opcode.LSHR:
1330 case Opcode.IUSHR: case Opcode.LUSHR:
1331 case Opcode.IAND: case Opcode.LAND:
1332 case Opcode.IOR: case Opcode.LOR:
1333 case Opcode.IXOR: case Opcode.LXOR:
1334 case Opcode.FCMPL: case Opcode.DCMPL:
1335 case Opcode.FCMPG: case Opcode.DCMPG:
1336 case Opcode.LCMP:
1337 case Opcode.I2L:
1338 case Opcode.I2F:
1339 case Opcode.I2D:
1340 case Opcode.L2I:
1341 case Opcode.L2F:
1342 case Opcode.L2D:
1343 case Opcode.F2I:
1344 case Opcode.F2L:
1345 case Opcode.F2D:
1346 case Opcode.D2I:
1347 case Opcode.D2L:
1348 case Opcode.D2F:
1349 case Opcode.I2B:
1350 case Opcode.I2C:
1351 case Opcode.I2S:
1352 case Opcode.IRETURN:
1353 case Opcode.LRETURN:
1354 case Opcode.FRETURN:
1355 case Opcode.DRETURN:
1356 case Opcode.ARETURN:
1357 case Opcode.RETURN:
1358 case Opcode.IALOAD:
1359 case Opcode.LALOAD:
1360 case Opcode.FALOAD:
1361 case Opcode.DALOAD:
1362 case Opcode.AALOAD:
1363 case Opcode.BALOAD:
1364 case Opcode.CALOAD:
1365 case Opcode.SALOAD:
1366 case Opcode.IASTORE:
1367 case Opcode.LASTORE:
1368 case Opcode.FASTORE:
1369 case Opcode.DASTORE:
1370 case Opcode.AASTORE:
1371 case Opcode.BASTORE:
1372 case Opcode.CASTORE:
1373 case Opcode.SASTORE:
1374 case Opcode.ARRAYLENGTH:
1375 case Opcode.ATHROW:
1376 case Opcode.MONITORENTER:
1377 case Opcode.MONITOREXIT:
1378 case Opcode.ILOAD_0: case Opcode.ISTORE_0:
1379 case Opcode.ILOAD_1: case Opcode.ISTORE_1:
1380 case Opcode.ILOAD_2: case Opcode.ISTORE_2:
1381 case Opcode.ILOAD_3: case Opcode.ISTORE_3:
1382 case Opcode.LLOAD_0: case Opcode.LSTORE_0:
1383 case Opcode.LLOAD_1: case Opcode.LSTORE_1:
1384 case Opcode.LLOAD_2: case Opcode.LSTORE_2:
1385 case Opcode.LLOAD_3: case Opcode.LSTORE_3:
1386 case Opcode.FLOAD_0: case Opcode.FSTORE_0:
1387 case Opcode.FLOAD_1: case Opcode.FSTORE_1:
1388 case Opcode.FLOAD_2: case Opcode.FSTORE_2:
1389 case Opcode.FLOAD_3: case Opcode.FSTORE_3:
1390 case Opcode.DLOAD_0: case Opcode.DSTORE_0:
1391 case Opcode.DLOAD_1: case Opcode.DSTORE_1:
1392 case Opcode.DLOAD_2: case Opcode.DSTORE_2:
1393 case Opcode.DLOAD_3: case Opcode.DSTORE_3:
1394 case Opcode.ALOAD_0: case Opcode.ASTORE_0:
1395 case Opcode.ALOAD_1: case Opcode.ASTORE_1:
1396 case Opcode.ALOAD_2: case Opcode.ASTORE_2:
1397 case Opcode.ALOAD_3: case Opcode.ASTORE_3:
1398 break;
1399
1400 // Opcodes with one operand byte...
1401
1402 case Opcode.LDC:
1403 case Opcode.ILOAD: case Opcode.ISTORE:
1404 case Opcode.LLOAD: case Opcode.LSTORE:
1405 case Opcode.FLOAD: case Opcode.FSTORE:
1406 case Opcode.DLOAD: case Opcode.DSTORE:
1407 case Opcode.ALOAD: case Opcode.ASTORE:
1408 case Opcode.RET:
1409 case Opcode.IINC:
1410 case Opcode.BIPUSH:
1411 case Opcode.NEWARRAY:
1412 mAddress += 1;
1413 break;
1414
1415 // Opcodes with two operand bytes...
1416
1417 case Opcode.LDC_W:
1418 case Opcode.LDC2_W:
1419 case Opcode.NEW:
1420 case Opcode.ANEWARRAY:
1421 case Opcode.CHECKCAST:
1422 case Opcode.INSTANCEOF:
1423 case Opcode.GETSTATIC:
1424 case Opcode.PUTSTATIC:
1425 case Opcode.GETFIELD:
1426 case Opcode.PUTFIELD:
1427 case Opcode.INVOKEVIRTUAL:
1428 case Opcode.INVOKESPECIAL:
1429 case Opcode.INVOKESTATIC:
1430 case Opcode.SIPUSH:
1431 mAddress += 2;
1432 break;
1433
1434 // Opcodes with three operand bytes...
1435
1436 case Opcode.MULTIANEWARRAY:
1437 mAddress += 3;
1438 break;
1439
1440 // Opcodes with four operand bytes...
1441
1442 case Opcode.INVOKEINTERFACE:
1443 mAddress += 4;
1444 break;
1445
1446 // Wide opcode has a variable sized operand.
1447
1448 case Opcode.WIDE:
1449 opcode = mByteCodes[++mAddress];
1450 mAddress += 2;
1451 if (opcode == Opcode.IINC) {
1452 mAddress += 2;
1453 }
1454 break;
1455 } // end huge switch
1456 } // end for loop
1457 }
1458
1459 private int readByte() {
1460 return mByteCodes[++mAddress];
1461 }
1462
1463 private int readUnsignedByte() {
1464 return mByteCodes[++mAddress] & 0xff;
1465 }
1466
1467 private int readShort() {
1468 return (mByteCodes[++mAddress] << 8) | (mByteCodes[++mAddress] & 0xff);
1469 }
1470
1471 private int readUnsignedShort() {
1472 return
1473 ((mByteCodes[++mAddress] & 0xff) << 8) |
1474 ((mByteCodes[++mAddress] & 0xff) << 0);
1475 }
1476
1477 private int readInt() {
1478 return
1479 (mByteCodes[++mAddress] << 24) |
1480 ((mByteCodes[++mAddress] & 0xff) << 16) |
1481 ((mByteCodes[++mAddress] & 0xff) << 8) |
1482 ((mByteCodes[++mAddress] & 0xff) << 0);
1483 }
1484
1485 private LocalVariable getLocalVariable(int index, Class typeHint) {
1486 TypeDescriptor type = new TypeDescriptor(typeHint);
1487 LocalVariable local;
1488
1489 if (index >= mLocals.size()) {
1490 mLocals.setSize(index + 1);
1491 local = null;
1492 }
1493 else {
1494 local = (LocalVariable)mLocals.elementAt(index);
1495 if (local != null) {
1496 TypeDescriptor localType = local.getType();
1497 Class typeClass = type.getClassArg();
1498 Class localTypeClass = localType.getClassArg();
1499
1500 if (typeClass != null && !typeClass.isPrimitive()) {
1501 typeClass = null;
1502 }
1503
1504 if (localTypeClass != null && !localTypeClass.isPrimitive()) {
1505 localTypeClass = null;
1506 }
1507
1508 if (typeClass == null) {
1509 if (localTypeClass == null) {
1510 // Both types must represent objects. This is ok.
1511 }
1512 else {
1513 // Requesting object type, but existing is primitive.
1514 local = null;
1515 }
1516 }
1517 else {
1518 if (localTypeClass == null) {
1519 // Requesting primitive type, but existing is object.
1520 local = null;
1521 }
1522 else {
1523 // Primitive types must exactly match.
1524 if (typeClass != localTypeClass) {
1525 local = null;
1526 }
1527 }
1528 }
1529 }
1530 }
1531
1532 if (local == null) {
1533 local = mAssembler.createLocalVariable(null, type);
1534 mLocals.setElementAt(local, index);
1535 }
1536
1537 return local;
1538 }
1539
1540 private void locateLabel() {
1541 Integer labelKey = new Integer(mAddress);
1542 Object labelValue = mLabels.get(labelKey);
1543 if (labelValue != null) {
1544 if (labelValue instanceof Label) {
1545 ((Label)labelValue).setLocation();
1546 }
1547 else {
1548 labelValue = mAssembler.createLabel().setLocation();
1549 mLabels.put(labelKey, labelValue);
1550 }
1551 }
1552
1553 List handlers = (List)mCatchLocations.get(labelKey);
1554
1555 if (handlers != null) {
1556 for (int i=0; i<handlers.size(); i++) {
1557 ExceptionHandler handler = (ExceptionHandler)handlers.get(i);
1558 Label start =
1559 getLabel(handler.getStartLocation().getLocation());
1560 Label end =
1561 getLabel(handler.getEndLocation().getLocation());
1562 String catchClassName;
1563 if (handler.getCatchType() == null) {
1564 catchClassName = null;
1565 }
1566 else {
1567 catchClassName = handler.getCatchType().getClassName();
1568 }
1569 mAssembler.exceptionHandler(start, end, catchClassName);
1570 }
1571 }
1572 }
1573
1574 private Label getLabel(int address) {
1575 Integer labelKey = new Integer(address);
1576 Object labelValue = mLabels.get(labelKey);
1577 // labelValue will never be null unless gatherLabels is broken.
1578 if (!(labelValue instanceof Label)) {
1579 labelValue = mAssembler.createLabel();
1580 mLabels.put(labelKey, labelValue);
1581 }
1582 return (Label)labelValue;
1583 }
1584 }