KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tc > asm > commons > AdviceAdapter


1 /***
2  * ASM: a very small and fast Java bytecode manipulation framework
3  * Copyright (c) 2000-2005 INRIA, France Telecom
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  * 3. Neither the name of the copyright holders nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28  * THE POSSIBILITY OF SUCH DAMAGE.
29  */

30 package com.tc.asm.commons;
31
32 import java.util.ArrayList JavaDoc;
33 import java.util.HashMap JavaDoc;
34
35 import com.tc.asm.Label;
36 import com.tc.asm.MethodVisitor;
37 import com.tc.asm.Opcodes;
38 import com.tc.asm.Type;
39
40 /**
41  * A <code>MethodAdapter</code> to dispatch method body instruction
42  * <p>
43  * The behavior is like this:
44  * <ol>
45  *
46  * <li>as long as the INVOKESPECIAL for the object initialization has not been
47  * reached, every bytecode instruction is dispatched in the ctor code visitor</li>
48  *
49  * <li>when this one is reached, it is only added in the ctor code visitor and
50  * a JP invoke is added</li>
51  * <li>after that, only the other code visitor receives the instructions</li>
52  *
53  * </ol>
54  *
55  * @author Eugene Kuleshov
56  * @author Eric Bruneton
57  */

58 public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes {
59     private static final Object JavaDoc THIS = new Object JavaDoc();
60     private static final Object JavaDoc OTHER = new Object JavaDoc();
61
62     protected int methodAccess;
63     protected String JavaDoc methodDesc;
64     
65     private boolean constructor;
66     private boolean superInitialized;
67     private ArrayList JavaDoc stackFrame;
68     private HashMap JavaDoc branches;
69
70     
71     /**
72      * Creates a new {@link AdviceAdapter}.
73      *
74      * @param mv the method visitor to which this adapter delegates calls.
75      * @param access the method's access flags (see {@link Opcodes}).
76      * @param name the method's name.
77      * @param desc the method's descriptor (see {@link Type Type}).
78      */

79     public AdviceAdapter(MethodVisitor mv, int access, String JavaDoc name, String JavaDoc desc) {
80         super(mv, access, name, desc);
81         methodAccess = access;
82         methodDesc = desc;
83
84         constructor = "<init>".equals(name);
85         if (!constructor) {
86             superInitialized = true;
87             onMethodEnter();
88         } else {
89             stackFrame = new ArrayList JavaDoc();
90             branches = new HashMap JavaDoc();
91         }
92     }
93
94     public void visitLabel(Label label) {
95         mv.visitLabel(label);
96
97         if (constructor && branches != null) {
98             ArrayList JavaDoc frame = (ArrayList JavaDoc) branches.get(label);
99             if (frame != null) {
100                 stackFrame = frame;
101                 branches.remove(label);
102             }
103         }
104     }
105
106     public void visitInsn(int opcode) {
107         if (constructor) {
108             switch (opcode) {
109                 case RETURN: // empty stack
110
onMethodExit(opcode);
111                     break;
112
113                 case IRETURN: // 1 before n/a after
114
case FRETURN: // 1 before n/a after
115
case ARETURN: // 1 before n/a after
116
case ATHROW: // 1 before n/a after
117
popValue();
118                     popValue();
119                     onMethodExit(opcode);
120                     break;
121
122                 case LRETURN: // 2 before n/a after
123
case DRETURN: // 2 before n/a after
124
popValue();
125                     popValue();
126                     onMethodExit(opcode);
127                     break;
128
129                 case NOP:
130                 case LALOAD: // remove 2 add 2
131
case DALOAD: // remove 2 add 2
132
case LNEG:
133                 case DNEG:
134                 case FNEG:
135                 case INEG:
136                 case L2D:
137                 case D2L:
138                 case F2I:
139                 case I2B:
140                 case I2C:
141                 case I2S:
142                 case I2F:
143                 case Opcodes.ARRAYLENGTH:
144                     break;
145
146                 case ACONST_NULL:
147                 case ICONST_M1:
148                 case ICONST_0:
149                 case ICONST_1:
150                 case ICONST_2:
151                 case ICONST_3:
152                 case ICONST_4:
153                 case ICONST_5:
154                 case FCONST_0:
155                 case FCONST_1:
156                 case FCONST_2:
157                 case F2L: // 1 before 2 after
158
case F2D:
159                 case I2L:
160                 case I2D:
161                     pushValue(OTHER);
162                     break;
163
164                 case LCONST_0:
165                 case LCONST_1:
166                 case DCONST_0:
167                 case DCONST_1:
168                     pushValue(OTHER);
169                     pushValue(OTHER);
170                     break;
171
172                 case IALOAD: // remove 2 add 1
173
case FALOAD: // remove 2 add 1
174
case AALOAD: // remove 2 add 1
175
case BALOAD: // remove 2 add 1
176
case CALOAD: // remove 2 add 1
177
case SALOAD: // remove 2 add 1
178
case POP:
179                 case IADD:
180                 case FADD:
181                 case ISUB:
182                 case LSHL: // 3 before 2 after
183
case LSHR: // 3 before 2 after
184
case LUSHR: // 3 before 2 after
185
case L2I: // 2 before 1 after
186
case L2F: // 2 before 1 after
187
case D2I: // 2 before 1 after
188
case D2F: // 2 before 1 after
189
case FSUB:
190                 case FMUL:
191                 case FDIV:
192                 case FREM:
193                 case FCMPL: // 2 before 1 after
194
case FCMPG: // 2 before 1 after
195
case IMUL:
196                 case IDIV:
197                 case IREM:
198                 case ISHL:
199                 case ISHR:
200                 case IUSHR:
201                 case IAND:
202                 case IOR:
203                 case IXOR:
204                 case MONITORENTER:
205                 case MONITOREXIT:
206                     popValue();
207                     break;
208
209                 case POP2:
210                 case LSUB:
211                 case LMUL:
212                 case LDIV:
213                 case LREM:
214                 case LADD:
215                 case LAND:
216                 case LOR:
217                 case LXOR:
218                 case DADD:
219                 case DMUL:
220                 case DSUB:
221                 case DDIV:
222                 case DREM:
223                     popValue();
224                     popValue();
225                     break;
226
227                 case IASTORE:
228                 case FASTORE:
229                 case AASTORE:
230                 case BASTORE:
231                 case CASTORE:
232                 case SASTORE:
233                 case LCMP: // 4 before 1 after
234
case DCMPL:
235                 case DCMPG:
236                     popValue();
237                     popValue();
238                     popValue();
239                     break;
240
241                 case LASTORE:
242                 case DASTORE:
243                     popValue();
244                     popValue();
245                     popValue();
246                     popValue();
247                     break;
248
249                 case DUP:
250                     pushValue(peekValue());
251                     break;
252
253                 case DUP_X1:
254                 // TODO optimize this
255
{
256                     Object JavaDoc o1 = popValue();
257                     Object JavaDoc o2 = popValue();
258                     pushValue(o1);
259                     pushValue(o2);
260                     pushValue(o1);
261                 }
262                     break;
263
264                 case DUP_X2:
265                 // TODO optimize this
266
{
267                     Object JavaDoc o1 = popValue();
268                     Object JavaDoc o2 = popValue();
269                     Object JavaDoc o3 = popValue();
270                     pushValue(o1);
271                     pushValue(o3);
272                     pushValue(o2);
273                     pushValue(o1);
274                 }
275                     break;
276
277                 case DUP2:
278                 // TODO optimize this
279
{
280                     Object JavaDoc o1 = popValue();
281                     Object JavaDoc o2 = popValue();
282                     pushValue(o2);
283                     pushValue(o1);
284                     pushValue(o2);
285                     pushValue(o1);
286                 }
287                     break;
288
289                 case DUP2_X1:
290                 // TODO optimize this
291
{
292                     Object JavaDoc o1 = popValue();
293                     Object JavaDoc o2 = popValue();
294                     Object JavaDoc o3 = popValue();
295                     pushValue(o2);
296                     pushValue(o1);
297                     pushValue(o3);
298                     pushValue(o2);
299                     pushValue(o1);
300                 }
301                     break;
302
303                 case DUP2_X2:
304                 // TODO optimize this
305
{
306                     Object JavaDoc o1 = popValue();
307                     Object JavaDoc o2 = popValue();
308                     Object JavaDoc o3 = popValue();
309                     Object JavaDoc o4 = popValue();
310                     pushValue(o2);
311                     pushValue(o1);
312                     pushValue(o4);
313                     pushValue(o3);
314                     pushValue(o2);
315                     pushValue(o1);
316                 }
317                     break;
318
319                 case SWAP: {
320                     Object JavaDoc o1 = popValue();
321                     Object JavaDoc o2 = popValue();
322                     pushValue(o1);
323                     pushValue(o2);
324                 }
325                     break;
326             }
327         } else {
328             switch (opcode) {
329                 case RETURN:
330                 case IRETURN:
331                 case FRETURN:
332                 case ARETURN:
333                 case LRETURN:
334                 case DRETURN:
335                 case ATHROW:
336                     onMethodExit(opcode);
337                     break;
338             }
339         }
340         mv.visitInsn(opcode);
341     }
342
343     public void visitVarInsn(int opcode, int var) {
344         super.visitVarInsn(opcode, var);
345
346         if (constructor) {
347             switch (opcode) {
348                 case ILOAD:
349                 case FLOAD:
350                     pushValue(OTHER);
351                     break;
352                 case LLOAD:
353                 case DLOAD:
354                     pushValue(OTHER);
355                     pushValue(OTHER);
356                     break;
357                 case ALOAD:
358                     pushValue(var == 0 ? THIS : OTHER);
359                     break;
360                 case ASTORE:
361                 case ISTORE:
362                 case FSTORE:
363                     popValue();
364                     break;
365                 case LSTORE:
366                 case DSTORE:
367                     popValue();
368                     popValue();
369                     break;
370             }
371         }
372     }
373
374     public void visitFieldInsn(
375         int opcode,
376         String JavaDoc owner,
377         String JavaDoc name,
378         String JavaDoc desc)
379     {
380         mv.visitFieldInsn(opcode, owner, name, desc);
381
382         if (constructor) {
383             char c = desc.charAt(0);
384             boolean longOrDouble = c == 'J' || c == 'D';
385             switch (opcode) {
386                 case GETSTATIC:
387                     pushValue(OTHER);
388                     if (longOrDouble) {
389                         pushValue(OTHER);
390                     }
391                     break;
392                 case PUTSTATIC:
393                     popValue();
394                     if(longOrDouble) {
395                         popValue();
396                     }
397                     break;
398                 case PUTFIELD:
399                     popValue();
400                     if(longOrDouble) {
401                         popValue();
402                         popValue();
403                     }
404                     break;
405                 // case GETFIELD:
406
default:
407                     if (longOrDouble) {
408                         pushValue(OTHER);
409                     }
410             }
411         }
412     }
413
414     public void visitIntInsn(int opcode, int operand) {
415         mv.visitIntInsn(opcode, operand);
416
417         if (constructor) {
418             switch (opcode) {
419                 case BIPUSH:
420                 case SIPUSH:
421                     pushValue(OTHER);
422             }
423         }
424     }
425
426     public void visitLdcInsn(Object JavaDoc cst) {
427         mv.visitLdcInsn(cst);
428
429         if (constructor) {
430             pushValue(OTHER);
431             if (cst instanceof Double JavaDoc || cst instanceof Long JavaDoc) {
432                 pushValue(OTHER);
433             }
434         }
435     }
436
437     public void visitMultiANewArrayInsn(String JavaDoc desc, int dims) {
438         mv.visitMultiANewArrayInsn(desc, dims);
439
440         if (constructor) {
441             for (int i = 0; i < dims; i++) {
442                 popValue();
443             }
444             pushValue(OTHER);
445         }
446     }
447
448     public void visitTypeInsn(int opcode, String JavaDoc name) {
449         mv.visitTypeInsn(opcode, name);
450
451         // ANEWARRAY, CHECKCAST or INSTANCEOF don't change stack
452
if (constructor && opcode == NEW) {
453             pushValue(OTHER);
454         }
455     }
456
457     public void visitMethodInsn(
458         int opcode,
459         String JavaDoc owner,
460         String JavaDoc name,
461         String JavaDoc desc)
462     {
463         mv.visitMethodInsn(opcode, owner, name, desc);
464
465         if (constructor) {
466             Type[] types = Type.getArgumentTypes(desc);
467             for (int i = 0; i < types.length; i++) {
468                 popValue();
469                 if (types[i].getSize() == 2) {
470                     popValue();
471                 }
472             }
473             switch (opcode) {
474                 // case INVOKESTATIC:
475
// break;
476

477                 case INVOKEINTERFACE:
478                 case INVOKEVIRTUAL:
479                     popValue(); // objectref
480
break;
481
482                 case INVOKESPECIAL:
483                     Object JavaDoc type = popValue(); // objectref
484
if (type == THIS && !superInitialized) {
485                         onMethodEnter();
486                         superInitialized = true;
487                         // once super has been initialized it is no longer
488
// necessary to keep track of stack state
489
constructor = false;
490                     }
491                     break;
492             }
493
494             Type returnType = Type.getReturnType(desc);
495             if (returnType != Type.VOID_TYPE) {
496                 pushValue(OTHER);
497                 if (returnType.getSize() == 2) {
498                     pushValue(OTHER);
499                 }
500             }
501         }
502     }
503
504     public void visitJumpInsn(int opcode, Label label) {
505         mv.visitJumpInsn(opcode, label);
506
507         if (constructor) {
508             switch (opcode) {
509                 case IFEQ:
510                 case IFNE:
511                 case IFLT:
512                 case IFGE:
513                 case IFGT:
514                 case IFLE:
515                 case IFNULL:
516                 case IFNONNULL:
517                     popValue();
518                     break;
519
520                 case IF_ICMPEQ:
521                 case IF_ICMPNE:
522                 case IF_ICMPLT:
523                 case IF_ICMPGE:
524                 case IF_ICMPGT:
525                 case IF_ICMPLE:
526                 case IF_ACMPEQ:
527                 case IF_ACMPNE:
528                     popValue();
529                     popValue();
530                     break;
531
532                 case JSR:
533                     pushValue(OTHER);
534                     break;
535             }
536             addBranch(label);
537         }
538     }
539
540     public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
541         mv.visitLookupSwitchInsn(dflt, keys, labels);
542
543         if (constructor) {
544             popValue();
545             addBranches(dflt, labels);
546         }
547     }
548
549     public void visitTableSwitchInsn(
550         int min,
551         int max,
552         Label dflt,
553         Label[] labels)
554     {
555         mv.visitTableSwitchInsn(min, max, dflt, labels);
556
557         if (constructor) {
558             popValue();
559             addBranches(dflt, labels);
560         }
561     }
562
563     private void addBranches(Label dflt, Label[] labels) {
564         addBranch(dflt);
565         for (int i = 0; i < labels.length; i++) {
566             addBranch(labels[i]);
567         }
568     }
569
570     private void addBranch(Label label) {
571         if (branches.containsKey(label)) {
572             return;
573         }
574         ArrayList JavaDoc frame = new ArrayList JavaDoc();
575         frame.addAll(stackFrame);
576         branches.put(label, frame);
577     }
578
579     private Object JavaDoc popValue() {
580         return stackFrame.remove(stackFrame.size()-1);
581     }
582
583     private Object JavaDoc peekValue() {
584         return stackFrame.get(stackFrame.size()-1);
585     }
586     
587     private void pushValue(Object JavaDoc o) {
588         stackFrame.add(o);
589     }
590     
591     /**
592      * Called at the beginning of the method or after super
593      * class class call in the constructor.
594      * <br><br>
595      *
596      * <i>Custom code can use or change all the local variables,
597      * but should not change state of the stack.</i>
598      */

