001: /***
002: * ASM: a very small and fast Java bytecode manipulation framework
003: * Copyright (c) 2000-2005 INRIA, France Telecom
004: * All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: * 1. Redistributions of source code must retain the above copyright
010: * notice, this list of conditions and the following disclaimer.
011: * 2. Redistributions in binary form must reproduce the above copyright
012: * notice, this list of conditions and the following disclaimer in the
013: * documentation and/or other materials provided with the distribution.
014: * 3. Neither the name of the copyright holders nor the names of its
015: * contributors may be used to endorse or promote products derived from
016: * this software without specific prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
021: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
022: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
023: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
024: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
025: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
026: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
027: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
028: * THE POSSIBILITY OF SUCH DAMAGE.
029: */package org.objectweb.asm.commons;
030:
031: import java.util.ArrayList;
032: import java.util.HashMap;
033: import java.util.List;
034: import java.util.Map;
035:
036: import org.objectweb.asm.Label;
037: import org.objectweb.asm.MethodAdapter;
038: import org.objectweb.asm.MethodVisitor;
039: import org.objectweb.asm.Opcodes;
040: import org.objectweb.asm.Type;
041:
042: /**
043: * A {@link MethodAdapter} that keeps track of stack map frame changes between
044: * {@link #visitFrame(int, int, Object[], int, Object[]) visitFrame} calls. This
045: * adapter must be used with the
046: * {@link org.objectweb.asm.ClassReader#EXPAND_FRAMES} option. Each visit<i>XXX</i>
047: * instruction delegates to the next visitor in the chain, if any, and then
048: * simulates the effect of this instruction on the stack map frame, represented
049: * by {@link #locals} and {@link #stack}. The next visitor in the chain can get
050: * the state of the stack map frame <i>before</i> each instruction by reading
051: * the value of these fields in its visit<i>XXX</i> methods (this requires a
052: * reference to the AnalyzerAdapter that is before it in the chain).
053: *
054: * @author Eric Bruneton
055: */
056: @SuppressWarnings("unchecked")
057: public class AnalyzerAdapter extends MethodAdapter {
058:
059: /**
060: * <code>List</code> of the local variable slots for current execution
061: * frame. Primitive types are represented by {@link Opcodes#TOP},
062: * {@link Opcodes#INTEGER}, {@link Opcodes#FLOAT}, {@link Opcodes#LONG},
063: * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or
064: * {@link Opcodes#UNINITIALIZED_THIS} (long and double are represented by a
065: * two elements, the second one being TOP). Reference types are represented
066: * by String objects (representing internal names, or type descriptors for
067: * array types), and uninitialized types by Label objects (this label
068: * designates the NEW instruction that created this uninitialized value).
069: * This field is <tt>null</tt> for unreacheable instructions.
070: */
071: public List locals;
072:
073: /**
074: * <code>List</code> of the operand stack slots for current execution
075: * frame. Primitive types are represented by {@link Opcodes#TOP},
076: * {@link Opcodes#INTEGER}, {@link Opcodes#FLOAT}, {@link Opcodes#LONG},
077: * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or
078: * {@link Opcodes#UNINITIALIZED_THIS} (long and double are represented by a
079: * two elements, the second one being TOP). Reference types are represented
080: * by String objects (representing internal names, or type descriptors for
081: * array types), and uninitialized types by Label objects (this label
082: * designates the NEW instruction that created this uninitialized value).
083: * This field is <tt>null</tt> for unreacheable instructions.
084: */
085: public List stack;
086:
087: /**
088: * The labels that designate the next instruction to be visited. May be
089: * <tt>null</tt>.
090: */
091: private List labels;
092:
093: /**
094: * Information about uninitialized types in the current execution frame.
095: * This map associates internal names to Label objects. Each label
096: * designates a NEW instruction that created the currently uninitialized
097: * types, and the associated internal name represents the NEW operand, i.e.
098: * the final, initialized type value.
099: */
100: private Map uninitializedTypes;
101:
102: /**
103: * The maximum stack size of this method.
104: */
105: private int maxStack;
106:
107: /**
108: * The maximum number of local variables of this method.
109: */
110: private int maxLocals;
111:
112: /**
113: * Creates a new {@link AnalyzerAdapter}.
114: *
115: * @param owner the owner's class name.
116: * @param access the method's access flags (see {@link Opcodes}).
117: * @param name the method's name.
118: * @param desc the method's descriptor (see {@link Type Type}).
119: * @param mv the method visitor to which this adapter delegates calls. May
120: * be <tt>null</tt>.
121: */
122: public AnalyzerAdapter(final String owner, final int access,
123: final String name, final String desc, final MethodVisitor mv) {
124: super (mv);
125: locals = new ArrayList();
126: stack = new ArrayList();
127: uninitializedTypes = new HashMap();
128:
129: if ((access & Opcodes.ACC_STATIC) == 0) {
130: if (name.equals("<init>")) {
131: locals.add(Opcodes.UNINITIALIZED_THIS);
132: } else {
133: locals.add(owner);
134: }
135: }
136: Type[] types = Type.getArgumentTypes(desc);
137: for (int i = 0; i < types.length; ++i) {
138: Type type = types[i];
139: switch (type.getSort()) {
140: case Type.BOOLEAN:
141: case Type.CHAR:
142: case Type.BYTE:
143: case Type.SHORT:
144: case Type.INT:
145: locals.add(Opcodes.INTEGER);
146: break;
147: case Type.FLOAT:
148: locals.add(Opcodes.FLOAT);
149: break;
150: case Type.LONG:
151: locals.add(Opcodes.LONG);
152: locals.add(Opcodes.TOP);
153: break;
154: case Type.DOUBLE:
155: locals.add(Opcodes.DOUBLE);
156: locals.add(Opcodes.TOP);
157: break;
158: case Type.ARRAY:
159: locals.add(types[i].getDescriptor());
160: break;
161: // case Type.OBJECT:
162: default:
163: locals.add(types[i].getInternalName());
164: }
165: }
166: }
167:
168: @Override
169: public void visitFrame(final int type, final int nLocal,
170: final Object[] local, final int nStack, final Object[] stack) {
171: if (type != Opcodes.F_NEW) { // uncompressed frame
172: throw new IllegalStateException(
173: "ClassReader.accept() should be called with EXPAND_FRAMES flag");
174: }
175:
176: if (mv != null) {
177: mv.visitFrame(type, nLocal, local, nStack, stack);
178: }
179:
180: if (this .locals != null) {
181: this .locals.clear();
182: this .stack.clear();
183: } else {
184: this .locals = new ArrayList();
185: this .stack = new ArrayList();
186: }
187: visitFrameTypes(nLocal, local, this .locals);
188: visitFrameTypes(nStack, stack, this .stack);
189: maxStack = Math.max(maxStack, this .stack.size());
190: }
191:
192: private void visitFrameTypes(final int n, final Object[] types,
193: final List result) {
194: for (int i = 0; i < n; ++i) {
195: Object type = types[i];
196: result.add(type);
197: if (type == Opcodes.LONG || type == Opcodes.DOUBLE) {
198: result.add(Opcodes.TOP);
199: }
200: }
201: }
202:
203: @Override
204: public void visitInsn(final int opcode) {
205: if (mv != null) {
206: mv.visitInsn(opcode);
207: }
208: execute(opcode, 0, null);
209: if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN)
210: || opcode == Opcodes.ATHROW) {
211: this .locals = null;
212: this .stack = null;
213: }
214: }
215:
216: @Override
217: public void visitIntInsn(final int opcode, final int operand) {
218: if (mv != null) {
219: mv.visitIntInsn(opcode, operand);
220: }
221: execute(opcode, operand, null);
222: }
223:
224: @Override
225: public void visitVarInsn(final int opcode, final int var) {
226: if (mv != null) {
227: mv.visitVarInsn(opcode, var);
228: }
229: execute(opcode, var, null);
230: }
231:
232: @Override
233: public void visitTypeInsn(final int opcode, final String desc) {
234: if (opcode == Opcodes.NEW) {
235: if (labels == null) {
236: Label l = new Label();
237: labels = new ArrayList(3);
238: labels.add(l);
239: if (mv != null) {
240: mv.visitLabel(l);
241: }
242: }
243: for (int i = 0; i < labels.size(); ++i) {
244: uninitializedTypes.put(labels.get(i), desc);
245: }
246: }
247: if (mv != null) {
248: mv.visitTypeInsn(opcode, desc);
249: }
250: execute(opcode, 0, desc);
251: }
252:
253: @Override
254: public void visitFieldInsn(final int opcode, final String owner,
255: final String name, final String desc) {
256: if (mv != null) {
257: mv.visitFieldInsn(opcode, owner, name, desc);
258: }
259: execute(opcode, 0, desc);
260: }
261:
262: @Override
263: public void visitMethodInsn(final int opcode, final String owner,
264: final String name, final String desc) {
265: if (mv != null) {
266: mv.visitMethodInsn(opcode, owner, name, desc);
267: }
268: pop(desc);
269: if (opcode != Opcodes.INVOKESTATIC) {
270: Object t = pop();
271: if (opcode == Opcodes.INVOKESPECIAL
272: && name.charAt(0) == '<') {
273: Object u;
274: if (t == Opcodes.UNINITIALIZED_THIS) {
275: u = owner;
276: } else {
277: u = uninitializedTypes.get(t);
278: }
279: for (int i = 0; i < locals.size(); ++i) {
280: if (locals.get(i) == t) {
281: locals.set(i, u);
282: }
283: }
284: for (int i = 0; i < stack.size(); ++i) {
285: if (stack.get(i) == t) {
286: stack.set(i, u);
287: }
288: }
289: }
290: }
291: pushDesc(desc);
292: labels = null;
293: }
294:
295: @Override
296: public void visitJumpInsn(final int opcode, final Label label) {
297: if (mv != null) {
298: mv.visitJumpInsn(opcode, label);
299: }
300: execute(opcode, 0, null);
301: if (opcode == Opcodes.GOTO) {
302: this .locals = null;
303: this .stack = null;
304: }
305: }
306:
307: @Override
308: public void visitLabel(final Label label) {
309: if (mv != null) {
310: mv.visitLabel(label);
311: }
312: if (labels == null) {
313: labels = new ArrayList(3);
314: }
315: labels.add(label);
316: }
317:
318: @Override
319: public void visitLdcInsn(final Object cst) {
320: if (mv != null) {
321: mv.visitLdcInsn(cst);
322: }
323: if (cst instanceof Integer) {
324: push(Opcodes.INTEGER);
325: } else if (cst instanceof Long) {
326: push(Opcodes.LONG);
327: push(Opcodes.TOP);
328: } else if (cst instanceof Float) {
329: push(Opcodes.FLOAT);
330: } else if (cst instanceof Double) {
331: push(Opcodes.DOUBLE);
332: push(Opcodes.TOP);
333: } else if (cst instanceof String) {
334: push("java/lang/String");
335: } else if (cst instanceof Type) {
336: push("java/lang/Class");
337: } else {
338: throw new IllegalArgumentException();
339: }
340: labels = null;
341: }
342:
343: @Override
344: public void visitIincInsn(final int var, final int increment) {
345: if (mv != null) {
346: mv.visitIincInsn(var, increment);
347: }
348: execute(Opcodes.IINC, var, null);
349: }
350:
351: @Override
352: public void visitTableSwitchInsn(final int min, final int max,
353: final Label dflt, final Label labels[]) {
354: if (mv != null) {
355: mv.visitTableSwitchInsn(min, max, dflt, labels);
356: }
357: execute(Opcodes.TABLESWITCH, 0, null);
358: this .locals = null;
359: this .stack = null;
360: }
361:
362: @Override
363: public void visitLookupSwitchInsn(final Label dflt,
364: final int keys[], final Label labels[]) {
365: if (mv != null) {
366: mv.visitLookupSwitchInsn(dflt, keys, labels);
367: }
368: execute(Opcodes.LOOKUPSWITCH, 0, null);
369: this .locals = null;
370: this .stack = null;
371: }
372:
373: @Override
374: public void visitMultiANewArrayInsn(final String desc,
375: final int dims) {
376: if (mv != null) {
377: mv.visitMultiANewArrayInsn(desc, dims);
378: }
379: execute(Opcodes.MULTIANEWARRAY, dims, desc);
380: }
381:
382: @Override
383: public void visitMaxs(final int maxStack, final int maxLocals) {
384: if (mv != null) {
385: this .maxStack = Math.max(this .maxStack, maxStack);
386: this .maxLocals = Math.max(this .maxLocals, maxLocals);
387: mv.visitMaxs(this .maxStack, this .maxLocals);
388: }
389: }
390:
391: // ------------------------------------------------------------------------
392:
393: private Object get(final int local) {
394: maxLocals = Math.max(maxLocals, local);
395: return local < locals.size() ? locals.get(local) : Opcodes.TOP;
396: }
397:
398: private void set(final int local, final Object type) {
399: maxLocals = Math.max(maxLocals, local);
400: while (local >= locals.size()) {
401: locals.add(Opcodes.TOP);
402: }
403: locals.set(local, type);
404: }
405:
406: private void push(final Object type) {
407: stack.add(type);
408: maxStack = Math.max(maxStack, stack.size());
409: }
410:
411: private void pushDesc(final String desc) {
412: int index = desc.charAt(0) == '(' ? desc.indexOf(')') + 1 : 0;
413: switch (desc.charAt(index)) {
414: case 'V':
415: return;
416: case 'Z':
417: case 'C':
418: case 'B':
419: case 'S':
420: case 'I':
421: push(Opcodes.INTEGER);
422: return;
423: case 'F':
424: push(Opcodes.FLOAT);
425: return;
426: case 'J':
427: push(Opcodes.LONG);
428: push(Opcodes.TOP);
429: return;
430: case 'D':
431: push(Opcodes.DOUBLE);
432: push(Opcodes.TOP);
433: return;
434: case '[':
435: if (index == 0) {
436: push(desc);
437: } else {
438: push(desc.substring(index, desc.length()));
439: }
440: break;
441: // case 'L':
442: default:
443: if (index == 0) {
444: push(desc.substring(1, desc.length() - 1));
445: } else {
446: push(desc.substring(index + 1, desc.length() - 1));
447: }
448: return;
449: }
450: }
451:
452: private Object pop() {
453: return stack.remove(stack.size() - 1);
454: }
455:
456: private void pop(final int n) {
457: int size = stack.size();
458: int end = size - n;
459: for (int i = size - 1; i >= end; --i) {
460: stack.remove(i);
461: }
462: }
463:
464: private void pop(final String desc) {
465: char c = desc.charAt(0);
466: if (c == '(') {
467: int n = 0;
468: Type[] types = Type.getArgumentTypes(desc);
469: for (int i = 0; i < types.length; ++i) {
470: n += types[i].getSize();
471: }
472: pop(n);
473: } else if (c == 'J' || c == 'D') {
474: pop(2);
475: } else {
476: pop(1);
477: }
478: }
479:
480: private void execute(final int opcode, final int iarg,
481: final String sarg) {
482: if (this .locals == null) {
483: return;
484: }
485: Object t1, t2, t3, t4;
486: switch (opcode) {
487: case Opcodes.NOP:
488: case Opcodes.INEG:
489: case Opcodes.LNEG:
490: case Opcodes.FNEG:
491: case Opcodes.DNEG:
492: case Opcodes.I2B:
493: case Opcodes.I2C:
494: case Opcodes.I2S:
495: case Opcodes.GOTO:
496: case Opcodes.RETURN:
497: break;
498: case Opcodes.ACONST_NULL:
499: push(Opcodes.NULL);
500: break;
501: case Opcodes.ICONST_M1:
502: case Opcodes.ICONST_0:
503: case Opcodes.ICONST_1:
504: case Opcodes.ICONST_2:
505: case Opcodes.ICONST_3:
506: case Opcodes.ICONST_4:
507: case Opcodes.ICONST_5:
508: case Opcodes.BIPUSH:
509: case Opcodes.SIPUSH:
510: push(Opcodes.INTEGER);
511: break;
512: case Opcodes.LCONST_0:
513: case Opcodes.LCONST_1:
514: push(Opcodes.LONG);
515: push(Opcodes.TOP);
516: break;
517: case Opcodes.FCONST_0:
518: case Opcodes.FCONST_1:
519: case Opcodes.FCONST_2:
520: push(Opcodes.FLOAT);
521: break;
522: case Opcodes.DCONST_0:
523: case Opcodes.DCONST_1:
524: push(Opcodes.DOUBLE);
525: push(Opcodes.TOP);
526: break;
527: case Opcodes.ILOAD:
528: case Opcodes.FLOAD:
529: case Opcodes.ALOAD:
530: push(get(iarg));
531: break;
532: case Opcodes.LLOAD:
533: case Opcodes.DLOAD:
534: push(get(iarg));
535: push(Opcodes.TOP);
536: break;
537: case Opcodes.IALOAD:
538: case Opcodes.BALOAD:
539: case Opcodes.CALOAD:
540: case Opcodes.SALOAD:
541: pop(2);
542: push(Opcodes.INTEGER);
543: break;
544: case Opcodes.LALOAD:
545: case Opcodes.D2L:
546: pop(2);
547: push(Opcodes.LONG);
548: push(Opcodes.TOP);
549: break;
550: case Opcodes.FALOAD:
551: pop(2);
552: push(Opcodes.FLOAT);
553: break;
554: case Opcodes.DALOAD:
555: case Opcodes.L2D:
556: pop(2);
557: push(Opcodes.DOUBLE);
558: push(Opcodes.TOP);
559: break;
560: case Opcodes.AALOAD:
561: pop(1);
562: t1 = pop();
563: pushDesc(((String) t1).substring(1));
564: break;
565: case Opcodes.ISTORE:
566: case Opcodes.FSTORE:
567: case Opcodes.ASTORE:
568: t1 = pop();
569: set(iarg, t1);
570: if (iarg > 0) {
571: t2 = get(iarg - 1);
572: if (t2 == Opcodes.LONG || t2 == Opcodes.DOUBLE) {
573: set(iarg - 1, Opcodes.TOP);
574: }
575: }
576: break;
577: case Opcodes.LSTORE:
578: case Opcodes.DSTORE:
579: pop(1);
580: t1 = pop();
581: set(iarg, t1);
582: set(iarg + 1, Opcodes.TOP);
583: if (iarg > 0) {
584: t2 = get(iarg - 1);
585: if (t2 == Opcodes.LONG || t2 == Opcodes.DOUBLE) {
586: set(iarg - 1, Opcodes.TOP);
587: }
588: }
589: break;
590: case Opcodes.IASTORE:
591: case Opcodes.BASTORE:
592: case Opcodes.CASTORE:
593: case Opcodes.SASTORE:
594: case Opcodes.FASTORE:
595: case Opcodes.AASTORE:
596: pop(3);
597: break;
598: case Opcodes.LASTORE:
599: case Opcodes.DASTORE:
600: pop(4);
601: break;
602: case Opcodes.POP:
603: case Opcodes.IFEQ:
604: case Opcodes.IFNE:
605: case Opcodes.IFLT:
606: case Opcodes.IFGE:
607: case Opcodes.IFGT:
608: case Opcodes.IFLE:
609: case Opcodes.IRETURN:
610: case Opcodes.FRETURN:
611: case Opcodes.ARETURN:
612: case Opcodes.TABLESWITCH:
613: case Opcodes.LOOKUPSWITCH:
614: case Opcodes.ATHROW:
615: case Opcodes.MONITORENTER:
616: case Opcodes.MONITOREXIT:
617: case Opcodes.IFNULL:
618: case Opcodes.IFNONNULL:
619: pop(1);
620: break;
621: case Opcodes.POP2:
622: case Opcodes.IF_ICMPEQ:
623: case Opcodes.IF_ICMPNE:
624: case Opcodes.IF_ICMPLT:
625: case Opcodes.IF_ICMPGE:
626: case Opcodes.IF_ICMPGT:
627: case Opcodes.IF_ICMPLE:
628: case Opcodes.IF_ACMPEQ:
629: case Opcodes.IF_ACMPNE:
630: case Opcodes.LRETURN:
631: case Opcodes.DRETURN:
632: pop(2);
633: break;
634: case Opcodes.DUP:
635: t1 = pop();
636: push(t1);
637: push(t1);
638: break;
639: case Opcodes.DUP_X1:
640: t1 = pop();
641: t2 = pop();
642: push(t1);
643: push(t2);
644: push(t1);
645: break;
646: case Opcodes.DUP_X2:
647: t1 = pop();
648: t2 = pop();
649: t3 = pop();
650: push(t1);
651: push(t3);
652: push(t2);
653: push(t1);
654: break;
655: case Opcodes.DUP2:
656: t1 = pop();
657: t2 = pop();
658: push(t2);
659: push(t1);
660: push(t2);
661: push(t1);
662: break;
663: case Opcodes.DUP2_X1:
664: t1 = pop();
665: t2 = pop();
666: t3 = pop();
667: push(t2);
668: push(t1);
669: push(t3);
670: push(t2);
671: push(t1);
672: break;
673: case Opcodes.DUP2_X2:
674: t1 = pop();
675: t2 = pop();
676: t3 = pop();
677: t4 = pop();
678: push(t2);
679: push(t1);
680: push(t4);
681: push(t3);
682: push(t2);
683: push(t1);
684: break;
685: case Opcodes.SWAP:
686: t1 = pop();
687: t2 = pop();
688: push(t1);
689: push(t2);
690: break;
691: case Opcodes.IADD:
692: case Opcodes.ISUB:
693: case Opcodes.IMUL:
694: case Opcodes.IDIV:
695: case Opcodes.IREM:
696: case Opcodes.IAND:
697: case Opcodes.IOR:
698: case Opcodes.IXOR:
699: case Opcodes.ISHL:
700: case Opcodes.ISHR:
701: case Opcodes.IUSHR:
702: case Opcodes.L2I:
703: case Opcodes.D2I:
704: case Opcodes.FCMPL:
705: case Opcodes.FCMPG:
706: pop(2);
707: push(Opcodes.INTEGER);
708: break;
709: case Opcodes.LADD:
710: case Opcodes.LSUB:
711: case Opcodes.LMUL:
712: case Opcodes.LDIV:
713: case Opcodes.LREM:
714: case Opcodes.LAND:
715: case Opcodes.LOR:
716: case Opcodes.LXOR:
717: pop(4);
718: push(Opcodes.LONG);
719: push(Opcodes.TOP);
720: break;
721: case Opcodes.FADD:
722: case Opcodes.FSUB:
723: case Opcodes.FMUL:
724: case Opcodes.FDIV:
725: case Opcodes.FREM:
726: case Opcodes.L2F:
727: case Opcodes.D2F:
728: pop(2);
729: push(Opcodes.FLOAT);
730: break;
731: case Opcodes.DADD:
732: case Opcodes.DSUB:
733: case Opcodes.DMUL:
734: case Opcodes.DDIV:
735: case Opcodes.DREM:
736: pop(4);
737: push(Opcodes.DOUBLE);
738: push(Opcodes.TOP);
739: break;
740: case Opcodes.LSHL:
741: case Opcodes.LSHR:
742: case Opcodes.LUSHR:
743: pop(3);
744: push(Opcodes.LONG);
745: push(Opcodes.TOP);
746: break;
747: case Opcodes.IINC:
748: set(iarg, Opcodes.INTEGER);
749: break;
750: case Opcodes.I2L:
751: case Opcodes.F2L:
752: pop(1);
753: push(Opcodes.LONG);
754: push(Opcodes.TOP);
755: break;
756: case Opcodes.I2F:
757: pop(1);
758: push(Opcodes.FLOAT);
759: break;
760: case Opcodes.I2D:
761: case Opcodes.F2D:
762: pop(1);
763: push(Opcodes.DOUBLE);
764: push(Opcodes.TOP);
765: break;
766: case Opcodes.F2I:
767: case Opcodes.ARRAYLENGTH:
768: case Opcodes.INSTANCEOF:
769: pop(1);
770: push(Opcodes.INTEGER);
771: break;
772: case Opcodes.LCMP:
773: case Opcodes.DCMPL:
774: case Opcodes.DCMPG:
775: pop(4);
776: push(Opcodes.INTEGER);
777: break;
778: case Opcodes.JSR:
779: case Opcodes.RET:
780: throw new RuntimeException("JSR/RET are not supported");
781: case Opcodes.GETSTATIC:
782: pushDesc(sarg);
783: break;
784: case Opcodes.PUTSTATIC:
785: pop(sarg);
786: break;
787: case Opcodes.GETFIELD:
788: pop(1);
789: pushDesc(sarg);
790: break;
791: case Opcodes.PUTFIELD:
792: pop(sarg);
793: pop();
794: break;
795: case Opcodes.NEW:
796: push(labels.get(0));
797: break;
798: case Opcodes.NEWARRAY:
799: pop();
800: switch (iarg) {
801: case Opcodes.T_BOOLEAN:
802: pushDesc("[Z");
803: break;
804: case Opcodes.T_CHAR:
805: pushDesc("[C");
806: break;
807: case Opcodes.T_BYTE:
808: pushDesc("[B");
809: break;
810: case Opcodes.T_SHORT:
811: pushDesc("[S");
812: break;
813: case Opcodes.T_INT:
814: pushDesc("[I");
815: break;
816: case Opcodes.T_FLOAT:
817: pushDesc("[F");
818: break;
819: case Opcodes.T_DOUBLE:
820: pushDesc("[D");
821: break;
822: // case Opcodes.T_LONG:
823: default:
824: pushDesc("[J");
825: break;
826: }
827: break;
828: case Opcodes.ANEWARRAY:
829: pop();
830: if (sarg.charAt(0) == '[') {
831: pushDesc("[" + sarg);
832: } else {
833: pushDesc("[L" + sarg + ";");
834: }
835: break;
836: case Opcodes.CHECKCAST:
837: pop();
838: if (sarg.charAt(0) == '[') {
839: pushDesc(sarg);
840: } else {
841: push(sarg);
842: }
843: break;
844: // case Opcodes.MULTIANEWARRAY:
845: default:
846: pop(iarg);
847: pushDesc(sarg);
848: break;
849: }
850: labels = null;
851: }
852: }
|