LocalVariablesSorter.java revision 674060f01e9090cd21b3c5656cc3204912ad17a6
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 */ 30package org.mockito.cglib.core; 31 32import org.mockito.asm.Label; 33import org.mockito.asm.MethodAdapter; 34import org.mockito.asm.MethodVisitor; 35import org.mockito.asm.Opcodes; 36import org.mockito.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 */ 46public 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 static class State 54 { 55 int[] mapping = new int[40]; 56 int nextLocal; 57 } 58 59 protected final int firstLocal; 60 private final State state; 61 62 public LocalVariablesSorter( 63 final int access, 64 final String desc, 65 final MethodVisitor mv) 66 { 67 super(mv); 68 state = new State(); 69 Type[] args = Type.getArgumentTypes(desc); 70 state.nextLocal = ((Opcodes.ACC_STATIC & access) != 0) ? 0 : 1; 71 for (int i = 0; i < args.length; i++) { 72 state.nextLocal += args[i].getSize(); 73 } 74 firstLocal = state.nextLocal; 75 } 76 77 public LocalVariablesSorter(LocalVariablesSorter lvs) { 78 super(lvs.mv); 79 state = lvs.state; 80 firstLocal = lvs.firstLocal; 81 } 82 83 public void visitVarInsn(final int opcode, final int var) { 84 int size; 85 switch (opcode) { 86 case Opcodes.LLOAD: 87 case Opcodes.LSTORE: 88 case Opcodes.DLOAD: 89 case Opcodes.DSTORE: 90 size = 2; 91 break; 92 default: 93 size = 1; 94 } 95 mv.visitVarInsn(opcode, remap(var, size)); 96 } 97 98 public void visitIincInsn(final int var, final int increment) { 99 mv.visitIincInsn(remap(var, 1), increment); 100 } 101 102 public void visitMaxs(final int maxStack, final int maxLocals) { 103 mv.visitMaxs(maxStack, state.nextLocal); 104 } 105 106 public void visitLocalVariable( 107 final String name, 108 final String desc, 109 final String signature, 110 final Label start, 111 final Label end, 112 final int index) 113 { 114 mv.visitLocalVariable(name, desc, signature, start, end, remap(index)); 115 } 116 117 // ------------- 118 119 protected int newLocal(final int size) { 120 int var = state.nextLocal; 121 state.nextLocal += size; 122 return var; 123 } 124 125 private int remap(final int var, final int size) { 126 if (var < firstLocal) { 127 return var; 128 } 129 int key = 2 * var + size - 1; 130 int length = state.mapping.length; 131 if (key >= length) { 132 int[] newMapping = new int[Math.max(2 * length, key + 1)]; 133 System.arraycopy(state.mapping, 0, newMapping, 0, length); 134 state.mapping = newMapping; 135 } 136 int value = state.mapping[key]; 137 if (value == 0) { 138 value = state.nextLocal + 1; 139 state.mapping[key] = value; 140 state.nextLocal += size; 141 } 142 return value - 1; 143 } 144 145 private int remap(final int var) { 146 if (var < firstLocal) { 147 return var; 148 } 149 int key = 2 * var; 150 int value = key < state.mapping.length ? state.mapping[key] : 0; 151 if (value == 0) { 152 value = key + 1 < state.mapping.length ? state.mapping[key + 1] : 0; 153 } 154 if (value == 0) { 155 throw new IllegalStateException("Unknown local variable " + var); 156 } 157 return value - 1; 158 } 159} 160