599     protected abstract void onMethodEnter();
600
601     /**
602      * Called before explicit exit from the method using either
603      * return or throw. Top element on the stack contains the
604      * return value or exception instance. For example:
605      *
606      * <pre>
607      * public void onMethodExit(int opcode) {
608      * if(opcode==RETURN) {
609      * visitInsn(ACONST_NULL);
610      * } else if(opcode==ARETURN || opcode==ATHROW) {
611      * dup();
612      * } else {
613      * if(opcode==LRETURN || opcode==DRETURN) {
614      * dup2();
615      * } else {
616      * dup();
617      * }
618      * box(Type.getReturnType(this.methodDesc));
619      * }
620      * visitIntInsn(SIPUSH, opcode);
621      * visitMethodInsn(INVOKESTATIC, owner, "onExit", "(Ljava/lang/Object;I)V");
622      * }
623      *
624      * // an actual call back method
625      * public static void onExit(int opcode, Object param) {
626      * ...
627      * </pre>
628      *
629      * <br><br>
630      *
631      * <i>Custom code can use or change all the local variables,
632      * but should not change state of the stack.</i>
633      *
634      * @param opcode one of the RETURN, IRETURN, FRETURN,
635      * ARETURN, LRETURN, DRETURN or ATHROW
636      *
637      */

638     protected abstract void onMethodExit(int opcode);
639
640     // TODO onException, onMethodCall
641

642 }
643
644
Popular Tags