Home | History | Annotate | Download | only in commons
      1 /***
      2  * ASM: a very small and fast Java bytecode manipulation framework
      3  * Copyright (c) 2000-2005 INRIA, France Telecom
      4  * All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  * 3. Neither the name of the copyright holders nor the names of its
     15  *    contributors may be used to endorse or promote products derived from
     16  *    this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
     22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
     28  * THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 package org.objectweb.asm.commons;
     31 
     32 import org.objectweb.asm.Label;
     33 import org.objectweb.asm.MethodAdapter;
     34 import org.objectweb.asm.MethodVisitor;
     35 import org.objectweb.asm.Opcodes;
     36 import org.objectweb.asm.Type;
     37 
     38 /**
     39  * A {@link MethodAdapter} that renumbers local variables in their order of
     40  * appearance. This adapter allows one to easily add new local variables to a
     41  * method.
     42  *
     43  * @author Chris Nokleberg
     44  * @author Eric Bruneton
     45  */
     46 public class LocalVariablesSorter extends MethodAdapter {
     47 
     48     /**
     49      * Mapping from old to new local variable indexes. A local variable at index
     50      * i of size 1 is remapped to 'mapping[2*i]', while a local variable at
     51      * index i of size 2 is remapped to 'mapping[2*i+1]'.
     52      */
     53     private int[] mapping = new int[40];
     54 
     55     protected final int firstLocal;
     56 
     57     private int nextLocal;
     58 
     59     public LocalVariablesSorter(
     60         final int access,
     61         final String desc,
     62         final MethodVisitor mv)
     63     {
     64         super(mv);
     65         Type[] args = Type.getArgumentTypes(desc);
     66         nextLocal = ((Opcodes.ACC_STATIC & access) != 0) ? 0 : 1;
     67         for (int i = 0; i < args.length; i++) {
     68             nextLocal += args[i].getSize();
     69         }
     70         firstLocal = nextLocal;
     71     }
     72 
     73     public void visitVarInsn(final int opcode, final int var) {
     74         int size;
     75         switch (opcode) {
     76             case Opcodes.LLOAD:
     77             case Opcodes.LSTORE:
     78             case Opcodes.DLOAD:
     79             case Opcodes.DSTORE:
     80                 size = 2;
     81                 break;
     82             default:
     83                 size = 1;
     84         }
     85         mv.visitVarInsn(opcode, remap(var, size));
     86     }
     87 
     88     public void visitIincInsn(final int var, final int increment) {
     89         mv.visitIincInsn(remap(var, 1), increment);
     90     }
     91 
     92     public void visitMaxs(final int maxStack, final int maxLocals) {
     93         mv.visitMaxs(maxStack, nextLocal);
     94     }
     95 
     96     public void visitLocalVariable(
     97         final String name,
     98         final String desc,
     99         final String signature,
    100         final Label start,
    101         final Label end,
    102         final int index)
    103     {
    104         int size = "J".equals(desc) || "D".equals(desc) ? 2 : 1;
    105         mv.visitLocalVariable(name, desc, signature, start, end, remap(index, size));
    106     }
    107 
    108     // -------------
    109 
    110     protected int newLocal(final int size) {
    111         int var = nextLocal;
    112         nextLocal += size;
    113         return var;
    114     }
    115 
    116     private int remap(final int var, final int size) {
    117         if (var < firstLocal) {
    118             return var;
    119         }
    120         int key = 2 * var + size - 1;
    121         int length = mapping.length;
    122         if (key >= length) {
    123             int[] newMapping = new int[Math.max(2 * length, key + 1)];
    124             System.arraycopy(mapping, 0, newMapping, 0, length);
    125             mapping = newMapping;
    126         }
    127         int value = mapping[key];
    128         if (value == 0) {
    129             value = nextLocal + 1;
    130             mapping[key] = value;
    131             nextLocal += size;
    132         }
    133         return value - 1;
    134     }
    135 
    136 }
    137