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
;
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);
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
);
60 private class MethodTranslator
extends NonRecordingGeneratorAdapter
{
61 MethodTranslator(MethodVisitor methodVisitor
, int access
, String name
, String desc
) {
62 super(methodVisitor
, access
, name
, desc
);
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
);
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
]);
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
) {
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
;