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(&quot;Hello world!&quot;);
    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, &quot;Example&quot;, null, &quot;java/lang/Object&quot;, null);
    1.62 + * <p/>
    1.63 + * Method m = Method.getMethod(&quot;void &lt;init&gt; ()&quot;);
    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(&quot;void main (String[])&quot;);
    1.71 + * mg = new GeneratorAdapter(ACC_PUBLIC + ACC_STATIC, m, null, null, cw);
    1.72 + * mg.getStatic(Type.getType(System.class), &quot;out&quot;, Type.getType(PrintStream.class));
    1.73 + * mg.push(&quot;Hello world!&quot;);
    1.74 + * mg.invokeVirtual(Type.getType(PrintStream.class), Method.getMethod(&quot;void println (String)&quot;));
    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 +}