KickJava   Java API By Example, From Geeks To Geeks.

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

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

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

647     protected void onMethodExit(int opcode) {
648     }
649
650     // TODO onException, onMethodCall
651

652 }
653
Popular Tags