1 8 package org.codehaus.aspectwerkz.hook.impl; 9 10 import org.codehaus.aspectwerkz.hook.ClassLoaderPatcher; 11 import org.codehaus.aspectwerkz.hook.ClassLoaderPreProcessor; 12 import org.objectweb.asm.ClassWriter; 13 import org.objectweb.asm.CodeVisitor; 14 import org.objectweb.asm.Attribute; 15 import org.objectweb.asm.ClassReader; 16 import org.objectweb.asm.ClassVisitor; 17 import org.objectweb.asm.ClassAdapter; 18 import org.objectweb.asm.CodeAdapter; 19 import org.objectweb.asm.Type; 20 import org.objectweb.asm.Constants; 21 import org.objectweb.asm.Label; 22 import org.objectweb.asm.attrs.Attributes; 23 24 import java.io.InputStream ; 25 import java.io.OutputStream ; 26 import java.io.FileOutputStream ; 27 import java.io.File ; 28 import java.util.HashMap ; 29 import java.util.Map ; 30 31 39 public class ClassLoaderPreProcessorImpl implements ClassLoaderPreProcessor { 40 41 private final static String CLASSLOADER_CLASS_NAME = "java/lang/ClassLoader"; 42 private final static String DEFINECLASS0_METHOD_NAME = "defineClass0"; 43 private final static String DEFINECLASS1_METHOD_NAME = "defineClass1"; private final static String DEFINECLASS2_METHOD_NAME = "defineClass2"; 46 47 private static final String DESC_CORE = "Ljava/lang/String;[BIILjava/security/ProtectionDomain;"; 48 private static final String DESC_PREFIX = "(" + DESC_CORE; 49 private static final String DESC_HELPER = "(Ljava/lang/ClassLoader;" + DESC_CORE + ")[B"; 50 51 private static final String DESC_BYTEBUFFER_CORE = "Ljava/lang/String;Ljava/nio/ByteBuffer;IILjava/security/ProtectionDomain;"; 52 private static final String DESC_BYTEBUFFER_PREFIX = "(" + DESC_BYTEBUFFER_CORE; 53 private static final String DESC_BYTEBUFFER_HELPER = "(Ljava/lang/ClassLoader;" + DESC_BYTEBUFFER_CORE + ")[B"; 54 55 public ClassLoaderPreProcessorImpl() { 56 } 57 58 66 public byte[] preProcess(byte[] classLoaderBytecode) { 67 try { 68 ClassWriter cw = new ClassWriter(true); 69 ClassLoaderVisitor cv = new ClassLoaderVisitor(cw); 70 ClassReader cr = new ClassReader(classLoaderBytecode); 71 cr.accept(cv, Attributes.getDefaultAttributes(), false); 72 return cw.toByteArray(); 73 } catch (Exception e) { 74 System.err.println("failed to patch ClassLoader:"); 75 e.printStackTrace(); 76 return classLoaderBytecode; 77 } 78 } 79 80 private static class ClassLoaderVisitor extends ClassAdapter { 81 public ClassLoaderVisitor(ClassVisitor cv) { 82 super(cv); 83 } 84 85 public CodeVisitor visitMethod(int access, String name, String desc, String [] exceptions, Attribute attrs) { 86 CodeVisitor cv = super.visitMethod(access, name, desc, exceptions, attrs); 87 Type[] args = Type.getArgumentTypes(desc); 88 return new PreProcessingVisitor(cv, access, args); 89 } 90 } 91 92 95 private static class PreProcessingVisitor extends RemappingCodeVisitor { 96 public PreProcessingVisitor(CodeVisitor cv, int access, Type[] args) { 97 super(cv, access, args); 98 } 99 100 public void visitMethodInsn(int opcode, String owner, String name, String desc) { 101 if ((DEFINECLASS0_METHOD_NAME.equals(name) || (DEFINECLASS1_METHOD_NAME.equals(name))) 102 && CLASSLOADER_CLASS_NAME.equals(owner)) { 103 Type[] args = Type.getArgumentTypes(desc); 104 if (args.length < 5 || !desc.startsWith(DESC_PREFIX)) { 105 throw new Error ("non supported JDK, native call not supported: " + desc); 106 } 107 int[] locals = new int[args.length]; 109 for (int i = args.length - 1; i >= 0; i--) { 110 cv.visitVarInsn( 111 args[i].getOpcode(Constants.ISTORE), 112 locals[i] = nextLocal(args[i].getSize()) 113 ); 114 } 115 for (int i = 0; i < 5; i++) { 116 cv.visitVarInsn(args[i].getOpcode(Constants.ILOAD), locals[i]); 117 } 118 super.visitMethodInsn( 119 Constants.INVOKESTATIC, 120 "org/codehaus/aspectwerkz/hook/impl/ClassPreProcessorHelper", 121 "defineClass0Pre", 122 DESC_HELPER 123 ); 124 cv.visitVarInsn(Constants.ASTORE, locals[1]); 125 cv.visitVarInsn(Constants.ALOAD, 0); 126 cv.visitVarInsn(Constants.ALOAD, locals[0]); cv.visitVarInsn(Constants.ALOAD, locals[1]); cv.visitInsn(Constants.ICONST_0); cv.visitVarInsn(Constants.ALOAD, locals[1]); 130 cv.visitInsn(Constants.ARRAYLENGTH); cv.visitVarInsn(Constants.ALOAD, locals[4]); for (int i = 5; i < args.length; i++) { 133 cv.visitVarInsn(args[i].getOpcode(Constants.ILOAD), locals[i]); 134 } 135 } else if (DEFINECLASS2_METHOD_NAME.equals(name) && CLASSLOADER_CLASS_NAME.equals(owner)) { 136 Type[] args = Type.getArgumentTypes(desc); 137 if (args.length < 5 || !desc.startsWith(DESC_BYTEBUFFER_PREFIX)) { 138 throw new Error ("non supported JDK, bytebuffer native call not supported: " + desc); 139 } 140 int[] locals = new int[args.length]; 142 for (int i = args.length - 1; i >= 0; i--) { 143 cv.visitVarInsn( 144 args[i].getOpcode(Constants.ISTORE), 145 locals[i] = nextLocal(args[i].getSize()) 146 ); 147 } 148 for (int i = 0; i < 5; i++) { 149 cv.visitVarInsn(args[i].getOpcode(Constants.ILOAD), locals[i]); 150 } 151 super.visitMethodInsn( 152 Constants.INVOKESTATIC, 153 "org/codehaus/aspectwerkz/hook/impl/ClassPreProcessorHelper", 154 "defineClass0Pre", 155 DESC_BYTEBUFFER_HELPER 156 ); 157 cv.visitVarInsn(Constants.ASTORE, locals[1]); 158 cv.visitVarInsn(Constants.ALOAD, 0); 159 cv.visitVarInsn(Constants.ALOAD, locals[0]); cv.visitVarInsn(Constants.ALOAD, locals[1]); cv.visitInsn(Constants.ICONST_0); cv.visitVarInsn(Constants.ALOAD, locals[1]); 163 cv.visitMethodInsn(Constants.INVOKEVIRTUAL, "Ljava/nio/Buffer;", "remaining", "()I"); 164 cv.visitVarInsn(Constants.ALOAD, locals[4]); for (int i = 5; i < args.length; i++) { 166 cv.visitVarInsn(args[i].getOpcode(Constants.ILOAD), locals[i]); 167 } 168 170 } 171 super.visitMethodInsn(opcode, owner, name, desc); 172 } 173 } 174 175 178 private static class State { 179 Map locals = new HashMap (); 180 int firstLocal; 181 int nextLocal; 182 183 State(int access, Type[] args) { 184 nextLocal = ((Constants.ACC_STATIC & access) != 0) ? 0 : 1; 185 for (int i = 0; i < args.length; i++) { 186 nextLocal += args[i].getSize(); 187 } 188 firstLocal = nextLocal; 189 } 190 } 191 192 195 private static class IntRef { 196 int key; 197 198 public boolean equals(Object o) { 199 return key == ((IntRef) o).key; 200 } 201 202 public int hashCode() { 203 return key; 204 } 205 } 206 207 210 private static class RemappingCodeVisitor extends CodeAdapter { 211 private State state; 212 private IntRef check = new IntRef(); 213 214 215 public RemappingCodeVisitor(CodeVisitor v, int access, Type[] args) { 216 super(v); 217 state = new State(access, args); 218 } 219 220 public RemappingCodeVisitor(RemappingCodeVisitor wrap) { 221 super(wrap.cv); 222 this.state = wrap.state; 223 } 224 225 protected int nextLocal(int size) { 226 int var = state.nextLocal; 227 state.nextLocal += size; 228 return var; 229 } 230 231 private int remap(int var, int size) { 232 if (var < state.firstLocal) { 233 return var; 234 } 235 check.key = (size == 2) ? ~var : var; 236 Integer value = (Integer ) state.locals.get(check); 237 if (value == null) { 238 IntRef ref = new IntRef(); 239 ref.key = check.key; 240 state.locals.put(ref, value = new Integer (nextLocal(size))); 241 } 242 return value.intValue(); 243 } 244 245 public void visitIincInsn(int var, int increment) { 246 cv.visitIincInsn(remap(var, 1), increment); 247 } 248 249 public void visitLocalVariable(String name, String desc, Label start, Label end, int index) { 250 cv.visitLocalVariable(name, desc, start, end, remap(index, 0)); 251 } 252 253 public void visitVarInsn(int opcode, int var) { 254 int size; 255 switch (opcode) { 256 case Constants.LLOAD: 257 case Constants.LSTORE: 258 case Constants.DLOAD: 259 case Constants.DSTORE: 260 size = 2; 261 break; 262 default: 263 size = 1; 264 } 265 cv.visitVarInsn(opcode, remap(var, size)); 266 } 267 268 public void visitMaxs(int maxStack, int maxLocals) { 269 cv.visitMaxs(0, 0); 270 } 271 } 272 273 public static void main(String args[]) throws Exception { 274 ClassLoaderPreProcessor me = new ClassLoaderPreProcessorImpl(); 275 InputStream is = ClassLoader.getSystemClassLoader().getParent().getResourceAsStream( 276 "java/lang/ClassLoader.class" 277 ); 278 byte[] out = me.preProcess(ClassLoaderPatcher.inputStreamToByteArray(is)); 279 is.close(); 280 File dir = new File ("_boot/java/lang/"); 281 dir.mkdirs(); 282 OutputStream os = new FileOutputStream ("_boot/java/lang/ClassLoader.class"); 283 os.write(out); 284 os.close(); 285 } 286 } | Popular Tags |