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 com.tc.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 com.tc.asm.Label;
037: import com.tc.asm.MethodAdapter;
038: import com.tc.asm.MethodVisitor;
039: import com.tc.asm.Opcodes;
040: import com.tc.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 com.tc.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, or type descriptors for
066: * array types), and uninitialized types by Label objects (this label
067: * designates the NEW instruction that created this uninitialized value).
068: * This field is <tt>null</tt> for unreacheable 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, or type descriptors for
080: * array types), and uninitialized types by Label objects (this label
081: * designates the NEW instruction that created this uninitialized value).
082: * This field is <tt>null</tt> for unreacheable 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 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 (name.equals("<init>")) {
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 void visitFrameTypes(final int n, final Object[] types,
191: 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 desc) {
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), desc);
239: }
240: }
241: if (mv != null) {
242: mv.visitTypeInsn(opcode, desc);
243: }
244: execute(opcode, 0, desc);
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: return;
433: }
434: }
435:
436: private Object pop() {
437: return stack.remove(stack.size() - 1);
438: }
439:
440: private void pop(final int n) {
441: int size = stack.size();
442: int end = size - n;
443: for (int i = size - 1; i >= end; --i) {
444: stack.remove(i);
445: }
446: }
447:
448: private void pop(final String desc) {
449: char c = desc.charAt(0);
450: if (c == '(') {
451: int n = 0;
452: Type[] types = Type.getArgumentTypes(desc);
453: for (int i = 0; i < types.length; ++i) {
454: n += types[i].getSize();
455: }
456: pop(n);
457: } else if (c == 'J' || c == 'D') {
458: pop(2);
459: } else {
460: pop(1);
461: }
462: }
463:
464: private void execute(final int opcode, final int iarg,
465: final String sarg) {
466: if (this .locals == null) {
467: return;
468: }
469: Object t1, t2, t3, t4;
470: switch (opcode) {
471: case Opcodes.NOP:
472: case Opcodes.INEG:
473: case Opcodes.LNEG:
474: case Opcodes.FNEG:
475: case Opcodes.DNEG:
476: case Opcodes.I2B:
477: case Opcodes.I2C:
478: case Opcodes.I2S:
479: case Opcodes.GOTO:
480: case Opcodes.RETURN:
481: break;
482: case Opcodes.ACONST_NULL:
483: push(Opcodes.NULL);
484: break;
485: case Opcodes.ICONST_M1:
486: case Opcodes.ICONST_0:
487: case Opcodes.ICONST_1:
488: case Opcodes.ICONST_2:
489: case Opcodes.ICONST_3:
490: case Opcodes.ICONST_4:
491: case Opcodes.ICONST_5:
492: case Opcodes.BIPUSH:
493: case Opcodes.SIPUSH:
494: push(Opcodes.INTEGER);
495: break;
496: case Opcodes.LCONST_0:
497: case Opcodes.LCONST_1:
498: push(Opcodes.LONG);
499: push(Opcodes.TOP);
500: break;
501: case Opcodes.FCONST_0:
502: case Opcodes.FCONST_1:
503: case Opcodes.FCONST_2:
504: push(Opcodes.FLOAT);
505: break;
506: case Opcodes.DCONST_0:
507: case Opcodes.DCONST_1:
508: push(Opcodes.DOUBLE);
509: push(Opcodes.TOP);
510: break;
511: case Opcodes.ILOAD:
512: case Opcodes.FLOAD:
513: case Opcodes.ALOAD:
514: push(get(iarg));
515: break;
516: case Opcodes.LLOAD:
517: case Opcodes.DLOAD:
518: push(get(iarg));
519: push(Opcodes.TOP);
520: break;
521: case Opcodes.IALOAD:
522: case Opcodes.BALOAD:
523: case Opcodes.CALOAD:
524: case Opcodes.SALOAD:
525: pop(2);
526: push(Opcodes.INTEGER);
527: break;
528: case Opcodes.LALOAD:
529: case Opcodes.D2L:
530: pop(2);
531: push(Opcodes.LONG);
532: push(Opcodes.TOP);
533: break;
534: case Opcodes.FALOAD:
535: pop(2);
536: push(Opcodes.FLOAT);
537: break;
538: case Opcodes.DALOAD:
539: case Opcodes.L2D:
540: pop(2);
541: push(Opcodes.DOUBLE);
542: push(Opcodes.TOP);
543: break;
544: case Opcodes.AALOAD:
545: pop(1);
546: t1 = pop();
547: pushDesc(((String) t1).substring(1));
548: break;
549: case Opcodes.ISTORE:
550: case Opcodes.FSTORE:
551: case Opcodes.ASTORE:
552: t1 = pop();
553: set(iarg, t1);
554: if (iarg > 0) {
555: t2 = get(iarg - 1);
556: if (t2 == Opcodes.LONG || t2 == Opcodes.DOUBLE) {
557: set(iarg - 1, Opcodes.TOP);
558: }
559: }
560: break;
561: case Opcodes.LSTORE:
562: case Opcodes.DSTORE:
563: pop(1);
564: t1 = pop();
565: set(iarg, t1);
566: set(iarg + 1, Opcodes.TOP);
567: if (iarg > 0) {
568: t2 = get(iarg - 1);
569: if (t2 == Opcodes.LONG || t2 == Opcodes.DOUBLE) {
570: set(iarg - 1, Opcodes.TOP);
571: }
572: }
573: break;
574: case Opcodes.IASTORE:
575: case Opcodes.BASTORE:
576: case Opcodes.CASTORE:
577: case Opcodes.SASTORE:
578: case Opcodes.FASTORE:
579: case Opcodes.AASTORE:
580: pop(3);
581: break;
582: case Opcodes.LASTORE:
583: case Opcodes.DASTORE:
584: pop(4);
585: break;
586: case Opcodes.POP:
587: case Opcodes.IFEQ:
588: case Opcodes.IFNE:
589: case Opcodes.IFLT:
590: case Opcodes.IFGE:
591: case Opcodes.IFGT:
592: case Opcodes.IFLE:
593: case Opcodes.IRETURN:
594: case Opcodes.FRETURN:
595: case Opcodes.ARETURN:
596: case Opcodes.TABLESWITCH:
597: case Opcodes.LOOKUPSWITCH:
598: case Opcodes.ATHROW:
599: case Opcodes.MONITORENTER:
600: case Opcodes.MONITOREXIT:
601: case Opcodes.IFNULL:
602: case Opcodes.IFNONNULL:
603: pop(1);
604: break;
605: case Opcodes.POP2:
606: case Opcodes.IF_ICMPEQ:
607: case Opcodes.IF_ICMPNE:
608: case Opcodes.IF_ICMPLT:
609: case Opcodes.IF_ICMPGE:
610: case Opcodes.IF_ICMPGT:
611: case Opcodes.IF_ICMPLE:
612: case Opcodes.IF_ACMPEQ:
613: case Opcodes.IF_ACMPNE:
614: case Opcodes.LRETURN:
615: case Opcodes.DRETURN:
616: pop(2);
617: break;
618: case Opcodes.DUP:
619: t1 = pop();
620: push(t1);
621: push(t1);
622: break;
623: case Opcodes.DUP_X1:
624: t1 = pop();
625: t2 = pop();
626: push(t1);
627: push(t2);
628: push(t1);
629: break;
630: case Opcodes.DUP_X2:
631: t1 = pop();
632: t2 = pop();
633: t3 = pop();
634: push(t1);
635: push(t3);
636: push(t2);
637: push(t1);
638: break;
639: case Opcodes.DUP2:
640: t1 = pop();
641: t2 = pop();
642: push(t2);
643: push(t1);
644: push(t2);
645: push(t1);
646: break;
647: case Opcodes.DUP2_X1:
648: t1 = pop();
649: t2 = pop();
650: t3 = pop();
651: push(t2);
652: push(t1);
653: push(t3);
654: push(t2);
655: push(t1);
656: break;
657: case Opcodes.DUP2_X2:
658: t1 = pop();
659: t2 = pop();
660: t3 = pop();
661: t4 = pop();
662: push(t2);
663: push(t1);
664: push(t4);
665: push(t3);
666: push(t2);
667: push(t1);
668: break;
669: case Opcodes.SWAP:
670: t1 = pop();
671: t2 = pop();
672: push(t1);
673: push(t2);
674: break;
675: case Opcodes.IADD:
676: case Opcodes.ISUB:
677: case Opcodes.IMUL:
678: case Opcodes.IDIV:
679: case Opcodes.IREM:
680: case Opcodes.IAND:
681: case Opcodes.IOR:
682: case Opcodes.IXOR:
683: case Opcodes.ISHL:
684: case Opcodes.ISHR:
685: case Opcodes.IUSHR:
686: case Opcodes.L2I:
687: case Opcodes.D2I:
688: case Opcodes.FCMPL:
689: case Opcodes.FCMPG:
690: pop(2);
691: push(Opcodes.INTEGER);
692: break;
693: case Opcodes.LADD:
694: case Opcodes.LSUB:
695: case Opcodes.LMUL:
696: case Opcodes.LDIV:
697: case Opcodes.LREM:
698: case Opcodes.LAND:
699: case Opcodes.LOR:
700: case Opcodes.LXOR:
701: pop(4);
702: push(Opcodes.LONG);
703: push(Opcodes.TOP);
704: break;
705: case Opcodes.FADD:
706: case Opcodes.FSUB:
707: case Opcodes.FMUL:
708: case Opcodes.FDIV:
709: case Opcodes.FREM:
710: case Opcodes.L2F:
711: case Opcodes.D2F:
712: pop(2);
713: push(Opcodes.FLOAT);
714: break;
715: case Opcodes.DADD:
716: case Opcodes.DSUB:
717: case Opcodes.DMUL:
718: case Opcodes.DDIV:
719: case Opcodes.DREM:
720: pop(4);
721: push(Opcodes.DOUBLE);
722: push(Opcodes.TOP);
723: break;
724: case Opcodes.LSHL:
725: case Opcodes.LSHR:
726: case Opcodes.LUSHR:
727: pop(3);
728: push(Opcodes.LONG);
729: push(Opcodes.TOP);
730: break;
731: case Opcodes.IINC:
732: set(iarg, Opcodes.INTEGER);
733: break;
734: case Opcodes.I2L:
735: case Opcodes.F2L:
736: pop(1);
737: push(Opcodes.LONG);
738: push(Opcodes.TOP);
739: break;
740: case Opcodes.I2F:
741: pop(1);
742: push(Opcodes.FLOAT);
743: break;
744: case Opcodes.I2D:
745: case Opcodes.F2D:
746: pop(1);
747: push(Opcodes.DOUBLE);
748: push(Opcodes.TOP);
749: break;
750: case Opcodes.F2I:
751: case Opcodes.ARRAYLENGTH:
752: case Opcodes.INSTANCEOF:
753: pop(1);
754: push(Opcodes.INTEGER);
755: break;
756: case Opcodes.LCMP:
757: case Opcodes.DCMPL:
758: case Opcodes.DCMPG:
759: pop(4);
760: push(Opcodes.INTEGER);
761: break;
762: case Opcodes.JSR:
763: case Opcodes.RET:
764: throw new RuntimeException("JSR/RET are not supported");
765: case Opcodes.GETSTATIC:
766: pushDesc(sarg);
767: break;
768: case Opcodes.PUTSTATIC:
769: pop(sarg);
770: break;
771: case Opcodes.GETFIELD:
772: pop(1);
773: pushDesc(sarg);
774: break;
775: case Opcodes.PUTFIELD:
776: pop(sarg);
777: pop();
778: break;
779: case Opcodes.NEW:
780: push(labels.get(0));
781: break;
782: case Opcodes.NEWARRAY:
783: pop();
784: switch (iarg) {
785: case Opcodes.T_BOOLEAN:
786: pushDesc("[Z");
787: break;
788: case Opcodes.T_CHAR:
789: pushDesc("[C");
790: break;
791: case Opcodes.T_BYTE:
792: pushDesc("[B");
793: break;
794: case Opcodes.T_SHORT:
795: pushDesc("[S");
796: break;
797: case Opcodes.T_INT:
798: pushDesc("[I");
799: break;
800: case Opcodes.T_FLOAT:
801: pushDesc("[F");
802: break;
803: case Opcodes.T_DOUBLE:
804: pushDesc("[D");
805: break;
806: // case Opcodes.T_LONG:
807: default:
808: pushDesc("[J");
809: break;
810: }
811: break;
812: case Opcodes.ANEWARRAY:
813: pop();
814: if (sarg.charAt(0) == '[') {
815: pushDesc("[" + sarg);
816: } else {
817: pushDesc("[L" + sarg + ";");
818: }
819: break;
820: case Opcodes.CHECKCAST:
821: pop();
822: if (sarg.charAt(0) == '[') {
823: pushDesc(sarg);
824: } else {
825: push(sarg);
826: }
827: break;
828: // case Opcodes.MULTIANEWARRAY:
829: default:
830: pop(iarg);
831: pushDesc(sarg);
832: break;
833: }
834: labels = null;
835: }
836: }
|