Mercurial > lasercutter
view src/clojure/asm/commons/LocalVariablesSorter.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 source
1 /***2 * ASM: a very small and fast Java bytecode manipulation framework3 * Copyright (c) 2000-2005 INRIA, France Telecom4 * All rights reserved.5 *6 * Redistribution and use in source and binary forms, with or without7 * modification, are permitted provided that the following conditions8 * are met:9 * 1. Redistributions of source code must retain the above copyright10 * notice, this list of conditions and the following disclaimer.11 * 2. Redistributions in binary form must reproduce the above copyright12 * notice, this list of conditions and the following disclaimer in the13 * documentation and/or other materials provided with the distribution.14 * 3. Neither the name of the copyright holders nor the names of its15 * contributors may be used to endorse or promote products derived from16 * 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, THE20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF28 * THE POSSIBILITY OF SUCH DAMAGE.29 */30 package clojure.asm.commons;32 import clojure.asm.Label;33 import clojure.asm.MethodAdapter;34 import clojure.asm.MethodVisitor;35 import clojure.asm.Opcodes;36 import clojure.asm.Type;38 /**39 * A {@link MethodAdapter} that renumbers local variables in their order of40 * appearance. This adapter allows one to easily add new local variables to a41 * method. It may be used by inheriting from this class, but the preferred way42 * of using it is via delegation: the next visitor in the chain can indeed add43 * new locals when needed by calling {@link #newLocal} on this adapter (this44 * requires a reference back to this {@link LocalVariablesSorter}).45 *46 * @author Chris Nokleberg47 * @author Eugene Kuleshov48 * @author Eric Bruneton49 */50 public class LocalVariablesSorter extends MethodAdapter{52 private final static Type OBJECT_TYPE = Type.getObjectType("java/lang/Object");54 /**55 * Mapping from old to new local variable indexes. A local variable at index56 * i of size 1 is remapped to 'mapping[2*i]', while a local variable at57 * index i of size 2 is remapped to 'mapping[2*i+1]'.58 */59 private int[] mapping = new int[40];61 /**62 * Array used to store stack map local variable types after remapping.63 */64 private Object[] newLocals = new Object[20];66 /**67 * Index of the first local variable, after formal parameters.68 */69 protected final int firstLocal;71 /**72 * Index of the next local variable to be created by {@link #newLocal}.73 */74 protected int nextLocal;76 /**77 * Indicates if at least one local variable has moved due to remapping.78 */79 private boolean changed;81 /**82 * Creates a new {@link LocalVariablesSorter}.83 *84 * @param access access flags of the adapted method.85 * @param desc the method's descriptor (see {@link Type Type}).86 * @param mv the method visitor to which this adapter delegates calls.87 */88 public LocalVariablesSorter(89 final int access,90 final String desc,91 final MethodVisitor mv){92 super(mv);93 Type[] args = Type.getArgumentTypes(desc);94 nextLocal = (Opcodes.ACC_STATIC & access) != 0 ? 0 : 1;95 for(int i = 0; i < args.length; i++)96 {97 nextLocal += args[i].getSize();98 }99 firstLocal = nextLocal;100 }102 public void visitVarInsn(final int opcode, final int var){103 Type type;104 switch(opcode)105 {106 case Opcodes.LLOAD:107 case Opcodes.LSTORE:108 type = Type.LONG_TYPE;109 break;111 case Opcodes.DLOAD:112 case Opcodes.DSTORE:113 type = Type.DOUBLE_TYPE;114 break;116 case Opcodes.FLOAD:117 case Opcodes.FSTORE:118 type = Type.FLOAT_TYPE;119 break;121 case Opcodes.ILOAD:122 case Opcodes.ISTORE:123 type = Type.INT_TYPE;124 break;126 case Opcodes.ALOAD:127 case Opcodes.ASTORE:128 type = OBJECT_TYPE;129 break;131 // case RET:132 default:133 type = Type.VOID_TYPE;134 }135 mv.visitVarInsn(opcode, remap(var, type));136 }138 public void visitIincInsn(final int var, final int increment){139 mv.visitIincInsn(remap(var, Type.INT_TYPE), increment);140 }142 public void visitMaxs(final int maxStack, final int maxLocals){143 mv.visitMaxs(maxStack, nextLocal);144 }146 public void visitLocalVariable(147 final String name,148 final String desc,149 final String signature,150 final Label start,151 final Label end,152 final int index){153 int size = "J".equals(desc) || "D".equals(desc) ? 2 : 1;154 int newIndex = remap(index, size);155 mv.visitLocalVariable(name, desc, signature, start, end, newIndex);156 }158 public void visitFrame(159 final int type,160 final int nLocal,161 final Object[] local,162 final int nStack,163 final Object[] stack){164 if(type != Opcodes.F_NEW)165 { // uncompressed frame166 throw new IllegalStateException("ClassReader.accept() should be called with EXPAND_FRAMES flag");167 }169 if(!changed)170 { // optimization for the case where mapping = identity171 mv.visitFrame(type, nLocal, local, nStack, stack);172 return;173 }175 // creates a copy of newLocals176 Object[] oldLocals = new Object[newLocals.length];177 System.arraycopy(newLocals, 0, oldLocals, 0, oldLocals.length);179 // copies types from 'local' to 'newLocals'180 // 'newLocals' already contains the variables added with 'newLocal'182 int index = 0; // old local variable index183 int number = 0; // old local variable number184 for(; number < nLocal; ++number)185 {186 Object t = local[number];187 int size = t == Opcodes.LONG || t == Opcodes.DOUBLE ? 2 : 1;188 if(t != Opcodes.TOP)189 {190 setFrameLocal(remap(index, size), t);191 }192 index += size;193 }195 // removes TOP after long and double types as well as trailing TOPs197 index = 0;198 number = 0;199 for(int i = 0; index < newLocals.length; ++i)200 {201 Object t = newLocals[index++];202 if(t != null && t != Opcodes.TOP)203 {204 newLocals[i] = t;205 number = i + 1;206 if(t == Opcodes.LONG || t == Opcodes.DOUBLE)207 {208 index += 1;209 }210 }211 else212 {213 newLocals[i] = Opcodes.TOP;214 }215 }217 // visits remapped frame218 mv.visitFrame(type, number, newLocals, nStack, stack);220 // restores original value of 'newLocals'221 newLocals = oldLocals;222 }224 // -------------226 /**227 * Creates a new local variable of the given type.228 *229 * @param type the type of the local variable to be created.230 * @return the identifier of the newly created local variable.231 */232 public int newLocal(final Type type){233 Object t;234 switch(type.getSort())235 {236 case Type.BOOLEAN:237 case Type.CHAR:238 case Type.BYTE:239 case Type.SHORT:240 case Type.INT:241 t = Opcodes.INTEGER;242 break;243 case Type.FLOAT:244 t = Opcodes.FLOAT;245 break;246 case Type.LONG:247 t = Opcodes.LONG;248 break;249 case Type.DOUBLE:250 t = Opcodes.DOUBLE;251 break;252 case Type.ARRAY:253 t = type.getDescriptor();254 break;255 // case Type.OBJECT:256 default:257 t = type.getInternalName();258 break;259 }260 int local = nextLocal;261 setLocalType(local, type);262 setFrameLocal(local, t);263 nextLocal += type.getSize();264 return local;265 }267 /**268 * Sets the current type of the given local variable. The default269 * implementation of this method does nothing.270 *271 * @param local a local variable identifier, as returned by {@link #newLocal272 * newLocal()}.273 * @param type the type of the value being stored in the local variable274 */275 protected void setLocalType(final int local, final Type type){276 }278 private void setFrameLocal(final int local, final Object type){279 int l = newLocals.length;280 if(local >= l)281 {282 Object[] a = new Object[Math.max(2 * l, local + 1)];283 System.arraycopy(newLocals, 0, a, 0, l);284 newLocals = a;285 }286 newLocals[local] = type;287 }289 private int remap(final int var, final Type type){290 if(var < firstLocal)291 {292 return var;293 }294 int key = 2 * var + type.getSize() - 1;295 int size = mapping.length;296 if(key >= size)297 {298 int[] newMapping = new int[Math.max(2 * size, key + 1)];299 System.arraycopy(mapping, 0, newMapping, 0, size);300 mapping = newMapping;301 }302 int value = mapping[key];303 if(value == 0)304 {305 value = nextLocal + 1;306 mapping[key] = value;307 setLocalType(nextLocal, type);308 nextLocal += type.getSize();309 }310 if(value - 1 != var)311 {312 changed = true;313 }314 return value - 1;315 }317 private int remap(final int var, final int size){318 if(var < firstLocal || !changed)319 {320 return var;321 }322 int key = 2 * var + size - 1;323 int value = key < mapping.length ? mapping[key] : 0;324 if(value == 0)325 {326 throw new IllegalStateException("Unknown local variable " + var);327 }328 return value - 1;329 }330 }