Mercurial > lasercutter
comparison src/clojure/asm/commons/AdviceAdapter.java @ 10:ef7dbbd6452c
added clojure source goodness
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sat, 21 Aug 2010 06:25:44 -0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
9:35cf337adfcf | 10:ef7dbbd6452c |
---|---|
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 clojure.asm.commons; | |
31 | |
32 import java.util.ArrayList; | |
33 import java.util.HashMap; | |
34 | |
35 import clojure.asm.Label; | |
36 import clojure.asm.MethodVisitor; | |
37 import clojure.asm.Opcodes; | |
38 import clojure.asm.Type; | |
39 | |
40 /** | |
41 * A {@link clojure.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 * <p/> | |
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 * <p/> | |
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 * <p/> | |
51 * <li>after that, only the other code visitor receives the instructions</li> | |
52 * <p/> | |
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 THIS = new Object(); | |
60 private static final Object OTHER = new Object(); | |
61 | |
62 protected int methodAccess; | |
63 protected String methodDesc; | |
64 | |
65 private boolean constructor; | |
66 private boolean superInitialized; | |
67 private ArrayList stackFrame; | |
68 private HashMap branches; | |
69 | |
70 /** | |
71 * Creates a new {@link AdviceAdapter}. | |
72 * | |
73 * @param mv the method visitor to which this adapter delegates calls. | |
74 * @param access the method's access flags (see {@link Opcodes}). | |
75 * @param name the method's name. | |
76 * @param desc the method's descriptor (see {@link Type Type}). | |
77 */ | |
78 public AdviceAdapter( | |
79 final MethodVisitor mv, | |
80 final int access, | |
81 final String name, | |
82 final String desc){ | |
83 super(mv, access, name, desc); | |
84 methodAccess = access; | |
85 methodDesc = desc; | |
86 | |
87 constructor = "<init>".equals(name); | |
88 } | |
89 | |
90 public void visitCode(){ | |
91 mv.visitCode(); | |
92 if(!constructor) | |
93 { | |
94 superInitialized = true; | |
95 onMethodEnter(); | |
96 } | |
97 else | |
98 { | |
99 stackFrame = new ArrayList(); | |
100 branches = new HashMap(); | |
101 } | |
102 } | |
103 | |
104 public void visitLabel(final Label label){ | |
105 mv.visitLabel(label); | |
106 | |
107 if(constructor && branches != null) | |
108 { | |
109 ArrayList frame = (ArrayList) branches.get(label); | |
110 if(frame != null) | |
111 { | |
112 stackFrame = frame; | |
113 branches.remove(label); | |
114 } | |
115 } | |
116 } | |
117 | |
118 public void visitInsn(final int opcode){ | |
119 if(constructor) | |
120 { | |
121 switch(opcode) | |
122 { | |
123 case RETURN: // empty stack | |
124 onMethodExit(opcode); | |
125 break; | |
126 | |
127 case IRETURN: // 1 before n/a after | |
128 case FRETURN: // 1 before n/a after | |
129 case ARETURN: // 1 before n/a after | |
130 case ATHROW: // 1 before n/a after | |
131 popValue(); | |
132 popValue(); | |
133 onMethodExit(opcode); | |
134 break; | |
135 | |
136 case LRETURN: // 2 before n/a after | |
137 case DRETURN: // 2 before n/a after | |
138 popValue(); | |
139 popValue(); | |
140 onMethodExit(opcode); | |
141 break; | |
142 | |
143 case NOP: | |
144 case LALOAD: // remove 2 add 2 | |
145 case DALOAD: // remove 2 add 2 | |
146 case LNEG: | |
147 case DNEG: | |
148 case FNEG: | |
149 case INEG: | |
150 case L2D: | |
151 case D2L: | |
152 case F2I: | |
153 case I2B: | |
154 case I2C: | |
155 case I2S: | |
156 case I2F: | |
157 case Opcodes.ARRAYLENGTH: | |
158 break; | |
159 | |
160 case ACONST_NULL: | |
161 case ICONST_M1: | |
162 case ICONST_0: | |
163 case ICONST_1: | |
164 case ICONST_2: | |
165 case ICONST_3: | |
166 case ICONST_4: | |
167 case ICONST_5: | |
168 case FCONST_0: | |
169 case FCONST_1: | |
170 case FCONST_2: | |
171 case F2L: // 1 before 2 after | |
172 case F2D: | |
173 case I2L: | |
174 case I2D: | |
175 pushValue(OTHER); | |
176 break; | |
177 | |
178 case LCONST_0: | |
179 case LCONST_1: | |
180 case DCONST_0: | |
181 case DCONST_1: | |
182 pushValue(OTHER); | |
183 pushValue(OTHER); | |
184 break; | |
185 | |
186 case IALOAD: // remove 2 add 1 | |
187 case FALOAD: // remove 2 add 1 | |
188 case AALOAD: // remove 2 add 1 | |
189 case BALOAD: // remove 2 add 1 | |
190 case CALOAD: // remove 2 add 1 | |
191 case SALOAD: // remove 2 add 1 | |
192 case POP: | |
193 case IADD: | |
194 case FADD: | |
195 case ISUB: | |
196 case LSHL: // 3 before 2 after | |
197 case LSHR: // 3 before 2 after | |
198 case LUSHR: // 3 before 2 after | |
199 case L2I: // 2 before 1 after | |
200 case L2F: // 2 before 1 after | |
201 case D2I: // 2 before 1 after | |
202 case D2F: // 2 before 1 after | |
203 case FSUB: | |
204 case FMUL: | |
205 case FDIV: | |
206 case FREM: | |
207 case FCMPL: // 2 before 1 after | |
208 case FCMPG: // 2 before 1 after | |
209 case IMUL: | |
210 case IDIV: | |
211 case IREM: | |
212 case ISHL: | |
213 case ISHR: | |
214 case IUSHR: | |
215 case IAND: | |
216 case IOR: | |
217 case IXOR: | |
218 case MONITORENTER: | |
219 case MONITOREXIT: | |
220 popValue(); | |
221 break; | |
222 | |
223 case POP2: | |
224 case LSUB: | |
225 case LMUL: | |
226 case LDIV: | |
227 case LREM: | |
228 case LADD: | |
229 case LAND: | |
230 case LOR: | |
231 case LXOR: | |
232 case DADD: | |
233 case DMUL: | |
234 case DSUB: | |
235 case DDIV: | |
236 case DREM: | |
237 popValue(); | |
238 popValue(); | |
239 break; | |
240 | |
241 case IASTORE: | |
242 case FASTORE: | |
243 case AASTORE: | |
244 case BASTORE: | |
245 case CASTORE: | |
246 case SASTORE: | |
247 case LCMP: // 4 before 1 after | |
248 case DCMPL: | |
249 case DCMPG: | |
250 popValue(); | |
251 popValue(); | |
252 popValue(); | |
253 break; | |
254 | |
255 case LASTORE: | |
256 case DASTORE: | |
257 popValue(); | |
258 popValue(); | |
259 popValue(); | |
260 popValue(); | |
261 break; | |
262 | |
263 case DUP: | |
264 pushValue(peekValue()); | |
265 break; | |
266 | |
267 case DUP_X1: | |
268 // TODO optimize this | |
269 { | |
270 Object o1 = popValue(); | |
271 Object o2 = popValue(); | |
272 pushValue(o1); | |
273 pushValue(o2); | |
274 pushValue(o1); | |
275 } | |
276 break; | |
277 | |
278 case DUP_X2: | |
279 // TODO optimize this | |
280 { | |
281 Object o1 = popValue(); | |
282 Object o2 = popValue(); | |
283 Object o3 = popValue(); | |
284 pushValue(o1); | |
285 pushValue(o3); | |
286 pushValue(o2); | |
287 pushValue(o1); | |
288 } | |
289 break; | |
290 | |
291 case DUP2: | |
292 // TODO optimize this | |
293 { | |
294 Object o1 = popValue(); | |
295 Object o2 = popValue(); | |
296 pushValue(o2); | |
297 pushValue(o1); | |
298 pushValue(o2); | |
299 pushValue(o1); | |
300 } | |
301 break; | |
302 | |
303 case DUP2_X1: | |
304 // TODO optimize this | |
305 { | |
306 Object o1 = popValue(); | |
307 Object o2 = popValue(); | |
308 Object o3 = popValue(); | |
309 pushValue(o2); | |
310 pushValue(o1); | |
311 pushValue(o3); | |
312 pushValue(o2); | |
313 pushValue(o1); | |
314 } | |
315 break; | |
316 | |
317 case DUP2_X2: | |
318 // TODO optimize this | |
319 { | |
320 Object o1 = popValue(); | |
321 Object o2 = popValue(); | |
322 Object o3 = popValue(); | |
323 Object o4 = popValue(); | |
324 pushValue(o2); | |
325 pushValue(o1); | |
326 pushValue(o4); | |
327 pushValue(o3); | |
328 pushValue(o2); | |
329 pushValue(o1); | |
330 } | |
331 break; | |
332 | |
333 case SWAP: | |
334 { | |
335 Object o1 = popValue(); | |
336 Object o2 = popValue(); | |
337 pushValue(o1); | |
338 pushValue(o2); | |
339 } | |
340 break; | |
341 } | |
342 } | |
343 else | |
344 { | |
345 switch(opcode) | |
346 { | |
347 case RETURN: | |
348 case IRETURN: | |
349 case FRETURN: | |
350 case ARETURN: | |
351 case LRETURN: | |
352 case DRETURN: | |
353 case ATHROW: | |
354 onMethodExit(opcode); | |
355 break; | |
356 } | |
357 } | |
358 mv.visitInsn(opcode); | |
359 } | |
360 | |
361 public void visitVarInsn(final int opcode, final int var){ | |
362 super.visitVarInsn(opcode, var); | |
363 | |
364 if(constructor) | |
365 { | |
366 switch(opcode) | |
367 { | |
368 case ILOAD: | |
369 case FLOAD: | |
370 pushValue(OTHER); | |
371 break; | |
372 case LLOAD: | |
373 case DLOAD: | |
374 pushValue(OTHER); | |
375 pushValue(OTHER); | |
376 break; | |
377 case ALOAD: | |
378 pushValue(var == 0 ? THIS : OTHER); | |
379 break; | |
380 case ASTORE: | |
381 case ISTORE: | |
382 case FSTORE: | |
383 popValue(); | |
384 break; | |
385 case LSTORE: | |
386 case DSTORE: | |
387 popValue(); | |
388 popValue(); | |
389 break; | |
390 } | |
391 } | |
392 } | |
393 | |
394 public void visitFieldInsn( | |
395 final int opcode, | |
396 final String owner, | |
397 final String name, | |
398 final String desc){ | |
399 mv.visitFieldInsn(opcode, owner, name, desc); | |
400 | |
401 if(constructor) | |
402 { | |
403 char c = desc.charAt(0); | |
404 boolean longOrDouble = c == 'J' || c == 'D'; | |
405 switch(opcode) | |
406 { | |
407 case GETSTATIC: | |
408 pushValue(OTHER); | |
409 if(longOrDouble) | |
410 { | |
411 pushValue(OTHER); | |
412 } | |
413 break; | |
414 case PUTSTATIC: | |
415 popValue(); | |
416 if(longOrDouble) | |
417 { | |
418 popValue(); | |
419 } | |
420 break; | |
421 case PUTFIELD: | |
422 popValue(); | |
423 if(longOrDouble) | |
424 { | |
425 popValue(); | |
426 popValue(); | |
427 } | |
428 break; | |
429 // case GETFIELD: | |
430 default: | |
431 if(longOrDouble) | |
432 { | |
433 pushValue(OTHER); | |
434 } | |
435 } | |
436 } | |
437 } | |
438 | |
439 public void visitIntInsn(final int opcode, final int operand){ | |
440 mv.visitIntInsn(opcode, operand); | |
441 | |
442 if(constructor && opcode != NEWARRAY) | |
443 { | |
444 pushValue(OTHER); | |
445 } | |
446 } | |
447 | |
448 public void visitLdcInsn(final Object cst){ | |
449 mv.visitLdcInsn(cst); | |
450 | |
451 if(constructor) | |
452 { | |
453 pushValue(OTHER); | |
454 if(cst instanceof Double || cst instanceof Long) | |
455 { | |
456 pushValue(OTHER); | |
457 } | |
458 } | |
459 } | |
460 | |
461 public void visitMultiANewArrayInsn(final String desc, final int dims){ | |
462 mv.visitMultiANewArrayInsn(desc, dims); | |
463 | |
464 if(constructor) | |
465 { | |
466 for(int i = 0; i < dims; i++) | |
467 { | |
468 popValue(); | |
469 } | |
470 pushValue(OTHER); | |
471 } | |
472 } | |
473 | |
474 public void visitTypeInsn(final int opcode, final String name){ | |
475 mv.visitTypeInsn(opcode, name); | |
476 | |
477 // ANEWARRAY, CHECKCAST or INSTANCEOF don't change stack | |
478 if(constructor && opcode == NEW) | |
479 { | |
480 pushValue(OTHER); | |
481 } | |
482 } | |
483 | |
484 public void visitMethodInsn( | |
485 final int opcode, | |
486 final String owner, | |
487 final String name, | |
488 final String desc){ | |
489 mv.visitMethodInsn(opcode, owner, name, desc); | |
490 | |
491 if(constructor) | |
492 { | |
493 Type[] types = Type.getArgumentTypes(desc); | |
494 for(int i = 0; i < types.length; i++) | |
495 { | |
496 popValue(); | |
497 if(types[i].getSize() == 2) | |
498 { | |
499 popValue(); | |
500 } | |
501 } | |
502 switch(opcode) | |
503 { | |
504 // case INVOKESTATIC: | |
505 // break; | |
506 | |
507 case INVOKEINTERFACE: | |
508 case INVOKEVIRTUAL: | |
509 popValue(); // objectref | |
510 break; | |
511 | |
512 case INVOKESPECIAL: | |
513 Object type = popValue(); // objectref | |
514 if(type == THIS && !superInitialized) | |
515 { | |
516 onMethodEnter(); | |
517 superInitialized = true; | |
518 // once super has been initialized it is no longer | |
519 // necessary to keep track of stack state | |
520 constructor = false; | |
521 } | |
522 break; | |
523 } | |
524 | |
525 Type returnType = Type.getReturnType(desc); | |
526 if(returnType != Type.VOID_TYPE) | |
527 { | |
528 pushValue(OTHER); | |
529 if(returnType.getSize() == 2) | |
530 { | |
531 pushValue(OTHER); | |
532 } | |
533 } | |
534 } | |
535 } | |
536 | |
537 public void visitJumpInsn(final int opcode, final Label label){ | |
538 mv.visitJumpInsn(opcode, label); | |
539 | |
540 if(constructor) | |
541 { | |
542 switch(opcode) | |
543 { | |
544 case IFEQ: | |
545 case IFNE: | |
546 case IFLT: | |
547 case IFGE: | |
548 case IFGT: | |
549 case IFLE: | |
550 case IFNULL: | |
551 case IFNONNULL: | |
552 popValue(); | |
553 break; | |
554 | |
555 case IF_ICMPEQ: | |
556 case IF_ICMPNE: | |
557 case IF_ICMPLT: | |
558 case IF_ICMPGE: | |
559 case IF_ICMPGT: | |
560 case IF_ICMPLE: | |
561 case IF_ACMPEQ: | |
562 case IF_ACMPNE: | |
563 popValue(); | |
564 popValue(); | |
565 break; | |
566 | |
567 case JSR: | |
568 pushValue(OTHER); | |
569 break; | |
570 } | |
571 addBranch(label); | |
572 } | |
573 } | |
574 | |
575 public void visitLookupSwitchInsn( | |
576 final Label dflt, | |
577 final int[] keys, | |
578 final Label[] labels){ | |
579 mv.visitLookupSwitchInsn(dflt, keys, labels); | |
580 | |
581 if(constructor) | |
582 { | |
583 popValue(); | |
584 addBranches(dflt, labels); | |
585 } | |
586 } | |
587 | |
588 public void visitTableSwitchInsn( | |
589 final int min, | |
590 final int max, | |
591 final Label dflt, | |
592 final Label[] labels){ | |
593 mv.visitTableSwitchInsn(min, max, dflt, labels); | |
594 | |
595 if(constructor) | |
596 { | |
597 popValue(); | |
598 addBranches(dflt, labels); | |
599 } | |
600 } | |
601 | |
602 private void addBranches(final Label dflt, final Label[] labels){ | |
603 addBranch(dflt); | |
604 for(int i = 0; i < labels.length; i++) | |
605 { | |
606 addBranch(labels[i]); | |
607 } | |
608 } | |
609 | |
610 private void addBranch(final Label label){ | |
611 if(branches.containsKey(label)) | |
612 { | |
613 return; | |
614 } | |
615 ArrayList frame = new ArrayList(); | |
616 frame.addAll(stackFrame); | |
617 branches.put(label, frame); | |
618 } | |
619 | |
620 private Object popValue(){ | |
621 return stackFrame.remove(stackFrame.size() - 1); | |
622 } | |
623 | |
624 private Object peekValue(){ | |
625 return stackFrame.get(stackFrame.size() - 1); | |
626 } | |
627 | |
628 private void pushValue(final Object o){ | |
629 stackFrame.add(o); | |
630 } | |
631 | |
632 /** | |
633 * Called at the beginning of the method or after super class class call in | |
634 * the constructor. <br><br> | |
635 * <p/> | |
636 * <i>Custom code can use or change all the local variables, but should not | |
637 * change state of the stack.</i> | |
638 */ | |
639 protected abstract void onMethodEnter(); | |
640 | |
641 /** | |
642 * Called before explicit exit from the method using either return or throw. | |
643 * Top element on the stack contains the return value or exception instance. | |
644 * For example: | |
645 * <p/> | |
646 * <pre> | |
647 * public void onMethodExit(int opcode) { | |
648 * if(opcode==RETURN) { | |
649 * visitInsn(ACONST_NULL); | |
650 * } else if(opcode==ARETURN || opcode==ATHROW) { | |
651 * dup(); | |
652 * } else { | |
653 * if(opcode==LRETURN || opcode==DRETURN) { | |
654 * dup2(); | |
655 * } else { | |
656 * dup(); | |
657 * } | |
658 * box(Type.getReturnType(this.methodDesc)); | |
659 * } | |
660 * visitIntInsn(SIPUSH, opcode); | |
661 * visitMethodInsn(INVOKESTATIC, owner, "onExit", "(Ljava/lang/Object;I)V"); | |
662 * } | |
663 * <p/> | |
664 * // an actual call back method | |
665 * public static void onExit(int opcode, Object param) { | |
666 * ... | |
667 * </pre> | |
668 * <p/> | |
669 * <br><br> | |
670 * <p/> | |
671 * <i>Custom code can use or change all the local variables, but should not | |
672 * change state of the stack.</i> | |
673 * | |
674 * @param opcode one of the RETURN, IRETURN, FRETURN, ARETURN, LRETURN, | |
675 * DRETURN or ATHROW | |
676 */ | |
677 protected abstract void onMethodExit(int opcode); | |
678 | |
679 // TODO onException, onMethodCall | |
680 | |
681 } |