Mercurial > lasercutter
diff 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 diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/clojure/asm/commons/LocalVariablesSorter.java Sat Aug 21 06:25:44 2010 -0400 1.3 @@ -0,0 +1,330 @@ 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 clojure.asm.Label; 1.36 +import clojure.asm.MethodAdapter; 1.37 +import clojure.asm.MethodVisitor; 1.38 +import clojure.asm.Opcodes; 1.39 +import clojure.asm.Type; 1.40 + 1.41 +/** 1.42 + * A {@link MethodAdapter} that renumbers local variables in their order of 1.43 + * appearance. This adapter allows one to easily add new local variables to a 1.44 + * method. It may be used by inheriting from this class, but the preferred way 1.45 + * of using it is via delegation: the next visitor in the chain can indeed add 1.46 + * new locals when needed by calling {@link #newLocal} on this adapter (this 1.47 + * requires a reference back to this {@link LocalVariablesSorter}). 1.48 + * 1.49 + * @author Chris Nokleberg 1.50 + * @author Eugene Kuleshov 1.51 + * @author Eric Bruneton 1.52 + */ 1.53 +public class LocalVariablesSorter extends MethodAdapter{ 1.54 + 1.55 +private final static Type OBJECT_TYPE = Type.getObjectType("java/lang/Object"); 1.56 + 1.57 +/** 1.58 + * Mapping from old to new local variable indexes. A local variable at index 1.59 + * i of size 1 is remapped to 'mapping[2*i]', while a local variable at 1.60 + * index i of size 2 is remapped to 'mapping[2*i+1]'. 1.61 + */ 1.62 +private int[] mapping = new int[40]; 1.63 + 1.64 +/** 1.65 + * Array used to store stack map local variable types after remapping. 1.66 + */ 1.67 +private Object[] newLocals = new Object[20]; 1.68 + 1.69 +/** 1.70 + * Index of the first local variable, after formal parameters. 1.71 + */ 1.72 +protected final int firstLocal; 1.73 + 1.74 +/** 1.75 + * Index of the next local variable to be created by {@link #newLocal}. 1.76 + */ 1.77 +protected int nextLocal; 1.78 + 1.79 +/** 1.80 + * Indicates if at least one local variable has moved due to remapping. 1.81 + */ 1.82 +private boolean changed; 1.83 + 1.84 +/** 1.85 + * Creates a new {@link LocalVariablesSorter}. 1.86 + * 1.87 + * @param access access flags of the adapted method. 1.88 + * @param desc the method's descriptor (see {@link Type Type}). 1.89 + * @param mv the method visitor to which this adapter delegates calls. 1.90 + */ 1.91 +public LocalVariablesSorter( 1.92 + final int access, 1.93 + final String desc, 1.94 + final MethodVisitor mv){ 1.95 + super(mv); 1.96 + Type[] args = Type.getArgumentTypes(desc); 1.97 + nextLocal = (Opcodes.ACC_STATIC & access) != 0 ? 0 : 1; 1.98 + for(int i = 0; i < args.length; i++) 1.99 + { 1.100 + nextLocal += args[i].getSize(); 1.101 + } 1.102 + firstLocal = nextLocal; 1.103 +} 1.104 + 1.105 +public void visitVarInsn(final int opcode, final int var){ 1.106 + Type type; 1.107 + switch(opcode) 1.108 + { 1.109 + case Opcodes.LLOAD: 1.110 + case Opcodes.LSTORE: 1.111 + type = Type.LONG_TYPE; 1.112 + break; 1.113 + 1.114 + case Opcodes.DLOAD: 1.115 + case Opcodes.DSTORE: 1.116 + type = Type.DOUBLE_TYPE; 1.117 + break; 1.118 + 1.119 + case Opcodes.FLOAD: 1.120 + case Opcodes.FSTORE: 1.121 + type = Type.FLOAT_TYPE; 1.122 + break; 1.123 + 1.124 + case Opcodes.ILOAD: 1.125 + case Opcodes.ISTORE: 1.126 + type = Type.INT_TYPE; 1.127 + break; 1.128 + 1.129 + case Opcodes.ALOAD: 1.130 + case Opcodes.ASTORE: 1.131 + type = OBJECT_TYPE; 1.132 + break; 1.133 + 1.134 + // case RET: 1.135 + default: 1.136 + type = Type.VOID_TYPE; 1.137 + } 1.138 + mv.visitVarInsn(opcode, remap(var, type)); 1.139 +} 1.140 + 1.141 +public void visitIincInsn(final int var, final int increment){ 1.142 + mv.visitIincInsn(remap(var, Type.INT_TYPE), increment); 1.143 +} 1.144 + 1.145 +public void visitMaxs(final int maxStack, final int maxLocals){ 1.146 + mv.visitMaxs(maxStack, nextLocal); 1.147 +} 1.148 + 1.149 +public void visitLocalVariable( 1.150 + final String name, 1.151 + final String desc, 1.152 + final String signature, 1.153 + final Label start, 1.154 + final Label end, 1.155 + final int index){ 1.156 + int size = "J".equals(desc) || "D".equals(desc) ? 2 : 1; 1.157 + int newIndex = remap(index, size); 1.158 + mv.visitLocalVariable(name, desc, signature, start, end, newIndex); 1.159 +} 1.160 + 1.161 +public void visitFrame( 1.162 + final int type, 1.163 + final int nLocal, 1.164 + final Object[] local, 1.165 + final int nStack, 1.166 + final Object[] stack){ 1.167 + if(type != Opcodes.F_NEW) 1.168 + { // uncompressed frame 1.169 + throw new IllegalStateException("ClassReader.accept() should be called with EXPAND_FRAMES flag"); 1.170 + } 1.171 + 1.172 + if(!changed) 1.173 + { // optimization for the case where mapping = identity 1.174 + mv.visitFrame(type, nLocal, local, nStack, stack); 1.175 + return; 1.176 + } 1.177 + 1.178 + // creates a copy of newLocals 1.179 + Object[] oldLocals = new Object[newLocals.length]; 1.180 + System.arraycopy(newLocals, 0, oldLocals, 0, oldLocals.length); 1.181 + 1.182 + // copies types from 'local' to 'newLocals' 1.183 + // 'newLocals' already contains the variables added with 'newLocal' 1.184 + 1.185 + int index = 0; // old local variable index 1.186 + int number = 0; // old local variable number 1.187 + for(; number < nLocal; ++number) 1.188 + { 1.189 + Object t = local[number]; 1.190 + int size = t == Opcodes.LONG || t == Opcodes.DOUBLE ? 2 : 1; 1.191 + if(t != Opcodes.TOP) 1.192 + { 1.193 + setFrameLocal(remap(index, size), t); 1.194 + } 1.195 + index += size; 1.196 + } 1.197 + 1.198 + // removes TOP after long and double types as well as trailing TOPs 1.199 + 1.200 + index = 0; 1.201 + number = 0; 1.202 + for(int i = 0; index < newLocals.length; ++i) 1.203 + { 1.204 + Object t = newLocals[index++]; 1.205 + if(t != null && t != Opcodes.TOP) 1.206 + { 1.207 + newLocals[i] = t; 1.208 + number = i + 1; 1.209 + if(t == Opcodes.LONG || t == Opcodes.DOUBLE) 1.210 + { 1.211 + index += 1; 1.212 + } 1.213 + } 1.214 + else 1.215 + { 1.216 + newLocals[i] = Opcodes.TOP; 1.217 + } 1.218 + } 1.219 + 1.220 + // visits remapped frame 1.221 + mv.visitFrame(type, number, newLocals, nStack, stack); 1.222 + 1.223 + // restores original value of 'newLocals' 1.224 + newLocals = oldLocals; 1.225 +} 1.226 + 1.227 +// ------------- 1.228 + 1.229 +/** 1.230 + * Creates a new local variable of the given type. 1.231 + * 1.232 + * @param type the type of the local variable to be created. 1.233 + * @return the identifier of the newly created local variable. 1.234 + */ 1.235 +public int newLocal(final Type type){ 1.236 + Object t; 1.237 + switch(type.getSort()) 1.238 + { 1.239 + case Type.BOOLEAN: 1.240 + case Type.CHAR: 1.241 + case Type.BYTE: 1.242 + case Type.SHORT: 1.243 + case Type.INT: 1.244 + t = Opcodes.INTEGER; 1.245 + break; 1.246 + case Type.FLOAT: 1.247 + t = Opcodes.FLOAT; 1.248 + break; 1.249 + case Type.LONG: 1.250 + t = Opcodes.LONG; 1.251 + break; 1.252 + case Type.DOUBLE: 1.253 + t = Opcodes.DOUBLE; 1.254 + break; 1.255 + case Type.ARRAY: 1.256 + t = type.getDescriptor(); 1.257 + break; 1.258 + // case Type.OBJECT: 1.259 + default: 1.260 + t = type.getInternalName(); 1.261 + break; 1.262 + } 1.263 + int local = nextLocal; 1.264 + setLocalType(local, type); 1.265 + setFrameLocal(local, t); 1.266 + nextLocal += type.getSize(); 1.267 + return local; 1.268 +} 1.269 + 1.270 +/** 1.271 + * Sets the current type of the given local variable. The default 1.272 + * implementation of this method does nothing. 1.273 + * 1.274 + * @param local a local variable identifier, as returned by {@link #newLocal 1.275 + * newLocal()}. 1.276 + * @param type the type of the value being stored in the local variable 1.277 + */ 1.278 +protected void setLocalType(final int local, final Type type){ 1.279 +} 1.280 + 1.281 +private void setFrameLocal(final int local, final Object type){ 1.282 + int l = newLocals.length; 1.283 + if(local >= l) 1.284 + { 1.285 + Object[] a = new Object[Math.max(2 * l, local + 1)]; 1.286 + System.arraycopy(newLocals, 0, a, 0, l); 1.287 + newLocals = a; 1.288 + } 1.289 + newLocals[local] = type; 1.290 +} 1.291 + 1.292 +private int remap(final int var, final Type type){ 1.293 + if(var < firstLocal) 1.294 + { 1.295 + return var; 1.296 + } 1.297 + int key = 2 * var + type.getSize() - 1; 1.298 + int size = mapping.length; 1.299 + if(key >= size) 1.300 + { 1.301 + int[] newMapping = new int[Math.max(2 * size, key + 1)]; 1.302 + System.arraycopy(mapping, 0, newMapping, 0, size); 1.303 + mapping = newMapping; 1.304 + } 1.305 + int value = mapping[key]; 1.306 + if(value == 0) 1.307 + { 1.308 + value = nextLocal + 1; 1.309 + mapping[key] = value; 1.310 + setLocalType(nextLocal, type); 1.311 + nextLocal += type.getSize(); 1.312 + } 1.313 + if(value - 1 != var) 1.314 + { 1.315 + changed = true; 1.316 + } 1.317 + return value - 1; 1.318 +} 1.319 + 1.320 +private int remap(final int var, final int size){ 1.321 + if(var < firstLocal || !changed) 1.322 + { 1.323 + return var; 1.324 + } 1.325 + int key = 2 * var + size - 1; 1.326 + int value = key < mapping.length ? mapping[key] : 0; 1.327 + if(value == 0) 1.328 + { 1.329 + throw new IllegalStateException("Unknown local variable " + var); 1.330 + } 1.331 + return value - 1; 1.332 +} 1.333 +}