1.9.30 sync.
[gae.git] / java / src / main / com / google / appengine / tools / development / agent / impl / ClassLoaderVisitor.java
blobe1753e63b7ce7d606c9dd2cee67c51a5b4b96416
1 // Copyright 2009 Google Inc. All Rights Reserved.
3 package com.google.appengine.tools.development.agent.impl;
5 import org.objectweb.asm.ClassVisitor;
6 import org.objectweb.asm.MethodVisitor;
7 import org.objectweb.asm.Opcodes;
8 import org.objectweb.asm.Type;
10 import java.util.Arrays;
11 import java.util.HashSet;
12 import java.util.Set;
14 /**
15 * Visits ClassLoader constructions so that we can record them in the agent
16 * and fixup their parents.
19 public class ClassLoaderVisitor extends ClassVisitor {
21 private static final String RECORD_CLASSLOADER = "recordClassLoader";
23 private static final String RECORD_CLASSLOADER_DESCRIPTOR = "(Ljava/lang/ClassLoader;)V";
25 private static final String CHECK_PARENT_CLASSLOADER = "checkParentClassLoader";
27 private static final String CHECK_PARENT_CLASSLOADER_DESCRIPTOR =
28 "(Ljava/lang/ClassLoader;)Ljava/lang/ClassLoader;";
30 private static final String URL_CLASSLOADER_CLASS = "java/net/URLClassLoader";
31 private static final String SECURE_CLASSLOADER_CLASS = "java/security/SecureClassLoader";
32 private static final String CLASSLOADER_CLASS = "java/lang/ClassLoader";
34 private static final String CONSTRUCTOR_METHOD = "<init>";
36 private static final String NEW_INSTANCE_METHOD = "newInstance";
38 private Set<String> classLoaderTypes = new HashSet<String>(Arrays.asList(URL_CLASSLOADER_CLASS,
39 SECURE_CLASSLOADER_CLASS, CLASSLOADER_CLASS));
41 public ClassLoaderVisitor(final ClassVisitor classVisitor) {
42 super(Opcodes.ASM4, classVisitor);
45 private static final Type CLASSLOADER_TYPE = Type.getType(ClassLoader.class);
47 @Override
48 public MethodVisitor visitMethod(int access, String name, String desc, String signature,
49 String[] exceptions) {
50 MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
51 return (mv == null) ? null : new MethodTranslator(mv, access, name, desc);
54 enum InitType {
55 None,
56 Init,
57 NewInstance,
60 private class MethodTranslator extends NonRecordingGeneratorAdapter {
61 MethodTranslator(MethodVisitor methodVisitor, int access, String name, String desc) {
62 super(methodVisitor, access, name, desc);
65 @Override
66 public void visitMethodInsn(int opcode, String owner, String name, String desc) {
67 InitType initType = initsNewClassLoader(owner, name);
68 if (initType == InitType.None) {
69 super.visitMethodInsn(opcode, owner, name, desc);
70 return;
73 Type[] argTypes = Type.getArgumentTypes(desc);
75 boolean acceptsParentClassLoader = argTypes.length > 0 &&
76 argTypes[argTypes.length - 1].equals(CLASSLOADER_TYPE);
78 if (!acceptsParentClassLoader) {
79 super.visitInsn(Opcodes.ACONST_NULL);
82 super.visitMethodInsn(Opcodes.INVOKESTATIC, AgentImpl.AGENT_RUNTIME,
83 CHECK_PARENT_CLASSLOADER, CHECK_PARENT_CLASSLOADER_DESCRIPTOR);
85 if (!acceptsParentClassLoader) {
86 Type[] newArgTypes = new Type[argTypes.length + 1];
87 System.arraycopy(argTypes, 0, newArgTypes, 0, argTypes.length);
88 newArgTypes[argTypes.length] = CLASSLOADER_TYPE;
89 argTypes = newArgTypes;
92 if (initType == InitType.Init) {
93 int[] locals = new int[argTypes.length];
95 for (int i = argTypes.length - 1; i >= 0; --i) {
96 locals[i] = super.newLocal(argTypes[i]);
97 super.storeLocal(locals[i]);
100 super.dup();
102 for (int i = 0; i < locals.length; ++i) {
103 super.loadLocal(locals[i]);
107 super.visitMethodInsn(opcode, owner, name,
108 Type.getMethodDescriptor(Type.getReturnType(desc), argTypes));
110 if (initType == InitType.NewInstance) {
111 super.dup();
114 super.visitMethodInsn(Opcodes.INVOKESTATIC, AgentImpl.AGENT_RUNTIME, RECORD_CLASSLOADER,
115 RECORD_CLASSLOADER_DESCRIPTOR);
118 private InitType initsNewClassLoader(String owner, String name) {
119 if (classLoaderTypes.contains(owner) && name.equals(CONSTRUCTOR_METHOD)) {
120 return InitType.Init;
123 if (owner.equals(URL_CLASSLOADER_CLASS) && name.equals(NEW_INSTANCE_METHOD)) {
124 return InitType.NewInstance;
127 return InitType.None;