blob: be0f4d33602baa1e75c19557d5668607d3d74f12 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.instrument;
27
28
29import java.lang.instrument.Instrumentation;
30import java.lang.instrument.ClassFileTransformer;
31import java.security.ProtectionDomain;
32
33/*
34 * Copyright 2003 Wily Technology, Inc.
35 */
36
37/**
38 * Support class for the InstrumentationImpl. Manages the list of registered transformers.
39 * Keeps everything in the right order, deals with sync of the list,
40 * and actually does the calling of the transformers.
41 */
42public class TransformerManager
43{
44 private class TransformerInfo {
45 final ClassFileTransformer mTransformer;
46 String mPrefix;
47
48 TransformerInfo(ClassFileTransformer transformer) {
49 mTransformer = transformer;
50 mPrefix = null;
51 }
52
53 ClassFileTransformer transformer() {
54 return mTransformer;
55 }
56
57 String getPrefix() {
58 return mPrefix;
59 }
60
61 void setPrefix(String prefix) {
62 mPrefix = prefix;
63 }
64 }
65
66 /**
67 * a given instance of this list is treated as immutable to simplify sync;
68 * we pay copying overhead whenever the list is changed rather than every time
69 * the list is referenced.
70 * The array is kept in the order the transformers are added via addTransformer
71 * (first added is 0, last added is length-1)
72 * Use an array, not a List or other Collection. This keeps the set of classes
73 * used by this code to a minimum. We want as few dependencies as possible in this
74 * code, since it is used inside the class definition system. Any class referenced here
75 * cannot be transformed by Java code.
76 */
77 private TransformerInfo[] mTransformerList;
78
79 /***
80 * Is this TransformerManager for transformers capable of retransformation?
81 */
82 private boolean mIsRetransformable;
83
84 TransformerManager(boolean isRetransformable) {
85 mTransformerList = new TransformerInfo[0];
86 mIsRetransformable = isRetransformable;
87 }
88
89 boolean isRetransformable() {
90 return mIsRetransformable;
91 }
92
93 public synchronized void
94 addTransformer( ClassFileTransformer transformer) {
95 TransformerInfo[] oldList = mTransformerList;
96 TransformerInfo[] newList = new TransformerInfo[oldList.length + 1];
97 System.arraycopy( oldList,
98 0,
99 newList,
100 0,
101 oldList.length);
102 newList[oldList.length] = new TransformerInfo(transformer);
103 mTransformerList = newList;
104 }
105
106 public synchronized boolean
107 removeTransformer(ClassFileTransformer transformer) {
108 boolean found = false;
109 TransformerInfo[] oldList = mTransformerList;
110 int oldLength = oldList.length;
111 int newLength = oldLength - 1;
112
113 // look for it in the list, starting at the last added, and remember
114 // where it was if we found it
115 int matchingIndex = 0;
116 for ( int x = oldLength - 1; x >= 0; x-- ) {
117 if ( oldList[x].transformer() == transformer ) {
118 found = true;
119 matchingIndex = x;
120 break;
121 }
122 }
123
124 // make a copy of the array without the matching element
125 if ( found ) {
126 TransformerInfo[] newList = new TransformerInfo[newLength];
127
128 // copy up to but not including the match
129 if ( matchingIndex > 0 ) {
130 System.arraycopy( oldList,
131 0,
132 newList,
133 0,
134 matchingIndex);
135 }
136
137 // if there is anything after the match, copy it as well
138 if ( matchingIndex < (newLength) ) {
139 System.arraycopy( oldList,
140 matchingIndex + 1,
141 newList,
142 matchingIndex,
143 (newLength) - matchingIndex);
144 }
145 mTransformerList = newList;
146 }
147 return found;
148 }
149
150 synchronized boolean
151 includesTransformer(ClassFileTransformer transformer) {
152 for (TransformerInfo info : mTransformerList) {
153 if ( info.transformer() == transformer ) {
154 return true;
155 }
156 }
157 return false;
158 }
159
160 // This function doesn't actually snapshot anything, but should be
161 // used to set a local variable, which will snapshot the transformer
162 // list because of the copying semantics of mTransformerList (see
163 // the comment for mTransformerList).
164 private TransformerInfo[]
165 getSnapshotTransformerList() {
166 return mTransformerList;
167 }
168
169 public byte[]
170 transform( ClassLoader loader,
171 String classname,
172 Class classBeingRedefined,
173 ProtectionDomain protectionDomain,
174 byte[] classfileBuffer) {
175 boolean someoneTouchedTheBytecode = false;
176
177 TransformerInfo[] transformerList = getSnapshotTransformerList();
178
179 byte[] bufferToUse = classfileBuffer;
180
181 // order matters, gotta run 'em in the order they were added
182 for ( int x = 0; x < transformerList.length; x++ ) {
183 TransformerInfo transformerInfo = transformerList[x];
184 ClassFileTransformer transformer = transformerInfo.transformer();
185 byte[] transformedBytes = null;
186
187 try {
188 transformedBytes = transformer.transform( loader,
189 classname,
190 classBeingRedefined,
191 protectionDomain,
192 bufferToUse);
193 }
194 catch (Throwable t) {
195 // don't let any one transformer mess it up for the others.
196 // This is where we need to put some logging. What should go here? FIXME
197 }
198
199 if ( transformedBytes != null ) {
200 someoneTouchedTheBytecode = true;
201 bufferToUse = transformedBytes;
202 }
203 }
204
205 // if someone modified it, return the modified buffer.
206 // otherwise return null to mean "no transforms occurred"
207 byte [] result;
208 if ( someoneTouchedTheBytecode ) {
209 result = bufferToUse;
210 }
211 else {
212 result = null;
213 }
214
215 return result;
216 }
217
218
219 int
220 getTransformerCount() {
221 TransformerInfo[] transformerList = getSnapshotTransformerList();
222 return transformerList.length;
223 }
224
225 boolean
226 setNativeMethodPrefix(ClassFileTransformer transformer, String prefix) {
227 TransformerInfo[] transformerList = getSnapshotTransformerList();
228
229 for ( int x = 0; x < transformerList.length; x++ ) {
230 TransformerInfo transformerInfo = transformerList[x];
231 ClassFileTransformer aTransformer = transformerInfo.transformer();
232
233 if ( aTransformer == transformer ) {
234 transformerInfo.setPrefix(prefix);
235 return true;
236 }
237 }
238 return false;
239 }
240
241
242 String[]
243 getNativeMethodPrefixes() {
244 TransformerInfo[] transformerList = getSnapshotTransformerList();
245 String[] prefixes = new String[transformerList.length];
246
247 for ( int x = 0; x < transformerList.length; x++ ) {
248 TransformerInfo transformerInfo = transformerList[x];
249 prefixes[x] = transformerInfo.getPrefix();
250 }
251 return prefixes;
252 }
253}