Mercurial > lasercutter
diff 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 |
line wrap: on
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/clojure/asm/commons/AdviceAdapter.java Sat Aug 21 06:25:44 2010 -0400 1.3 @@ -0,0 +1,681 @@ 1.4 +/*** 1.5 + * ASM: a very small and fast Java bytecode manipulation framework 1.6 + * Copyright (c) 2000-2005 INRIA, France Telecom 1.7 + * All rights reserved. 1.8 + * 1.9 + * Redistribution and use in source and binary forms, with or without 1.10 + * modification, are permitted provided that the following conditions 1.11 + * are met: 1.12 + * 1. Redistributions of source code must retain the above copyright 1.13 + * notice, this list of conditions and the following disclaimer. 1.14 + * 2. Redistributions in binary form must reproduce the above copyright 1.15 + * notice, this list of conditions and the following disclaimer in the 1.16 + * documentation and/or other materials provided with the distribution. 1.17 + * 3. Neither the name of the copyright holders nor the names of its 1.18 + * contributors may be used to endorse or promote products derived from 1.19 + * this software without specific prior written permission. 1.20 + * 1.21 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 1.22 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1.23 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1.24 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 1.25 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 1.26 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 1.27 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 1.28 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 1.29 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 1.30 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 1.31 + * THE POSSIBILITY OF SUCH DAMAGE. 1.32 + */ 1.33 +package clojure.asm.commons; 1.34 + 1.35 +import java.util.ArrayList; 1.36 +import java.util.HashMap; 1.37 + 1.38 +import clojure.asm.Label; 1.39 +import clojure.asm.MethodVisitor; 1.40 +import clojure.asm.Opcodes; 1.41 +import clojure.asm.Type; 1.42 + 1.43 +/** 1.44 + * A {@link clojure.asm.MethodAdapter} to insert before, after and around 1.45 + * advices in methods and constructors. <p> The behavior for constructors is 1.46 + * like this: <ol> 1.47 + * <p/> 1.48 + * <li>as long as the INVOKESPECIAL for the object initialization has not been 1.49 + * reached, every bytecode instruction is dispatched in the ctor code visitor</li> 1.50 + * <p/> 1.51 + * <li>when this one is reached, it is only added in the ctor code visitor and 1.52 + * a JP invoke is added</li> 1.53 + * <p/> 1.54 + * <li>after that, only the other code visitor receives the instructions</li> 1.55 + * <p/> 1.56 + * </ol> 1.57 + * 1.58 + * @author Eugene Kuleshov 1.59 + * @author Eric Bruneton 1.60 + */ 1.61 +public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes{ 1.62 +private static final Object THIS = new Object(); 1.63 +private static final Object OTHER = new Object(); 1.64 + 1.65 +protected int methodAccess; 1.66 +protected String methodDesc; 1.67 + 1.68 +private boolean constructor; 1.69 +private boolean superInitialized; 1.70 +private ArrayList stackFrame; 1.71 +private HashMap branches; 1.72 + 1.73 +/** 1.74 + * Creates a new {@link AdviceAdapter}. 1.75 + * 1.76 + * @param mv the method visitor to which this adapter delegates calls. 1.77 + * @param access the method's access flags (see {@link Opcodes}). 1.78 + * @param name the method's name. 1.79 + * @param desc the method's descriptor (see {@link Type Type}). 1.80 + */ 1.81 +public AdviceAdapter( 1.82 + final MethodVisitor mv, 1.83 + final int access, 1.84 + final String name, 1.85 + final String desc){ 1.86 + super(mv, access, name, desc); 1.87 + methodAccess = access; 1.88 + methodDesc = desc; 1.89 + 1.90 + constructor = "<init>".equals(name); 1.91 +} 1.92 + 1.93 +public void visitCode(){ 1.94 + mv.visitCode(); 1.95 + if(!constructor) 1.96 + { 1.97 + superInitialized = true; 1.98 + onMethodEnter(); 1.99 + } 1.100 + else 1.101 + { 1.102 + stackFrame = new ArrayList(); 1.103 + branches = new HashMap(); 1.104 + } 1.105 +} 1.106 + 1.107 +public void visitLabel(final Label label){ 1.108 + mv.visitLabel(label); 1.109 + 1.110 + if(constructor && branches != null) 1.111 + { 1.112 + ArrayList frame = (ArrayList) branches.get(label); 1.113 + if(frame != null) 1.114 + { 1.115 + stackFrame = frame; 1.116 + branches.remove(label); 1.117 + } 1.118 + } 1.119 +} 1.120 + 1.121 +public void visitInsn(final int opcode){ 1.122 + if(constructor) 1.123 + { 1.124 + switch(opcode) 1.125 + { 1.126 + case RETURN: // empty stack 1.127 + onMethodExit(opcode); 1.128 + break; 1.129 + 1.130 + case IRETURN: // 1 before n/a after 1.131 + case FRETURN: // 1 before n/a after 1.132 + case ARETURN: // 1 before n/a after 1.133 + case ATHROW: // 1 before n/a after 1.134 + popValue(); 1.135 + popValue(); 1.136 + onMethodExit(opcode); 1.137 + break; 1.138 + 1.139 + case LRETURN: // 2 before n/a after 1.140 + case DRETURN: // 2 before n/a after 1.141 + popValue(); 1.142 + popValue(); 1.143 + onMethodExit(opcode); 1.144 + break; 1.145 + 1.146 + case NOP: 1.147 + case LALOAD: // remove 2 add 2 1.148 + case DALOAD: // remove 2 add 2 1.149 + case LNEG: 1.150 + case DNEG: 1.151 + case FNEG: 1.152 + case INEG: 1.153 + case L2D: 1.154 + case D2L: 1.155 + case F2I: 1.156 + case I2B: 1.157 + case I2C: 1.158 + case I2S: 1.159 + case I2F: 1.160 + case Opcodes.ARRAYLENGTH: 1.161 + break; 1.162 + 1.163 + case ACONST_NULL: 1.164 + case ICONST_M1: 1.165 + case ICONST_0: 1.166 + case ICONST_1: 1.167 + case ICONST_2: 1.168 + case ICONST_3: 1.169 + case ICONST_4: 1.170 + case ICONST_5: 1.171 + case FCONST_0: 1.172 + case FCONST_1: 1.173 + case FCONST_2: 1.174 + case F2L: // 1 before 2 after 1.175 + case F2D: 1.176 + case I2L: 1.177 + case I2D: 1.178 + pushValue(OTHER); 1.179 + break; 1.180 + 1.181 + case LCONST_0: 1.182 + case LCONST_1: 1.183 + case DCONST_0: 1.184 + case DCONST_1: 1.185 + pushValue(OTHER); 1.186 + pushValue(OTHER); 1.187 + break; 1.188 + 1.189 + case IALOAD: // remove 2 add 1 1.190 + case FALOAD: // remove 2 add 1 1.191 + case AALOAD: // remove 2 add 1 1.192 + case BALOAD: // remove 2 add 1 1.193 + case CALOAD: // remove 2 add 1 1.194 + case SALOAD: // remove 2 add 1 1.195 + case POP: 1.196 + case IADD: 1.197 + case FADD: 1.198 + case ISUB: 1.199 + case LSHL: // 3 before 2 after 1.200 + case LSHR: // 3 before 2 after 1.201 + case LUSHR: // 3 before 2 after 1.202 + case L2I: // 2 before 1 after 1.203 + case L2F: // 2 before 1 after 1.204 + case D2I: // 2 before 1 after 1.205 + case D2F: // 2 before 1 after 1.206 + case FSUB: 1.207 + case FMUL: 1.208 + case FDIV: 1.209 + case FREM: 1.210 + case FCMPL: // 2 before 1 after 1.211 + case FCMPG: // 2 before 1 after 1.212 + case IMUL: 1.213 + case IDIV: 1.214 + case IREM: 1.215 + case ISHL: 1.216 + case ISHR: 1.217 + case IUSHR: 1.218 + case IAND: 1.219 + case IOR: 1.220 + case IXOR: 1.221 + case MONITORENTER: 1.222 + case MONITOREXIT: 1.223 + popValue(); 1.224 + break; 1.225 + 1.226 + case POP2: 1.227 + case LSUB: 1.228 + case LMUL: 1.229 + case LDIV: 1.230 + case LREM: 1.231 + case LADD: 1.232 + case LAND: 1.233 + case LOR: 1.234 + case LXOR: 1.235 + case DADD: 1.236 + case DMUL: 1.237 + case DSUB: 1.238 + case DDIV: 1.239 + case DREM: 1.240 + popValue(); 1.241 + popValue(); 1.242 + break; 1.243 + 1.244 + case IASTORE: 1.245 + case FASTORE: 1.246 + case AASTORE: 1.247 + case BASTORE: 1.248 + case CASTORE: 1.249 + case SASTORE: 1.250 + case LCMP: // 4 before 1 after 1.251 + case DCMPL: 1.252 + case DCMPG: 1.253 + popValue(); 1.254 + popValue(); 1.255 + popValue(); 1.256 + break; 1.257 + 1.258 + case LASTORE: 1.259 + case DASTORE: 1.260 + popValue(); 1.261 + popValue(); 1.262 + popValue(); 1.263 + popValue(); 1.264 + break; 1.265 + 1.266 + case DUP: 1.267 + pushValue(peekValue()); 1.268 + break; 1.269 + 1.270 + case DUP_X1: 1.271 + // TODO optimize this 1.272 + { 1.273 + Object o1 = popValue(); 1.274 + Object o2 = popValue(); 1.275 + pushValue(o1); 1.276 + pushValue(o2); 1.277 + pushValue(o1); 1.278 + } 1.279 + break; 1.280 + 1.281 + case DUP_X2: 1.282 + // TODO optimize this 1.283 + { 1.284 + Object o1 = popValue(); 1.285 + Object o2 = popValue(); 1.286 + Object o3 = popValue(); 1.287 + pushValue(o1); 1.288 + pushValue(o3); 1.289 + pushValue(o2); 1.290 + pushValue(o1); 1.291 + } 1.292 + break; 1.293 + 1.294 + case DUP2: 1.295 + // TODO optimize this 1.296 + { 1.297 + Object o1 = popValue(); 1.298 + Object o2 = popValue(); 1.299 + pushValue(o2); 1.300 + pushValue(o1); 1.301 + pushValue(o2); 1.302 + pushValue(o1); 1.303 + } 1.304 + break; 1.305 + 1.306 + case DUP2_X1: 1.307 + // TODO optimize this 1.308 + { 1.309 + Object o1 = popValue(); 1.310 + Object o2 = popValue(); 1.311 + Object o3 = popValue(); 1.312 + pushValue(o2); 1.313 + pushValue(o1); 1.314 + pushValue(o3); 1.315 + pushValue(o2); 1.316 + pushValue(o1); 1.317 + } 1.318 + break; 1.319 + 1.320 + case DUP2_X2: 1.321 + // TODO optimize this 1.322 + { 1.323 + Object o1 = popValue(); 1.324 + Object o2 = popValue(); 1.325 + Object o3 = popValue(); 1.326 + Object o4 = popValue(); 1.327 + pushValue(o2); 1.328 + pushValue(o1); 1.329 + pushValue(o4); 1.330 + pushValue(o3); 1.331 + pushValue(o2); 1.332 + pushValue(o1); 1.333 + } 1.334 + break; 1.335 + 1.336 + case SWAP: 1.337 + { 1.338 + Object o1 = popValue(); 1.339 + Object o2 = popValue(); 1.340 + pushValue(o1); 1.341 + pushValue(o2); 1.342 + } 1.343 + break; 1.344 + } 1.345 + } 1.346 + else 1.347 + { 1.348 + switch(opcode) 1.349 + { 1.350 + case RETURN: 1.351 + case IRETURN: 1.352 + case FRETURN: 1.353 + case ARETURN: 1.354 + case LRETURN: 1.355 + case DRETURN: 1.356 + case ATHROW: 1.357 + onMethodExit(opcode); 1.358 + break; 1.359 + } 1.360 + } 1.361 + mv.visitInsn(opcode); 1.362 +} 1.363 + 1.364 +public void visitVarInsn(final int opcode, final int var){ 1.365 + super.visitVarInsn(opcode, var); 1.366 + 1.367 + if(constructor) 1.368 + { 1.369 + switch(opcode) 1.370 + { 1.371 + case ILOAD: 1.372 + case FLOAD: 1.373 + pushValue(OTHER); 1.374 + break; 1.375 + case LLOAD: 1.376 + case DLOAD: 1.377 + pushValue(OTHER); 1.378 + pushValue(OTHER); 1.379 + break; 1.380 + case ALOAD: 1.381 + pushValue(var == 0 ? THIS : OTHER); 1.382 + break; 1.383 + case ASTORE: 1.384 + case ISTORE: 1.385 + case FSTORE: 1.386 + popValue(); 1.387 + break; 1.388 + case LSTORE: 1.389 + case DSTORE: 1.390 + popValue(); 1.391 + popValue(); 1.392 + break; 1.393 + } 1.394 + } 1.395 +} 1.396 + 1.397 +public void visitFieldInsn( 1.398 + final int opcode, 1.399 + final String owner, 1.400 + final String name, 1.401 + final String desc){ 1.402 + mv.visitFieldInsn(opcode, owner, name, desc); 1.403 + 1.404 + if(constructor) 1.405 + { 1.406 + char c = desc.charAt(0); 1.407 + boolean longOrDouble = c == 'J' || c == 'D'; 1.408 + switch(opcode) 1.409 + { 1.410 + case GETSTATIC: 1.411 + pushValue(OTHER); 1.412 + if(longOrDouble) 1.413 + { 1.414 + pushValue(OTHER); 1.415 + } 1.416 + break; 1.417 + case PUTSTATIC: 1.418 + popValue(); 1.419 + if(longOrDouble) 1.420 + { 1.421 + popValue(); 1.422 + } 1.423 + break; 1.424 + case PUTFIELD: 1.425 + popValue(); 1.426 + if(longOrDouble) 1.427 + { 1.428 + popValue(); 1.429 + popValue(); 1.430 + } 1.431 + break; 1.432 + // case GETFIELD: 1.433 + default: 1.434 + if(longOrDouble) 1.435 + { 1.436 + pushValue(OTHER); 1.437 + } 1.438 + } 1.439 + } 1.440 +} 1.441 + 1.442 +public void visitIntInsn(final int opcode, final int operand){ 1.443 + mv.visitIntInsn(opcode, operand); 1.444 + 1.445 + if(constructor && opcode != NEWARRAY) 1.446 + { 1.447 + pushValue(OTHER); 1.448 + } 1.449 +} 1.450 + 1.451 +public void visitLdcInsn(final Object cst){ 1.452 + mv.visitLdcInsn(cst); 1.453 + 1.454 + if(constructor) 1.455 + { 1.456 + pushValue(OTHER); 1.457 + if(cst instanceof Double || cst instanceof Long) 1.458 + { 1.459 + pushValue(OTHER); 1.460 + } 1.461 + } 1.462 +} 1.463 + 1.464 +public void visitMultiANewArrayInsn(final String desc, final int dims){ 1.465 + mv.visitMultiANewArrayInsn(desc, dims); 1.466 + 1.467 + if(constructor) 1.468 + { 1.469 + for(int i = 0; i < dims; i++) 1.470 + { 1.471 + popValue(); 1.472 + } 1.473 + pushValue(OTHER); 1.474 + } 1.475 +} 1.476 + 1.477 +public void visitTypeInsn(final int opcode, final String name){ 1.478 + mv.visitTypeInsn(opcode, name); 1.479 + 1.480 + // ANEWARRAY, CHECKCAST or INSTANCEOF don't change stack 1.481 + if(constructor && opcode == NEW) 1.482 + { 1.483 + pushValue(OTHER); 1.484 + } 1.485 +} 1.486 + 1.487 +public void visitMethodInsn( 1.488 + final int opcode, 1.489 + final String owner, 1.490 + final String name, 1.491 + final String desc){ 1.492 + mv.visitMethodInsn(opcode, owner, name, desc); 1.493 + 1.494 + if(constructor) 1.495 + { 1.496 + Type[] types = Type.getArgumentTypes(desc); 1.497 + for(int i = 0; i < types.length; i++) 1.498 + { 1.499 + popValue(); 1.500 + if(types[i].getSize() == 2) 1.501 + { 1.502 + popValue(); 1.503 + } 1.504 + } 1.505 + switch(opcode) 1.506 + { 1.507 + // case INVOKESTATIC: 1.508 + // break; 1.509 + 1.510 + case INVOKEINTERFACE: 1.511 + case INVOKEVIRTUAL: 1.512 + popValue(); // objectref 1.513 + break; 1.514 + 1.515 + case INVOKESPECIAL: 1.516 + Object type = popValue(); // objectref 1.517 + if(type == THIS && !superInitialized) 1.518 + { 1.519 + onMethodEnter(); 1.520 + superInitialized = true; 1.521 + // once super has been initialized it is no longer 1.522 + // necessary to keep track of stack state 1.523 + constructor = false; 1.524 + } 1.525 + break; 1.526 + } 1.527 + 1.528 + Type returnType = Type.getReturnType(desc); 1.529 + if(returnType != Type.VOID_TYPE) 1.530 + { 1.531 + pushValue(OTHER); 1.532 + if(returnType.getSize() == 2) 1.533 + { 1.534 + pushValue(OTHER); 1.535 + } 1.536 + } 1.537 + } 1.538 +} 1.539 + 1.540 +public void visitJumpInsn(final int opcode, final Label label){ 1.541 + mv.visitJumpInsn(opcode, label); 1.542 + 1.543 + if(constructor) 1.544 + { 1.545 + switch(opcode) 1.546 + { 1.547 + case IFEQ: 1.548 + case IFNE: 1.549 + case IFLT: 1.550 + case IFGE: 1.551 + case IFGT: 1.552 + case IFLE: 1.553 + case IFNULL: 1.554 + case IFNONNULL: 1.555 + popValue(); 1.556 + break; 1.557 + 1.558 + case IF_ICMPEQ: 1.559 + case IF_ICMPNE: 1.560 + case IF_ICMPLT: 1.561 + case IF_ICMPGE: 1.562 + case IF_ICMPGT: 1.563 + case IF_ICMPLE: 1.564 + case IF_ACMPEQ: 1.565 + case IF_ACMPNE: 1.566 + popValue(); 1.567 + popValue(); 1.568 + break; 1.569 + 1.570 + case JSR: 1.571 + pushValue(OTHER); 1.572 + break; 1.573 + } 1.574 + addBranch(label); 1.575 + } 1.576 +} 1.577 + 1.578 +public void visitLookupSwitchInsn( 1.579 + final Label dflt, 1.580 + final int[] keys, 1.581 + final Label[] labels){ 1.582 + mv.visitLookupSwitchInsn(dflt, keys, labels); 1.583 + 1.584 + if(constructor) 1.585 + { 1.586 + popValue(); 1.587 + addBranches(dflt, labels); 1.588 + } 1.589 +} 1.590 + 1.591 +public void visitTableSwitchInsn( 1.592 + final int min, 1.593 + final int max, 1.594 + final Label dflt, 1.595 + final Label[] labels){ 1.596 + mv.visitTableSwitchInsn(min, max, dflt, labels); 1.597 + 1.598 + if(constructor) 1.599 + { 1.600 + popValue(); 1.601 + addBranches(dflt, labels); 1.602 + } 1.603 +} 1.604 + 1.605 +private void addBranches(final Label dflt, final Label[] labels){ 1.606 + addBranch(dflt); 1.607 + for(int i = 0; i < labels.length; i++) 1.608 + { 1.609 + addBranch(labels[i]); 1.610 + } 1.611 +} 1.612 + 1.613 +private void addBranch(final Label label){ 1.614 + if(branches.containsKey(label)) 1.615 + { 1.616 + return; 1.617 + } 1.618 + ArrayList frame = new ArrayList(); 1.619 + frame.addAll(stackFrame); 1.620 + branches.put(label, frame); 1.621 +} 1.622 + 1.623 +private Object popValue(){ 1.624 + return stackFrame.remove(stackFrame.size() - 1); 1.625 +} 1.626 + 1.627 +private Object peekValue(){ 1.628 + return stackFrame.get(stackFrame.size() - 1); 1.629 +} 1.630 + 1.631 +private void pushValue(final Object o){ 1.632 + stackFrame.add(o); 1.633 +} 1.634 + 1.635 +/** 1.636 + * Called at the beginning of the method or after super class class call in 1.637 + * the constructor. <br><br> 1.638 + * <p/> 1.639 + * <i>Custom code can use or change all the local variables, but should not 1.640 + * change state of the stack.</i> 1.641 + */ 1.642 +protected abstract void onMethodEnter(); 1.643 + 1.644 +/** 1.645 + * Called before explicit exit from the method using either return or throw. 1.646 + * Top element on the stack contains the return value or exception instance. 1.647 + * For example: 1.648 + * <p/> 1.649 + * <pre> 1.650 + * public void onMethodExit(int opcode) { 1.651 + * if(opcode==RETURN) { 1.652 + * visitInsn(ACONST_NULL); 1.653 + * } else if(opcode==ARETURN || opcode==ATHROW) { 1.654 + * dup(); 1.655 + * } else { 1.656 + * if(opcode==LRETURN || opcode==DRETURN) { 1.657 + * dup2(); 1.658 + * } else { 1.659 + * dup(); 1.660 + * } 1.661 + * box(Type.getReturnType(this.methodDesc)); 1.662 + * } 1.663 + * visitIntInsn(SIPUSH, opcode); 1.664 + * visitMethodInsn(INVOKESTATIC, owner, "onExit", "(Ljava/lang/Object;I)V"); 1.665 + * } 1.666 + * <p/> 1.667 + * // an actual call back method 1.668 + * public static void onExit(int opcode, Object param) { 1.669 + * ... 1.670 + * </pre> 1.671 + * <p/> 1.672 + * <br><br> 1.673 + * <p/> 1.674 + * <i>Custom code can use or change all the local variables, but should not 1.675 + * change state of the stack.</i> 1.676 + * 1.677 + * @param opcode one of the RETURN, IRETURN, FRETURN, ARETURN, LRETURN, 1.678 + * DRETURN or ATHROW 1.679 + */ 1.680 +protected abstract void onMethodExit(int opcode); 1.681 + 1.682 +// TODO onException, onMethodCall 1.683 + 1.684 +}