Mercurial > lasercutter
diff src/clojure/asm/commons/GeneratorAdapter.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/GeneratorAdapter.java Sat Aug 21 06:25:44 2010 -0400 1.3 @@ -0,0 +1,1533 @@ 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.Arrays; 1.37 +import java.util.List; 1.38 + 1.39 +import clojure.asm.ClassVisitor; 1.40 +import clojure.asm.Label; 1.41 +import clojure.asm.MethodVisitor; 1.42 +import clojure.asm.Opcodes; 1.43 +import clojure.asm.Type; 1.44 + 1.45 +/** 1.46 + * A {@link clojure.asm.MethodAdapter} with convenient methods to generate 1.47 + * code. For example, using this adapter, the class below 1.48 + * <p/> 1.49 + * <pre> 1.50 + * public class Example { 1.51 + * public static void main(String[] args) { 1.52 + * System.out.println("Hello world!"); 1.53 + * } 1.54 + * } 1.55 + * </pre> 1.56 + * <p/> 1.57 + * can be generated as follows: 1.58 + * <p/> 1.59 + * <pre> 1.60 + * ClassWriter cw = new ClassWriter(true); 1.61 + * cw.visit(V1_1, ACC_PUBLIC, "Example", null, "java/lang/Object", null); 1.62 + * <p/> 1.63 + * Method m = Method.getMethod("void <init> ()"); 1.64 + * GeneratorAdapter mg = new GeneratorAdapter(ACC_PUBLIC, m, null, null, cw); 1.65 + * mg.loadThis(); 1.66 + * mg.invokeConstructor(Type.getType(Object.class), m); 1.67 + * mg.returnValue(); 1.68 + * mg.endMethod(); 1.69 + * <p/> 1.70 + * m = Method.getMethod("void main (String[])"); 1.71 + * mg = new GeneratorAdapter(ACC_PUBLIC + ACC_STATIC, m, null, null, cw); 1.72 + * mg.getStatic(Type.getType(System.class), "out", Type.getType(PrintStream.class)); 1.73 + * mg.push("Hello world!"); 1.74 + * mg.invokeVirtual(Type.getType(PrintStream.class), Method.getMethod("void println (String)")); 1.75 + * mg.returnValue(); 1.76 + * mg.endMethod(); 1.77 + * <p/> 1.78 + * cw.visitEnd(); 1.79 + * </pre> 1.80 + * 1.81 + * @author Juozas Baliuka 1.82 + * @author Chris Nokleberg 1.83 + * @author Eric Bruneton 1.84 + */ 1.85 +public class GeneratorAdapter extends LocalVariablesSorter{ 1.86 + 1.87 +private final static Type BYTE_TYPE = Type.getObjectType("java/lang/Byte"); 1.88 + 1.89 +private final static Type BOOLEAN_TYPE = Type.getObjectType("java/lang/Boolean"); 1.90 + 1.91 +private final static Type SHORT_TYPE = Type.getObjectType("java/lang/Short"); 1.92 + 1.93 +private final static Type CHARACTER_TYPE = Type.getObjectType("java/lang/Character"); 1.94 + 1.95 +private final static Type INTEGER_TYPE = Type.getObjectType("java/lang/Integer"); 1.96 + 1.97 +private final static Type FLOAT_TYPE = Type.getObjectType("java/lang/Float"); 1.98 + 1.99 +private final static Type LONG_TYPE = Type.getObjectType("java/lang/Long"); 1.100 + 1.101 +private final static Type DOUBLE_TYPE = Type.getObjectType("java/lang/Double"); 1.102 + 1.103 +private final static Type NUMBER_TYPE = Type.getObjectType("java/lang/Number"); 1.104 + 1.105 +private final static Type OBJECT_TYPE = Type.getObjectType("java/lang/Object"); 1.106 + 1.107 +private final static Method BOOLEAN_VALUE = Method.getMethod("boolean booleanValue()"); 1.108 + 1.109 +private final static Method CHAR_VALUE = Method.getMethod("char charValue()"); 1.110 + 1.111 +private final static Method INT_VALUE = Method.getMethod("int intValue()"); 1.112 + 1.113 +private final static Method FLOAT_VALUE = Method.getMethod("float floatValue()"); 1.114 + 1.115 +private final static Method LONG_VALUE = Method.getMethod("long longValue()"); 1.116 + 1.117 +private final static Method DOUBLE_VALUE = Method.getMethod("double doubleValue()"); 1.118 + 1.119 +/** 1.120 + * Constant for the {@link #math math} method. 1.121 + */ 1.122 +public final static int ADD = Opcodes.IADD; 1.123 + 1.124 +/** 1.125 + * Constant for the {@link #math math} method. 1.126 + */ 1.127 +public final static int SUB = Opcodes.ISUB; 1.128 + 1.129 +/** 1.130 + * Constant for the {@link #math math} method. 1.131 + */ 1.132 +public final static int MUL = Opcodes.IMUL; 1.133 + 1.134 +/** 1.135 + * Constant for the {@link #math math} method. 1.136 + */ 1.137 +public final static int DIV = Opcodes.IDIV; 1.138 + 1.139 +/** 1.140 + * Constant for the {@link #math math} method. 1.141 + */ 1.142 +public final static int REM = Opcodes.IREM; 1.143 + 1.144 +/** 1.145 + * Constant for the {@link #math math} method. 1.146 + */ 1.147 +public final static int NEG = Opcodes.INEG; 1.148 + 1.149 +/** 1.150 + * Constant for the {@link #math math} method. 1.151 + */ 1.152 +public final static int SHL = Opcodes.ISHL; 1.153 + 1.154 +/** 1.155 + * Constant for the {@link #math math} method. 1.156 + */ 1.157 +public final static int SHR = Opcodes.ISHR; 1.158 + 1.159 +/** 1.160 + * Constant for the {@link #math math} method. 1.161 + */ 1.162 +public final static int USHR = Opcodes.IUSHR; 1.163 + 1.164 +/** 1.165 + * Constant for the {@link #math math} method. 1.166 + */ 1.167 +public final static int AND = Opcodes.IAND; 1.168 + 1.169 +/** 1.170 + * Constant for the {@link #math math} method. 1.171 + */ 1.172 +public final static int OR = Opcodes.IOR; 1.173 + 1.174 +/** 1.175 + * Constant for the {@link #math math} method. 1.176 + */ 1.177 +public final static int XOR = Opcodes.IXOR; 1.178 + 1.179 +/** 1.180 + * Constant for the {@link #ifCmp ifCmp} method. 1.181 + */ 1.182 +public final static int EQ = Opcodes.IFEQ; 1.183 + 1.184 +/** 1.185 + * Constant for the {@link #ifCmp ifCmp} method. 1.186 + */ 1.187 +public final static int NE = Opcodes.IFNE; 1.188 + 1.189 +/** 1.190 + * Constant for the {@link #ifCmp ifCmp} method. 1.191 + */ 1.192 +public final static int LT = Opcodes.IFLT; 1.193 + 1.194 +/** 1.195 + * Constant for the {@link #ifCmp ifCmp} method. 1.196 + */ 1.197 +public final static int GE = Opcodes.IFGE; 1.198 + 1.199 +/** 1.200 + * Constant for the {@link #ifCmp ifCmp} method. 1.201 + */ 1.202 +public final static int GT = Opcodes.IFGT; 1.203 + 1.204 +/** 1.205 + * Constant for the {@link #ifCmp ifCmp} method. 1.206 + */ 1.207 +public final static int LE = Opcodes.IFLE; 1.208 + 1.209 +/** 1.210 + * Access flags of the method visited by this adapter. 1.211 + */ 1.212 +private final int access; 1.213 + 1.214 +/** 1.215 + * Return type of the method visited by this adapter. 1.216 + */ 1.217 +private final Type returnType; 1.218 + 1.219 +/** 1.220 + * Argument types of the method visited by this adapter. 1.221 + */ 1.222 +private final Type[] argumentTypes; 1.223 + 1.224 +/** 1.225 + * Types of the local variables of the method visited by this adapter. 1.226 + */ 1.227 +private final List localTypes = new ArrayList(); 1.228 + 1.229 +/** 1.230 + * Creates a new {@link GeneratorAdapter}. 1.231 + * 1.232 + * @param mv the method visitor to which this adapter delegates calls. 1.233 + * @param access the method's access flags (see {@link Opcodes}). 1.234 + * @param name the method's name. 1.235 + * @param desc the method's descriptor (see {@link Type Type}). 1.236 + */ 1.237 +public GeneratorAdapter( 1.238 + final MethodVisitor mv, 1.239 + final int access, 1.240 + final String name, 1.241 + final String desc){ 1.242 + super(access, desc, mv); 1.243 + this.access = access; 1.244 + this.returnType = Type.getReturnType(desc); 1.245 + this.argumentTypes = Type.getArgumentTypes(desc); 1.246 +} 1.247 + 1.248 +/** 1.249 + * Creates a new {@link GeneratorAdapter}. 1.250 + * 1.251 + * @param access access flags of the adapted method. 1.252 + * @param method the adapted method. 1.253 + * @param mv the method visitor to which this adapter delegates calls. 1.254 + */ 1.255 +public GeneratorAdapter( 1.256 + final int access, 1.257 + final Method method, 1.258 + final MethodVisitor mv){ 1.259 + super(access, method.getDescriptor(), mv); 1.260 + this.access = access; 1.261 + this.returnType = method.getReturnType(); 1.262 + this.argumentTypes = method.getArgumentTypes(); 1.263 +} 1.264 + 1.265 +/** 1.266 + * Creates a new {@link GeneratorAdapter}. 1.267 + * 1.268 + * @param access access flags of the adapted method. 1.269 + * @param method the adapted method. 1.270 + * @param signature the signature of the adapted method (may be 1.271 + * <tt>null</tt>). 1.272 + * @param exceptions the exceptions thrown by the adapted method (may be 1.273 + * <tt>null</tt>). 1.274 + * @param cv the class visitor to which this adapter delegates calls. 1.275 + */ 1.276 +public GeneratorAdapter( 1.277 + final int access, 1.278 + final Method method, 1.279 + final String signature, 1.280 + final Type[] exceptions, 1.281 + final ClassVisitor cv){ 1.282 + this(access, method, cv.visitMethod(access, 1.283 + method.getName(), 1.284 + method.getDescriptor(), 1.285 + signature, 1.286 + getInternalNames(exceptions))); 1.287 +} 1.288 + 1.289 +/** 1.290 + * Returns the internal names of the given types. 1.291 + * 1.292 + * @param types a set of types. 1.293 + * @return the internal names of the given types. 1.294 + */ 1.295 +private static String[] getInternalNames(final Type[] types){ 1.296 + if(types == null) 1.297 + { 1.298 + return null; 1.299 + } 1.300 + String[] names = new String[types.length]; 1.301 + for(int i = 0; i < names.length; ++i) 1.302 + { 1.303 + names[i] = types[i].getInternalName(); 1.304 + } 1.305 + return names; 1.306 +} 1.307 + 1.308 +// ------------------------------------------------------------------------ 1.309 +// Instructions to push constants on the stack 1.310 +// ------------------------------------------------------------------------ 1.311 + 1.312 +/** 1.313 + * Generates the instruction to push the given value on the stack. 1.314 + * 1.315 + * @param value the value to be pushed on the stack. 1.316 + */ 1.317 +public void push(final boolean value){ 1.318 + push(value ? 1 : 0); 1.319 +} 1.320 + 1.321 +/** 1.322 + * Generates the instruction to push the given value on the stack. 1.323 + * 1.324 + * @param value the value to be pushed on the stack. 1.325 + */ 1.326 +public void push(final int value){ 1.327 + if(value >= -1 && value <= 5) 1.328 + { 1.329 + mv.visitInsn(Opcodes.ICONST_0 + value); 1.330 + } 1.331 + else if(value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) 1.332 + { 1.333 + mv.visitIntInsn(Opcodes.BIPUSH, value); 1.334 + } 1.335 + else if(value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) 1.336 + { 1.337 + mv.visitIntInsn(Opcodes.SIPUSH, value); 1.338 + } 1.339 + else 1.340 + { 1.341 + mv.visitLdcInsn(new Integer(value)); 1.342 + } 1.343 +} 1.344 + 1.345 +/** 1.346 + * Generates the instruction to push the given value on the stack. 1.347 + * 1.348 + * @param value the value to be pushed on the stack. 1.349 + */ 1.350 +public void push(final long value){ 1.351 + if(value == 0L || value == 1L) 1.352 + { 1.353 + mv.visitInsn(Opcodes.LCONST_0 + (int) value); 1.354 + } 1.355 + else 1.356 + { 1.357 + mv.visitLdcInsn(new Long(value)); 1.358 + } 1.359 +} 1.360 + 1.361 +/** 1.362 + * Generates the instruction to push the given value on the stack. 1.363 + * 1.364 + * @param value the value to be pushed on the stack. 1.365 + */ 1.366 +public void push(final float value){ 1.367 + int bits = Float.floatToIntBits(value); 1.368 + if(bits == 0L || bits == 0x3f800000 || bits == 0x40000000) 1.369 + { // 0..2 1.370 + mv.visitInsn(Opcodes.FCONST_0 + (int) value); 1.371 + } 1.372 + else 1.373 + { 1.374 + mv.visitLdcInsn(new Float(value)); 1.375 + } 1.376 +} 1.377 + 1.378 +/** 1.379 + * Generates the instruction to push the given value on the stack. 1.380 + * 1.381 + * @param value the value to be pushed on the stack. 1.382 + */ 1.383 +public void push(final double value){ 1.384 + long bits = Double.doubleToLongBits(value); 1.385 + if(bits == 0L || bits == 0x3ff0000000000000L) 1.386 + { // +0.0d and 1.0d 1.387 + mv.visitInsn(Opcodes.DCONST_0 + (int) value); 1.388 + } 1.389 + else 1.390 + { 1.391 + mv.visitLdcInsn(new Double(value)); 1.392 + } 1.393 +} 1.394 + 1.395 +/** 1.396 + * Generates the instruction to push the given value on the stack. 1.397 + * 1.398 + * @param value the value to be pushed on the stack. May be <tt>null</tt>. 1.399 + */ 1.400 +public void push(final String value){ 1.401 + if(value == null) 1.402 + { 1.403 + mv.visitInsn(Opcodes.ACONST_NULL); 1.404 + } 1.405 + else 1.406 + { 1.407 + mv.visitLdcInsn(value); 1.408 + } 1.409 +} 1.410 + 1.411 +/** 1.412 + * Generates the instruction to push the given value on the stack. 1.413 + * 1.414 + * @param value the value to be pushed on the stack. 1.415 + */ 1.416 +public void push(final Type value){ 1.417 + if(value == null) 1.418 + { 1.419 + mv.visitInsn(Opcodes.ACONST_NULL); 1.420 + } 1.421 + else 1.422 + { 1.423 + mv.visitLdcInsn(value); 1.424 + } 1.425 +} 1.426 + 1.427 +// ------------------------------------------------------------------------ 1.428 +// Instructions to load and store method arguments 1.429 +// ------------------------------------------------------------------------ 1.430 + 1.431 +/** 1.432 + * Returns the index of the given method argument in the frame's local 1.433 + * variables array. 1.434 + * 1.435 + * @param arg the index of a method argument. 1.436 + * @return the index of the given method argument in the frame's local 1.437 + * variables array. 1.438 + */ 1.439 +private int getArgIndex(final int arg){ 1.440 + int index = (access & Opcodes.ACC_STATIC) == 0 ? 1 : 0; 1.441 + for(int i = 0; i < arg; i++) 1.442 + { 1.443 + index += argumentTypes[i].getSize(); 1.444 + } 1.445 + return index; 1.446 +} 1.447 + 1.448 +/** 1.449 + * Generates the instruction to push a local variable on the stack. 1.450 + * 1.451 + * @param type the type of the local variable to be loaded. 1.452 + * @param index an index in the frame's local variables array. 1.453 + */ 1.454 +private void loadInsn(final Type type, final int index){ 1.455 + mv.visitVarInsn(type.getOpcode(Opcodes.ILOAD), index); 1.456 +} 1.457 + 1.458 +/** 1.459 + * Generates the instruction to store the top stack value in a local 1.460 + * variable. 1.461 + * 1.462 + * @param type the type of the local variable to be stored. 1.463 + * @param index an index in the frame's local variables array. 1.464 + */ 1.465 +private void storeInsn(final Type type, final int index){ 1.466 + mv.visitVarInsn(type.getOpcode(Opcodes.ISTORE), index); 1.467 +} 1.468 + 1.469 +/** 1.470 + * Generates the instruction to load 'this' on the stack. 1.471 + */ 1.472 +public void loadThis(){ 1.473 + if((access & Opcodes.ACC_STATIC) != 0) 1.474 + { 1.475 + throw new IllegalStateException("no 'this' pointer within static method"); 1.476 + } 1.477 + mv.visitVarInsn(Opcodes.ALOAD, 0); 1.478 +} 1.479 + 1.480 +/** 1.481 + * Generates the instruction to load the given method argument on the stack. 1.482 + * 1.483 + * @param arg the index of a method argument. 1.484 + */ 1.485 +public void loadArg(final int arg){ 1.486 + loadInsn(argumentTypes[arg], getArgIndex(arg)); 1.487 +} 1.488 + 1.489 +/** 1.490 + * Generates the instructions to load the given method arguments on the 1.491 + * stack. 1.492 + * 1.493 + * @param arg the index of the first method argument to be loaded. 1.494 + * @param count the number of method arguments to be loaded. 1.495 + */ 1.496 +public void loadArgs(final int arg, final int count){ 1.497 + int index = getArgIndex(arg); 1.498 + for(int i = 0; i < count; ++i) 1.499 + { 1.500 + Type t = argumentTypes[arg + i]; 1.501 + loadInsn(t, index); 1.502 + index += t.getSize(); 1.503 + } 1.504 +} 1.505 + 1.506 +/** 1.507 + * Generates the instructions to load all the method arguments on the stack. 1.508 + */ 1.509 +public void loadArgs(){ 1.510 + loadArgs(0, argumentTypes.length); 1.511 +} 1.512 + 1.513 +/** 1.514 + * Generates the instructions to load all the method arguments on the stack, 1.515 + * as a single object array. 1.516 + */ 1.517 +public void loadArgArray(){ 1.518 + push(argumentTypes.length); 1.519 + newArray(OBJECT_TYPE); 1.520 + for(int i = 0; i < argumentTypes.length; i++) 1.521 + { 1.522 + dup(); 1.523 + push(i); 1.524 + loadArg(i); 1.525 + box(argumentTypes[i]); 1.526 + arrayStore(OBJECT_TYPE); 1.527 + } 1.528 +} 1.529 + 1.530 +/** 1.531 + * Generates the instruction to store the top stack value in the given 1.532 + * method argument. 1.533 + * 1.534 + * @param arg the index of a method argument. 1.535 + */ 1.536 +public void storeArg(final int arg){ 1.537 + storeInsn(argumentTypes[arg], getArgIndex(arg)); 1.538 +} 1.539 + 1.540 +// ------------------------------------------------------------------------ 1.541 +// Instructions to load and store local variables 1.542 +// ------------------------------------------------------------------------ 1.543 + 1.544 +/** 1.545 + * Returns the type of the given local variable. 1.546 + * 1.547 + * @param local a local variable identifier, as returned by 1.548 + * {@link LocalVariablesSorter#newLocal(Type) newLocal()}. 1.549 + * @return the type of the given local variable. 1.550 + */ 1.551 +public Type getLocalType(final int local){ 1.552 + return (Type) localTypes.get(local - firstLocal); 1.553 +} 1.554 + 1.555 +protected void setLocalType(final int local, final Type type){ 1.556 + int index = local - firstLocal; 1.557 + while(localTypes.size() < index + 1) 1.558 + { 1.559 + localTypes.add(null); 1.560 + } 1.561 + localTypes.set(index, type); 1.562 +} 1.563 + 1.564 +/** 1.565 + * Generates the instruction to load the given local variable on the stack. 1.566 + * 1.567 + * @param local a local variable identifier, as returned by 1.568 + * {@link LocalVariablesSorter#newLocal(Type) newLocal()}. 1.569 + */ 1.570 +public void loadLocal(final int local){ 1.571 + loadInsn(getLocalType(local), local); 1.572 +} 1.573 + 1.574 +/** 1.575 + * Generates the instruction to load the given local variable on the stack. 1.576 + * 1.577 + * @param local a local variable identifier, as returned by 1.578 + * {@link LocalVariablesSorter#newLocal(Type) newLocal()}. 1.579 + * @param type the type of this local variable. 1.580 + */ 1.581 +public void loadLocal(final int local, final Type type){ 1.582 + setLocalType(local, type); 1.583 + loadInsn(type, local); 1.584 +} 1.585 + 1.586 +/** 1.587 + * Generates the instruction to store the top stack value in the given local 1.588 + * variable. 1.589 + * 1.590 + * @param local a local variable identifier, as returned by 1.591 + * {@link LocalVariablesSorter#newLocal(Type) newLocal()}. 1.592 + */ 1.593 +public void storeLocal(final int local){ 1.594 + storeInsn(getLocalType(local), local); 1.595 +} 1.596 + 1.597 +/** 1.598 + * Generates the instruction to store the top stack value in the given local 1.599 + * variable. 1.600 + * 1.601 + * @param local a local variable identifier, as returned by 1.602 + * {@link LocalVariablesSorter#newLocal(Type) newLocal()}. 1.603 + * @param type the type of this local variable. 1.604 + */ 1.605 +public void storeLocal(final int local, final Type type){ 1.606 + setLocalType(local, type); 1.607 + storeInsn(type, local); 1.608 +} 1.609 + 1.610 +/** 1.611 + * Generates the instruction to load an element from an array. 1.612 + * 1.613 + * @param type the type of the array element to be loaded. 1.614 + */ 1.615 +public void arrayLoad(final Type type){ 1.616 + mv.visitInsn(type.getOpcode(Opcodes.IALOAD)); 1.617 +} 1.618 + 1.619 +/** 1.620 + * Generates the instruction to store an element in an array. 1.621 + * 1.622 + * @param type the type of the array element to be stored. 1.623 + */ 1.624 +public void arrayStore(final Type type){ 1.625 + mv.visitInsn(type.getOpcode(Opcodes.IASTORE)); 1.626 +} 1.627 + 1.628 +// ------------------------------------------------------------------------ 1.629 +// Instructions to manage the stack 1.630 +// ------------------------------------------------------------------------ 1.631 + 1.632 +/** 1.633 + * Generates a POP instruction. 1.634 + */ 1.635 +public void pop(){ 1.636 + mv.visitInsn(Opcodes.POP); 1.637 +} 1.638 + 1.639 +/** 1.640 + * Generates a POP2 instruction. 1.641 + */ 1.642 +public void pop2(){ 1.643 + mv.visitInsn(Opcodes.POP2); 1.644 +} 1.645 + 1.646 +/** 1.647 + * Generates a DUP instruction. 1.648 + */ 1.649 +public void dup(){ 1.650 + mv.visitInsn(Opcodes.DUP); 1.651 +} 1.652 + 1.653 +/** 1.654 + * Generates a DUP2 instruction. 1.655 + */ 1.656 +public void dup2(){ 1.657 + mv.visitInsn(Opcodes.DUP2); 1.658 +} 1.659 + 1.660 +/** 1.661 + * Generates a DUP_X1 instruction. 1.662 + */ 1.663 +public void dupX1(){ 1.664 + mv.visitInsn(Opcodes.DUP_X1); 1.665 +} 1.666 + 1.667 +/** 1.668 + * Generates a DUP_X2 instruction. 1.669 + */ 1.670 +public void dupX2(){ 1.671 + mv.visitInsn(Opcodes.DUP_X2); 1.672 +} 1.673 + 1.674 +/** 1.675 + * Generates a DUP2_X1 instruction. 1.676 + */ 1.677 +public void dup2X1(){ 1.678 + mv.visitInsn(Opcodes.DUP2_X1); 1.679 +} 1.680 + 1.681 +/** 1.682 + * Generates a DUP2_X2 instruction. 1.683 + */ 1.684 +public void dup2X2(){ 1.685 + mv.visitInsn(Opcodes.DUP2_X2); 1.686 +} 1.687 + 1.688 +/** 1.689 + * Generates a SWAP instruction. 1.690 + */ 1.691 +public void swap(){ 1.692 + mv.visitInsn(Opcodes.SWAP); 1.693 +} 1.694 + 1.695 +/** 1.696 + * Generates the instructions to swap the top two stack values. 1.697 + * 1.698 + * @param prev type of the top - 1 stack value. 1.699 + * @param type type of the top stack value. 1.700 + */ 1.701 +public void swap(final Type prev, final Type type){ 1.702 + if(type.getSize() == 1) 1.703 + { 1.704 + if(prev.getSize() == 1) 1.705 + { 1.706 + swap(); // same as dupX1(), pop(); 1.707 + } 1.708 + else 1.709 + { 1.710 + dupX2(); 1.711 + pop(); 1.712 + } 1.713 + } 1.714 + else 1.715 + { 1.716 + if(prev.getSize() == 1) 1.717 + { 1.718 + dup2X1(); 1.719 + pop2(); 1.720 + } 1.721 + else 1.722 + { 1.723 + dup2X2(); 1.724 + pop2(); 1.725 + } 1.726 + } 1.727 +} 1.728 + 1.729 +// ------------------------------------------------------------------------ 1.730 +// Instructions to do mathematical and logical operations 1.731 +// ------------------------------------------------------------------------ 1.732 + 1.733 +/** 1.734 + * Generates the instruction to do the specified mathematical or logical 1.735 + * operation. 1.736 + * 1.737 + * @param op a mathematical or logical operation. Must be one of ADD, SUB, 1.738 + * MUL, DIV, REM, NEG, SHL, SHR, USHR, AND, OR, XOR. 1.739 + * @param type the type of the operand(s) for this operation. 1.740 + */ 1.741 +public void math(final int op, final Type type){ 1.742 + mv.visitInsn(type.getOpcode(op)); 1.743 +} 1.744 + 1.745 +/** 1.746 + * Generates the instructions to compute the bitwise negation of the top 1.747 + * stack value. 1.748 + */ 1.749 +public void not(){ 1.750 + mv.visitInsn(Opcodes.ICONST_1); 1.751 + mv.visitInsn(Opcodes.IXOR); 1.752 +} 1.753 + 1.754 +/** 1.755 + * Generates the instruction to increment the given local variable. 1.756 + * 1.757 + * @param local the local variable to be incremented. 1.758 + * @param amount the amount by which the local variable must be incremented. 1.759 + */ 1.760 +public void iinc(final int local, final int amount){ 1.761 + mv.visitIincInsn(local, amount); 1.762 +} 1.763 + 1.764 +/** 1.765 + * Generates the instructions to cast a numerical value from one type to 1.766 + * another. 1.767 + * 1.768 + * @param from the type of the top stack value 1.769 + * @param to the type into which this value must be cast. 1.770 + */ 1.771 +public void cast(final Type from, final Type to){ 1.772 + if(from != to) 1.773 + { 1.774 + if(from == Type.DOUBLE_TYPE) 1.775 + { 1.776 + if(to == Type.FLOAT_TYPE) 1.777 + { 1.778 + mv.visitInsn(Opcodes.D2F); 1.779 + } 1.780 + else if(to == Type.LONG_TYPE) 1.781 + { 1.782 + mv.visitInsn(Opcodes.D2L); 1.783 + } 1.784 + else 1.785 + { 1.786 + mv.visitInsn(Opcodes.D2I); 1.787 + cast(Type.INT_TYPE, to); 1.788 + } 1.789 + } 1.790 + else if(from == Type.FLOAT_TYPE) 1.791 + { 1.792 + if(to == Type.DOUBLE_TYPE) 1.793 + { 1.794 + mv.visitInsn(Opcodes.F2D); 1.795 + } 1.796 + else if(to == Type.LONG_TYPE) 1.797 + { 1.798 + mv.visitInsn(Opcodes.F2L); 1.799 + } 1.800 + else 1.801 + { 1.802 + mv.visitInsn(Opcodes.F2I); 1.803 + cast(Type.INT_TYPE, to); 1.804 + } 1.805 + } 1.806 + else if(from == Type.LONG_TYPE) 1.807 + { 1.808 + if(to == Type.DOUBLE_TYPE) 1.809 + { 1.810 + mv.visitInsn(Opcodes.L2D); 1.811 + } 1.812 + else if(to == Type.FLOAT_TYPE) 1.813 + { 1.814 + mv.visitInsn(Opcodes.L2F); 1.815 + } 1.816 + else 1.817 + { 1.818 + mv.visitInsn(Opcodes.L2I); 1.819 + cast(Type.INT_TYPE, to); 1.820 + } 1.821 + } 1.822 + else 1.823 + { 1.824 + if(to == Type.BYTE_TYPE) 1.825 + { 1.826 + mv.visitInsn(Opcodes.I2B); 1.827 + } 1.828 + else if(to == Type.CHAR_TYPE) 1.829 + { 1.830 + mv.visitInsn(Opcodes.I2C); 1.831 + } 1.832 + else if(to == Type.DOUBLE_TYPE) 1.833 + { 1.834 + mv.visitInsn(Opcodes.I2D); 1.835 + } 1.836 + else if(to == Type.FLOAT_TYPE) 1.837 + { 1.838 + mv.visitInsn(Opcodes.I2F); 1.839 + } 1.840 + else if(to == Type.LONG_TYPE) 1.841 + { 1.842 + mv.visitInsn(Opcodes.I2L); 1.843 + } 1.844 + else if(to == Type.SHORT_TYPE) 1.845 + { 1.846 + mv.visitInsn(Opcodes.I2S); 1.847 + } 1.848 + } 1.849 + } 1.850 +} 1.851 + 1.852 +// ------------------------------------------------------------------------ 1.853 +// Instructions to do boxing and unboxing operations 1.854 +// ------------------------------------------------------------------------ 1.855 + 1.856 +/** 1.857 + * Generates the instructions to box the top stack value. This value is 1.858 + * replaced by its boxed equivalent on top of the stack. 1.859 + * 1.860 + * @param type the type of the top stack value. 1.861 + */ 1.862 +public void box(final Type type){ 1.863 + if(type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) 1.864 + { 1.865 + return; 1.866 + } 1.867 + if(type == Type.VOID_TYPE) 1.868 + { 1.869 + push((String) null); 1.870 + } 1.871 + else 1.872 + { 1.873 + Type boxed = type; 1.874 + switch(type.getSort()) 1.875 + { 1.876 + case Type.BYTE: 1.877 + boxed = BYTE_TYPE; 1.878 + break; 1.879 + case Type.BOOLEAN: 1.880 + boxed = BOOLEAN_TYPE; 1.881 + break; 1.882 + case Type.SHORT: 1.883 + boxed = SHORT_TYPE; 1.884 + break; 1.885 + case Type.CHAR: 1.886 + boxed = CHARACTER_TYPE; 1.887 + break; 1.888 + case Type.INT: 1.889 + boxed = INTEGER_TYPE; 1.890 + break; 1.891 + case Type.FLOAT: 1.892 + boxed = FLOAT_TYPE; 1.893 + break; 1.894 + case Type.LONG: 1.895 + boxed = LONG_TYPE; 1.896 + break; 1.897 + case Type.DOUBLE: 1.898 + boxed = DOUBLE_TYPE; 1.899 + break; 1.900 + } 1.901 + newInstance(boxed); 1.902 + if(type.getSize() == 2) 1.903 + { 1.904 + // Pp -> Ppo -> oPpo -> ooPpo -> ooPp -> o 1.905 + dupX2(); 1.906 + dupX2(); 1.907 + pop(); 1.908 + } 1.909 + else 1.910 + { 1.911 + // p -> po -> opo -> oop -> o 1.912 + dupX1(); 1.913 + swap(); 1.914 + } 1.915 + invokeConstructor(boxed, new Method("<init>", 1.916 + Type.VOID_TYPE, 1.917 + new Type[]{type})); 1.918 + } 1.919 +} 1.920 + 1.921 +/** 1.922 + * Generates the instructions to unbox the top stack value. This value is 1.923 + * replaced by its unboxed equivalent on top of the stack. 1.924 + * 1.925 + * @param type the type of the top stack value. 1.926 + */ 1.927 +public void unbox(final Type type){ 1.928 + Type t = NUMBER_TYPE; 1.929 + Method sig = null; 1.930 + switch(type.getSort()) 1.931 + { 1.932 + case Type.VOID: 1.933 + return; 1.934 + case Type.CHAR: 1.935 + t = CHARACTER_TYPE; 1.936 + sig = CHAR_VALUE; 1.937 + break; 1.938 + case Type.BOOLEAN: 1.939 + t = BOOLEAN_TYPE; 1.940 + sig = BOOLEAN_VALUE; 1.941 + break; 1.942 + case Type.DOUBLE: 1.943 + sig = DOUBLE_VALUE; 1.944 + break; 1.945 + case Type.FLOAT: 1.946 + sig = FLOAT_VALUE; 1.947 + break; 1.948 + case Type.LONG: 1.949 + sig = LONG_VALUE; 1.950 + break; 1.951 + case Type.INT: 1.952 + case Type.SHORT: 1.953 + case Type.BYTE: 1.954 + sig = INT_VALUE; 1.955 + } 1.956 + if(sig == null) 1.957 + { 1.958 + checkCast(type); 1.959 + } 1.960 + else 1.961 + { 1.962 + checkCast(t); 1.963 + invokeVirtual(t, sig); 1.964 + } 1.965 +} 1.966 + 1.967 +// ------------------------------------------------------------------------ 1.968 +// Instructions to jump to other instructions 1.969 +// ------------------------------------------------------------------------ 1.970 + 1.971 +/** 1.972 + * Creates a new {@link Label}. 1.973 + * 1.974 + * @return a new {@link Label}. 1.975 + */ 1.976 +public Label newLabel(){ 1.977 + return new Label(); 1.978 +} 1.979 + 1.980 +/** 1.981 + * Marks the current code position with the given label. 1.982 + * 1.983 + * @param label a label. 1.984 + */ 1.985 +public void mark(final Label label){ 1.986 + mv.visitLabel(label); 1.987 +} 1.988 + 1.989 +/** 1.990 + * Marks the current code position with a new label. 1.991 + * 1.992 + * @return the label that was created to mark the current code position. 1.993 + */ 1.994 +public Label mark(){ 1.995 + Label label = new Label(); 1.996 + mv.visitLabel(label); 1.997 + return label; 1.998 +} 1.999 + 1.1000 +/** 1.1001 + * Generates the instructions to jump to a label based on the comparison of 1.1002 + * the top two stack values. 1.1003 + * 1.1004 + * @param type the type of the top two stack values. 1.1005 + * @param mode how these values must be compared. One of EQ, NE, LT, GE, GT, 1.1006 + * LE. 1.1007 + * @param label where to jump if the comparison result is <tt>true</tt>. 1.1008 + */ 1.1009 +public void ifCmp(final Type type, final int mode, final Label label){ 1.1010 + int intOp = -1; 1.1011 + switch(type.getSort()) 1.1012 + { 1.1013 + case Type.LONG: 1.1014 + mv.visitInsn(Opcodes.LCMP); 1.1015 + break; 1.1016 + case Type.DOUBLE: 1.1017 + mv.visitInsn(Opcodes.DCMPG); 1.1018 + break; 1.1019 + case Type.FLOAT: 1.1020 + mv.visitInsn(Opcodes.FCMPG); 1.1021 + break; 1.1022 + case Type.ARRAY: 1.1023 + case Type.OBJECT: 1.1024 + switch(mode) 1.1025 + { 1.1026 + case EQ: 1.1027 + mv.visitJumpInsn(Opcodes.IF_ACMPEQ, label); 1.1028 + return; 1.1029 + case NE: 1.1030 + mv.visitJumpInsn(Opcodes.IF_ACMPNE, label); 1.1031 + return; 1.1032 + } 1.1033 + throw new IllegalArgumentException("Bad comparison for type " 1.1034 + + type); 1.1035 + default: 1.1036 + switch(mode) 1.1037 + { 1.1038 + case EQ: 1.1039 + intOp = Opcodes.IF_ICMPEQ; 1.1040 + break; 1.1041 + case NE: 1.1042 + intOp = Opcodes.IF_ICMPNE; 1.1043 + break; 1.1044 + case GE: 1.1045 + intOp = Opcodes.IF_ICMPGE; 1.1046 + break; 1.1047 + case LT: 1.1048 + intOp = Opcodes.IF_ICMPLT; 1.1049 + break; 1.1050 + case LE: 1.1051 + intOp = Opcodes.IF_ICMPLE; 1.1052 + break; 1.1053 + case GT: 1.1054 + intOp = Opcodes.IF_ICMPGT; 1.1055 + break; 1.1056 + } 1.1057 + mv.visitJumpInsn(intOp, label); 1.1058 + return; 1.1059 + } 1.1060 + int jumpMode = mode; 1.1061 + switch(mode) 1.1062 + { 1.1063 + case GE: 1.1064 + jumpMode = LT; 1.1065 + break; 1.1066 + case LE: 1.1067 + jumpMode = GT; 1.1068 + break; 1.1069 + } 1.1070 + mv.visitJumpInsn(jumpMode, label); 1.1071 +} 1.1072 + 1.1073 +/** 1.1074 + * Generates the instructions to jump to a label based on the comparison of 1.1075 + * the top two integer stack values. 1.1076 + * 1.1077 + * @param mode how these values must be compared. One of EQ, NE, LT, GE, GT, 1.1078 + * LE. 1.1079 + * @param label where to jump if the comparison result is <tt>true</tt>. 1.1080 + */ 1.1081 +public void ifICmp(final int mode, final Label label){ 1.1082 + ifCmp(Type.INT_TYPE, mode, label); 1.1083 +} 1.1084 + 1.1085 +/** 1.1086 + * Generates the instructions to jump to a label based on the comparison of 1.1087 + * the top integer stack value with zero. 1.1088 + * 1.1089 + * @param mode how these values must be compared. One of EQ, NE, LT, GE, GT, 1.1090 + * LE. 1.1091 + * @param label where to jump if the comparison result is <tt>true</tt>. 1.1092 + */ 1.1093 +public void ifZCmp(final int mode, final Label label){ 1.1094 + mv.visitJumpInsn(mode, label); 1.1095 +} 1.1096 + 1.1097 +/** 1.1098 + * Generates the instruction to jump to the given label if the top stack 1.1099 + * value is null. 1.1100 + * 1.1101 + * @param label where to jump if the condition is <tt>true</tt>. 1.1102 + */ 1.1103 +public void ifNull(final Label label){ 1.1104 + mv.visitJumpInsn(Opcodes.IFNULL, label); 1.1105 +} 1.1106 + 1.1107 +/** 1.1108 + * Generates the instruction to jump to the given label if the top stack 1.1109 + * value is not null. 1.1110 + * 1.1111 + * @param label where to jump if the condition is <tt>true</tt>. 1.1112 + */ 1.1113 +public void ifNonNull(final Label label){ 1.1114 + mv.visitJumpInsn(Opcodes.IFNONNULL, label); 1.1115 +} 1.1116 + 1.1117 +/** 1.1118 + * Generates the instruction to jump to the given label. 1.1119 + * 1.1120 + * @param label where to jump if the condition is <tt>true</tt>. 1.1121 + */ 1.1122 +public void goTo(final Label label){ 1.1123 + mv.visitJumpInsn(Opcodes.GOTO, label); 1.1124 +} 1.1125 + 1.1126 +/** 1.1127 + * Generates a RET instruction. 1.1128 + * 1.1129 + * @param local a local variable identifier, as returned by 1.1130 + * {@link LocalVariablesSorter#newLocal(Type) newLocal()}. 1.1131 + */ 1.1132 +public void ret(final int local){ 1.1133 + mv.visitVarInsn(Opcodes.RET, local); 1.1134 +} 1.1135 + 1.1136 +/** 1.1137 + * Generates the instructions for a switch statement. 1.1138 + * 1.1139 + * @param keys the switch case keys. 1.1140 + * @param generator a generator to generate the code for the switch cases. 1.1141 + */ 1.1142 +public void tableSwitch( 1.1143 + final int[] keys, 1.1144 + final TableSwitchGenerator generator){ 1.1145 + float density; 1.1146 + if(keys.length == 0) 1.1147 + { 1.1148 + density = 0; 1.1149 + } 1.1150 + else 1.1151 + { 1.1152 + density = (float) keys.length 1.1153 + / (keys[keys.length - 1] - keys[0] + 1); 1.1154 + } 1.1155 + tableSwitch(keys, generator, density >= 0.5f); 1.1156 +} 1.1157 + 1.1158 +/** 1.1159 + * Generates the instructions for a switch statement. 1.1160 + * 1.1161 + * @param keys the switch case keys. 1.1162 + * @param generator a generator to generate the code for the switch cases. 1.1163 + * @param useTable <tt>true</tt> to use a TABLESWITCH instruction, or 1.1164 + * <tt>false</tt> to use a LOOKUPSWITCH instruction. 1.1165 + */ 1.1166 +public void tableSwitch( 1.1167 + final int[] keys, 1.1168 + final TableSwitchGenerator generator, 1.1169 + final boolean useTable){ 1.1170 + for(int i = 1; i < keys.length; ++i) 1.1171 + { 1.1172 + if(keys[i] < keys[i - 1]) 1.1173 + { 1.1174 + throw new IllegalArgumentException("keys must be sorted ascending"); 1.1175 + } 1.1176 + } 1.1177 + Label def = newLabel(); 1.1178 + Label end = newLabel(); 1.1179 + if(keys.length > 0) 1.1180 + { 1.1181 + int len = keys.length; 1.1182 + int min = keys[0]; 1.1183 + int max = keys[len - 1]; 1.1184 + int range = max - min + 1; 1.1185 + if(useTable) 1.1186 + { 1.1187 + Label[] labels = new Label[range]; 1.1188 + Arrays.fill(labels, def); 1.1189 + for(int i = 0; i < len; ++i) 1.1190 + { 1.1191 + labels[keys[i] - min] = newLabel(); 1.1192 + } 1.1193 + mv.visitTableSwitchInsn(min, max, def, labels); 1.1194 + for(int i = 0; i < range; ++i) 1.1195 + { 1.1196 + Label label = labels[i]; 1.1197 + if(label != def) 1.1198 + { 1.1199 + mark(label); 1.1200 + generator.generateCase(i + min, end); 1.1201 + } 1.1202 + } 1.1203 + } 1.1204 + else 1.1205 + { 1.1206 + Label[] labels = new Label[len]; 1.1207 + for(int i = 0; i < len; ++i) 1.1208 + { 1.1209 + labels[i] = newLabel(); 1.1210 + } 1.1211 + mv.visitLookupSwitchInsn(def, keys, labels); 1.1212 + for(int i = 0; i < len; ++i) 1.1213 + { 1.1214 + mark(labels[i]); 1.1215 + generator.generateCase(keys[i], end); 1.1216 + } 1.1217 + } 1.1218 + } 1.1219 + mark(def); 1.1220 + generator.generateDefault(); 1.1221 + mark(end); 1.1222 +} 1.1223 + 1.1224 +/** 1.1225 + * Generates the instruction to return the top stack value to the caller. 1.1226 + */ 1.1227 +public void returnValue(){ 1.1228 + mv.visitInsn(returnType.getOpcode(Opcodes.IRETURN)); 1.1229 +} 1.1230 + 1.1231 +// ------------------------------------------------------------------------ 1.1232 +// Instructions to load and store fields 1.1233 +// ------------------------------------------------------------------------ 1.1234 + 1.1235 +/** 1.1236 + * Generates a get field or set field instruction. 1.1237 + * 1.1238 + * @param opcode the instruction's opcode. 1.1239 + * @param ownerType the class in which the field is defined. 1.1240 + * @param name the name of the field. 1.1241 + * @param fieldType the type of the field. 1.1242 + */ 1.1243 +private void fieldInsn( 1.1244 + final int opcode, 1.1245 + final Type ownerType, 1.1246 + final String name, 1.1247 + final Type fieldType){ 1.1248 + mv.visitFieldInsn(opcode, 1.1249 + ownerType.getInternalName(), 1.1250 + name, 1.1251 + fieldType.getDescriptor()); 1.1252 +} 1.1253 + 1.1254 +/** 1.1255 + * Generates the instruction to push the value of a static field on the 1.1256 + * stack. 1.1257 + * 1.1258 + * @param owner the class in which the field is defined. 1.1259 + * @param name the name of the field. 1.1260 + * @param type the type of the field. 1.1261 + */ 1.1262 +public void getStatic(final Type owner, final String name, final Type type){ 1.1263 + fieldInsn(Opcodes.GETSTATIC, owner, name, type); 1.1264 +} 1.1265 + 1.1266 +/** 1.1267 + * Generates the instruction to store the top stack value in a static field. 1.1268 + * 1.1269 + * @param owner the class in which the field is defined. 1.1270 + * @param name the name of the field. 1.1271 + * @param type the type of the field. 1.1272 + */ 1.1273 +public void putStatic(final Type owner, final String name, final Type type){ 1.1274 + fieldInsn(Opcodes.PUTSTATIC, owner, name, type); 1.1275 +} 1.1276 + 1.1277 +/** 1.1278 + * Generates the instruction to push the value of a non static field on the 1.1279 + * stack. 1.1280 + * 1.1281 + * @param owner the class in which the field is defined. 1.1282 + * @param name the name of the field. 1.1283 + * @param type the type of the field. 1.1284 + */ 1.1285 +public void getField(final Type owner, final String name, final Type type){ 1.1286 + fieldInsn(Opcodes.GETFIELD, owner, name, type); 1.1287 +} 1.1288 + 1.1289 +/** 1.1290 + * Generates the instruction to store the top stack value in a non static 1.1291 + * field. 1.1292 + * 1.1293 + * @param owner the class in which the field is defined. 1.1294 + * @param name the name of the field. 1.1295 + * @param type the type of the field. 1.1296 + */ 1.1297 +public void putField(final Type owner, final String name, final Type type){ 1.1298 + fieldInsn(Opcodes.PUTFIELD, owner, name, type); 1.1299 +} 1.1300 + 1.1301 +// ------------------------------------------------------------------------ 1.1302 +// Instructions to invoke methods 1.1303 +// ------------------------------------------------------------------------ 1.1304 + 1.1305 +/** 1.1306 + * Generates an invoke method instruction. 1.1307 + * 1.1308 + * @param opcode the instruction's opcode. 1.1309 + * @param type the class in which the method is defined. 1.1310 + * @param method the method to be invoked. 1.1311 + */ 1.1312 +private void invokeInsn( 1.1313 + final int opcode, 1.1314 + final Type type, 1.1315 + final Method method){ 1.1316 + String owner = type.getSort() == Type.ARRAY 1.1317 + ? type.getDescriptor() 1.1318 + : type.getInternalName(); 1.1319 + mv.visitMethodInsn(opcode, 1.1320 + owner, 1.1321 + method.getName(), 1.1322 + method.getDescriptor()); 1.1323 +} 1.1324 + 1.1325 +/** 1.1326 + * Generates the instruction to invoke a normal method. 1.1327 + * 1.1328 + * @param owner the class in which the method is defined. 1.1329 + * @param method the method to be invoked. 1.1330 + */ 1.1331 +public void invokeVirtual(final Type owner, final Method method){ 1.1332 + invokeInsn(Opcodes.INVOKEVIRTUAL, owner, method); 1.1333 +} 1.1334 + 1.1335 +/** 1.1336 + * Generates the instruction to invoke a constructor. 1.1337 + * 1.1338 + * @param type the class in which the constructor is defined. 1.1339 + * @param method the constructor to be invoked. 1.1340 + */ 1.1341 +public void invokeConstructor(final Type type, final Method method){ 1.1342 + invokeInsn(Opcodes.INVOKESPECIAL, type, method); 1.1343 +} 1.1344 + 1.1345 +/** 1.1346 + * Generates the instruction to invoke a static method. 1.1347 + * 1.1348 + * @param owner the class in which the method is defined. 1.1349 + * @param method the method to be invoked. 1.1350 + */ 1.1351 +public void invokeStatic(final Type owner, final Method method){ 1.1352 + invokeInsn(Opcodes.INVOKESTATIC, owner, method); 1.1353 +} 1.1354 + 1.1355 +/** 1.1356 + * Generates the instruction to invoke an interface method. 1.1357 + * 1.1358 + * @param owner the class in which the method is defined. 1.1359 + * @param method the method to be invoked. 1.1360 + */ 1.1361 +public void invokeInterface(final Type owner, final Method method){ 1.1362 + invokeInsn(Opcodes.INVOKEINTERFACE, owner, method); 1.1363 +} 1.1364 + 1.1365 +// ------------------------------------------------------------------------ 1.1366 +// Instructions to create objects and arrays 1.1367 +// ------------------------------------------------------------------------ 1.1368 + 1.1369 +/** 1.1370 + * Generates a type dependent instruction. 1.1371 + * 1.1372 + * @param opcode the instruction's opcode. 1.1373 + * @param type the instruction's operand. 1.1374 + */ 1.1375 +private void typeInsn(final int opcode, final Type type){ 1.1376 + String desc; 1.1377 + if(type.getSort() == Type.ARRAY) 1.1378 + { 1.1379 + desc = type.getDescriptor(); 1.1380 + } 1.1381 + else 1.1382 + { 1.1383 + desc = type.getInternalName(); 1.1384 + } 1.1385 + mv.visitTypeInsn(opcode, desc); 1.1386 +} 1.1387 + 1.1388 +/** 1.1389 + * Generates the instruction to create a new object. 1.1390 + * 1.1391 + * @param type the class of the object to be created. 1.1392 + */ 1.1393 +public void newInstance(final Type type){ 1.1394 + typeInsn(Opcodes.NEW, type); 1.1395 +} 1.1396 + 1.1397 +/** 1.1398 + * Generates the instruction to create a new array. 1.1399 + * 1.1400 + * @param type the type of the array elements. 1.1401 + */ 1.1402 +public void newArray(final Type type){ 1.1403 + int typ; 1.1404 + switch(type.getSort()) 1.1405 + { 1.1406 + case Type.BOOLEAN: 1.1407 + typ = Opcodes.T_BOOLEAN; 1.1408 + break; 1.1409 + case Type.CHAR: 1.1410 + typ = Opcodes.T_CHAR; 1.1411 + break; 1.1412 + case Type.BYTE: 1.1413 + typ = Opcodes.T_BYTE; 1.1414 + break; 1.1415 + case Type.SHORT: 1.1416 + typ = Opcodes.T_SHORT; 1.1417 + break; 1.1418 + case Type.INT: 1.1419 + typ = Opcodes.T_INT; 1.1420 + break; 1.1421 + case Type.FLOAT: 1.1422 + typ = Opcodes.T_FLOAT; 1.1423 + break; 1.1424 + case Type.LONG: 1.1425 + typ = Opcodes.T_LONG; 1.1426 + break; 1.1427 + case Type.DOUBLE: 1.1428 + typ = Opcodes.T_DOUBLE; 1.1429 + break; 1.1430 + default: 1.1431 + typeInsn(Opcodes.ANEWARRAY, type); 1.1432 + return; 1.1433 + } 1.1434 + mv.visitIntInsn(Opcodes.NEWARRAY, typ); 1.1435 +} 1.1436 + 1.1437 +// ------------------------------------------------------------------------ 1.1438 +// Miscelaneous instructions 1.1439 +// ------------------------------------------------------------------------ 1.1440 + 1.1441 +/** 1.1442 + * Generates the instruction to compute the length of an array. 1.1443 + */ 1.1444 +public void arrayLength(){ 1.1445 + mv.visitInsn(Opcodes.ARRAYLENGTH); 1.1446 +} 1.1447 + 1.1448 +/** 1.1449 + * Generates the instruction to throw an exception. 1.1450 + */ 1.1451 +public void throwException(){ 1.1452 + mv.visitInsn(Opcodes.ATHROW); 1.1453 +} 1.1454 + 1.1455 +/** 1.1456 + * Generates the instructions to create and throw an exception. The 1.1457 + * exception class must have a constructor with a single String argument. 1.1458 + * 1.1459 + * @param type the class of the exception to be thrown. 1.1460 + * @param msg the detailed message of the exception. 1.1461 + */ 1.1462 +public void throwException(final Type type, final String msg){ 1.1463 + newInstance(type); 1.1464 + dup(); 1.1465 + push(msg); 1.1466 + invokeConstructor(type, Method.getMethod("void <init> (String)")); 1.1467 + throwException(); 1.1468 +} 1.1469 + 1.1470 +/** 1.1471 + * Generates the instruction to check that the top stack value is of the 1.1472 + * given type. 1.1473 + * 1.1474 + * @param type a class or interface type. 1.1475 + */ 1.1476 +public void checkCast(final Type type){ 1.1477 + if(!type.equals(OBJECT_TYPE)) 1.1478 + { 1.1479 + typeInsn(Opcodes.CHECKCAST, type); 1.1480 + } 1.1481 +} 1.1482 + 1.1483 +/** 1.1484 + * Generates the instruction to test if the top stack value is of the given 1.1485 + * type. 1.1486 + * 1.1487 + * @param type a class or interface type. 1.1488 + */ 1.1489 +public void instanceOf(final Type type){ 1.1490 + typeInsn(Opcodes.INSTANCEOF, type); 1.1491 +} 1.1492 + 1.1493 +/** 1.1494 + * Generates the instruction to get the monitor of the top stack value. 1.1495 + */ 1.1496 +public void monitorEnter(){ 1.1497 + mv.visitInsn(Opcodes.MONITORENTER); 1.1498 +} 1.1499 + 1.1500 +/** 1.1501 + * Generates the instruction to release the monitor of the top stack value. 1.1502 + */ 1.1503 +public void monitorExit(){ 1.1504 + mv.visitInsn(Opcodes.MONITOREXIT); 1.1505 +} 1.1506 + 1.1507 +// ------------------------------------------------------------------------ 1.1508 +// Non instructions 1.1509 +// ------------------------------------------------------------------------ 1.1510 + 1.1511 +/** 1.1512 + * Marks the end of the visited method. 1.1513 + */ 1.1514 +public void endMethod(){ 1.1515 + if((access & Opcodes.ACC_ABSTRACT) == 0) 1.1516 + { 1.1517 + mv.visitMaxs(0, 0); 1.1518 + } 1.1519 + mv.visitEnd(); 1.1520 +} 1.1521 + 1.1522 +/** 1.1523 + * Marks the start of an exception handler. 1.1524 + * 1.1525 + * @param start beginning of the exception handler's scope (inclusive). 1.1526 + * @param end end of the exception handler's scope (exclusive). 1.1527 + * @param exception internal name of the type of exceptions handled by the 1.1528 + * handler. 1.1529 + */ 1.1530 +public void catchException( 1.1531 + final Label start, 1.1532 + final Label end, 1.1533 + final Type exception){ 1.1534 + mv.visitTryCatchBlock(start, end, mark(), exception.getInternalName()); 1.1535 +} 1.1536 +}