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