History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/sun/instrument/InstrumentationImpl.java (1 of 18352 files). Show all

Unified · Split

java/pkg/sun/instrument/InstrumentationImpl.java+431−0
@@ -0,0 +1,431 @@
1+/*
2+ * Copyright (c) 2003, 2008, Oracle and/or its affiliates. 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. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+
27+package sun.instrument;
28+
29+import java.lang.reflect.Method;
30+import java.lang.reflect.AccessibleObject;
31+
32+import java.lang.instrument.ClassFileTransformer;
33+import java.lang.instrument.ClassDefinition;
34+import java.lang.instrument.Instrumentation;
35+
36+import java.security.AccessController;
37+import java.security.PrivilegedAction;
38+import java.security.ProtectionDomain;
39+
40+import java.util.jar.JarFile;
41+
42+/*
43+ * Copyright 2003 Wily Technology, Inc.
44+ */
45+
46+/**
47+ * The Java side of the JPLIS implementation. Works in concert with a native JVMTI agent
48+ * to implement the JPLIS API set. Provides both the Java API implementation of
49+ * the Instrumentation interface and utility Java routines to support the native code.
50+ * Keeps a pointer to the native data structure in a scalar field to allow native
51+ * processing behind native methods.
52+ */
53+public class InstrumentationImpl implements Instrumentation {
54+ private final TransformerManager mTransformerManager;
55+ private TransformerManager mRetransfomableTransformerManager;
56+ // needs to store a native pointer, so use 64 bits
57+ private final long mNativeAgent;
58+ private final boolean mEnvironmentSupportsRedefineClasses;
59+ private volatile boolean mEnvironmentSupportsRetransformClassesKnown;
60+ private volatile boolean mEnvironmentSupportsRetransformClasses;
61+ private final boolean mEnvironmentSupportsNativeMethodPrefix;
62+
63+ private
64+ InstrumentationImpl(long nativeAgent,
65+ boolean environmentSupportsRedefineClasses,
66+ boolean environmentSupportsNativeMethodPrefix) {
67+ mTransformerManager = new TransformerManager(false);
68+ mRetransfomableTransformerManager = null;
69+ mNativeAgent = nativeAgent;
70+ mEnvironmentSupportsRedefineClasses = environmentSupportsRedefineClasses;
71+ mEnvironmentSupportsRetransformClassesKnown = false; // false = need to ask
72+ mEnvironmentSupportsRetransformClasses = false; // don't know yet
73+ mEnvironmentSupportsNativeMethodPrefix = environmentSupportsNativeMethodPrefix;
74+ }
75+
76+ public void
77+ addTransformer(ClassFileTransformer transformer) {
78+ addTransformer(transformer, false);
79+ }
80+
81+ public synchronized void
82+ addTransformer(ClassFileTransformer transformer, boolean canRetransform) {
83+ if (transformer == null) {
84+ throw new NullPointerException("null passed as 'transformer' in addTransformer");
85+ }
86+ if (canRetransform) {
87+ if (!isRetransformClassesSupported()) {
88+ throw new UnsupportedOperationException(
89+ "adding retransformable transformers is not supported in this environment");
90+ }
91+ if (mRetransfomableTransformerManager == null) {
92+ mRetransfomableTransformerManager = new TransformerManager(true);
93+ }
94+ mRetransfomableTransformerManager.addTransformer(transformer);
95+ if (mRetransfomableTransformerManager.getTransformerCount() == 1) {
96+ setHasRetransformableTransformers(mNativeAgent, true);
97+ }
98+ } else {
99+ mTransformerManager.addTransformer(transformer);
100+ }
101+ }
102+
103+ public synchronized boolean
104+ removeTransformer(ClassFileTransformer transformer) {
105+ if (transformer == null) {
106+ throw new NullPointerException("null passed as 'transformer' in removeTransformer");
107+ }
108+ TransformerManager mgr = findTransformerManager(transformer);
109+ if (mgr != null) {
110+ mgr.removeTransformer(transformer);
111+ if (mgr.isRetransformable() && mgr.getTransformerCount() == 0) {
112+ setHasRetransformableTransformers(mNativeAgent, false);
113+ }
114+ return true;
115+ }
116+ return false;
117+ }
118+
119+ public boolean
120+ isModifiableClass(Class<?> theClass) {
121+ if (theClass == null) {
122+ throw new NullPointerException(
123+ "null passed as 'theClass' in isModifiableClass");
124+ }
125+ return isModifiableClass0(mNativeAgent, theClass);
126+ }
127+
128+ public boolean
129+ isRetransformClassesSupported() {
130+ // ask lazily since there is some overhead
131+ if (!mEnvironmentSupportsRetransformClassesKnown) {
132+ mEnvironmentSupportsRetransformClasses = isRetransformClassesSupported0(mNativeAgent);
133+ mEnvironmentSupportsRetransformClassesKnown = true;
134+ }
135+ return mEnvironmentSupportsRetransformClasses;
136+ }
137+
138+ public void
139+ retransformClasses(Class<?>[] classes) {
140+ if (!isRetransformClassesSupported()) {
141+ throw new UnsupportedOperationException(
142+ "retransformClasses is not supported in this environment");
143+ }
144+ retransformClasses0(mNativeAgent, classes);
145+ }
146+
147+ public boolean
148+ isRedefineClassesSupported() {
149+ return mEnvironmentSupportsRedefineClasses;
150+ }
151+
152+ public void
153+ redefineClasses(ClassDefinition[] definitions)
154+ throws ClassNotFoundException {
155+ if (!isRedefineClassesSupported()) {
156+ throw new UnsupportedOperationException("redefineClasses is not supported in this environment");
157+ }
158+ if (definitions == null) {
159+ throw new NullPointerException("null passed as 'definitions' in redefineClasses");
160+ }
161+ for (int i = 0; i < definitions.length; ++i) {
162+ if (definitions[i] == null) {
163+ throw new NullPointerException("element of 'definitions' is null in redefineClasses");
164+ }
165+ }
166+ if (definitions.length == 0) {
167+ return; // short-circuit if there are no changes requested
168+ }
169+
170+ redefineClasses0(mNativeAgent, definitions);
171+ }
172+
173+ public Class[]
174+ getAllLoadedClasses() {
175+ return getAllLoadedClasses0(mNativeAgent);
176+ }
177+
178+ public Class[]
179+ getInitiatedClasses(ClassLoader loader) {
180+ return getInitiatedClasses0(mNativeAgent, loader);
181+ }
182+
183+ public long
184+ getObjectSize(Object objectToSize) {
185+ if (objectToSize == null) {
186+ throw new NullPointerException("null passed as 'objectToSize' in getObjectSize");
187+ }
188+ return getObjectSize0(mNativeAgent, objectToSize);
189+ }
190+
191+ public void
192+ appendToBootstrapClassLoaderSearch(JarFile jarfile) {
193+ appendToClassLoaderSearch0(mNativeAgent, jarfile.getName(), true);
194+ }
195+
196+ public void
197+ appendToSystemClassLoaderSearch(JarFile jarfile) {
198+ appendToClassLoaderSearch0(mNativeAgent, jarfile.getName(), false);
199+ }
200+
201+ public boolean
202+ isNativeMethodPrefixSupported() {
203+ return mEnvironmentSupportsNativeMethodPrefix;
204+ }
205+
206+ public synchronized void
207+ setNativeMethodPrefix(ClassFileTransformer transformer, String prefix) {
208+ if (!isNativeMethodPrefixSupported()) {
209+ throw new UnsupportedOperationException(
210+ "setNativeMethodPrefix is not supported in this environment");
211+ }
212+ if (transformer == null) {
213+ throw new NullPointerException(
214+ "null passed as 'transformer' in setNativeMethodPrefix");
215+ }
216+ TransformerManager mgr = findTransformerManager(transformer);
217+ if (mgr == null) {
218+ throw new IllegalArgumentException(
219+ "transformer not registered in setNativeMethodPrefix");
220+ }
221+ mgr.setNativeMethodPrefix(transformer, prefix);
222+ String[] prefixes = mgr.getNativeMethodPrefixes();
223+ setNativeMethodPrefixes(mNativeAgent, prefixes, mgr.isRetransformable());
224+ }
225+
226+ private TransformerManager
227+ findTransformerManager(ClassFileTransformer transformer) {
228+ if (mTransformerManager.includesTransformer(transformer)) {
229+ return mTransformerManager;
230+ }
231+ if (mRetransfomableTransformerManager != null &&
232+ mRetransfomableTransformerManager.includesTransformer(transformer)) {
233+ return mRetransfomableTransformerManager;
234+ }
235+ return null;
236+ }
237+
238+
239+ /*
240+ * Natives
241+ */
242+ private native boolean
243+ isModifiableClass0(long nativeAgent, Class<?> theClass);
244+
245+ private native boolean
246+ isRetransformClassesSupported0(long nativeAgent);
247+
248+ private native void
249+ setHasRetransformableTransformers(long nativeAgent, boolean has);
250+
251+ private native void
252+ retransformClasses0(long nativeAgent, Class<?>[] classes);
253+
254+ private native void
255+ redefineClasses0(long nativeAgent, ClassDefinition[] definitions)
256+ throws ClassNotFoundException;
257+
258+ private native Class[]
259+ getAllLoadedClasses0(long nativeAgent);
260+
261+ private native Class[]
262+ getInitiatedClasses0(long nativeAgent, ClassLoader loader);
263+
264+ private native long
265+ getObjectSize0(long nativeAgent, Object objectToSize);
266+
267+ private native void
268+ appendToClassLoaderSearch0(long nativeAgent, String jarfile, boolean bootLoader);
269+
270+ private native void
271+ setNativeMethodPrefixes(long nativeAgent, String[] prefixes, boolean isRetransformable);
272+
273+ static {
274+ System.loadLibrary("instrument");
275+ }
276+
277+ /*
278+ * Internals
279+ */
280+
281+
282+ // Enable or disable Java programming language access checks on a
283+ // reflected object (for example, a method)
284+ private static void setAccessible(final AccessibleObject ao, final boolean accessible) {
285+ AccessController.doPrivileged(new PrivilegedAction<Object>() {
286+ public Object run() {
287+ ao.setAccessible(accessible);
288+ return null;
289+ }});
290+ }
291+
292+ // Attempt to load and start an agent
293+ private void
294+ loadClassAndStartAgent( String classname,
295+ String methodname,
296+ String optionsString)
297+ throws Throwable {
298+
299+ ClassLoader mainAppLoader = ClassLoader.getSystemClassLoader();
300+ Class<?> javaAgentClass = mainAppLoader.loadClass(classname);
301+
302+ Method m = null;
303+ NoSuchMethodException firstExc = null;
304+ boolean twoArgAgent = false;
305+
306+ // The agent class must have a premain or agentmain method that
307+ // has 1 or 2 arguments. We check in the following order:
308+ //
309+ // 1) declared with a signature of (String, Instrumentation)
310+ // 2) declared with a signature of (String)
311+ // 3) inherited with a signature of (String, Instrumentation)
312+ // 4) inherited with a signature of (String)
313+ //
314+ // So the declared version of either 1-arg or 2-arg always takes
315+ // primary precedence over an inherited version. After that, the
316+ // 2-arg version takes precedence over the 1-arg version.
317+ //
318+ // If no method is found then we throw the NoSuchMethodException
319+ // from the first attempt so that the exception text indicates
320+ // the lookup failed for the 2-arg method (same as JDK5.0).
321+
322+ try {
323+ m = javaAgentClass.getDeclaredMethod( methodname,
324+ new Class[] {
325+ String.class,
326+ java.lang.instrument.Instrumentation.class
327+ }
328+ );
329+ twoArgAgent = true;
330+ } catch (NoSuchMethodException x) {
331+ // remember the NoSuchMethodException
332+ firstExc = x;
333+ }
334+
335+ if (m == null) {
336+ // now try the declared 1-arg method
337+ try {
338+ m = javaAgentClass.getDeclaredMethod(methodname,
339+ new Class[] { String.class });
340+ } catch (NoSuchMethodException x) {
341+ // ignore this exception because we'll try
342+ // two arg inheritance next
343+ }
344+ }
345+
346+ if (m == null) {
347+ // now try the inherited 2-arg method
348+ try {
349+ m = javaAgentClass.getMethod( methodname,
350+ new Class[] {
351+ String.class,
352+ java.lang.instrument.Instrumentation.class
353+ }
354+ );
355+ twoArgAgent = true;
356+ } catch (NoSuchMethodException x) {
357+ // ignore this exception because we'll try
358+ // one arg inheritance next
359+ }
360+ }
361+
362+ if (m == null) {
363+ // finally try the inherited 1-arg method
364+ try {
365+ m = javaAgentClass.getMethod(methodname,
366+ new Class[] { String.class });
367+ } catch (NoSuchMethodException x) {
368+ // none of the methods exists so we throw the
369+ // first NoSuchMethodException as per 5.0
370+ throw firstExc;
371+ }
372+ }
373+
374+ // the premain method should not be required to be public,
375+ // make it accessible so we can call it
376+ // Note: The spec says the following:
377+ // The agent class must implement a public static premain method...
378+ setAccessible(m, true);
379+
380+ // invoke the 1 or 2-arg method
381+ if (twoArgAgent) {
382+ m.invoke(null, new Object[] { optionsString, this });
383+ } else {
384+ m.invoke(null, new Object[] { optionsString });
385+ }
386+
387+ // don't let others access a non-public premain method
388+ setAccessible(m, false);
389+ }
390+
391+ // WARNING: the native code knows the name & signature of this method
392+ private void
393+ loadClassAndCallPremain( String classname,
394+ String optionsString)
395+ throws Throwable {
396+
397+ loadClassAndStartAgent( classname, "premain", optionsString );
398+ }
399+
400+
401+ // WARNING: the native code knows the name & signature of this method
402+ private void
403+ loadClassAndCallAgentmain( String classname,
404+ String optionsString)
405+ throws Throwable {
406+
407+ loadClassAndStartAgent( classname, "agentmain", optionsString );
408+ }
409+
410+ // WARNING: the native code knows the name & signature of this method
411+ private byte[]
412+ transform( ClassLoader loader,
413+ String classname,
414+ Class classBeingRedefined,
415+ ProtectionDomain protectionDomain,
416+ byte[] classfileBuffer,
417+ boolean isRetransformer) {
418+ TransformerManager mgr = isRetransformer?
419+ mRetransfomableTransformerManager :
420+ mTransformerManager;
421+ if (mgr == null) {
422+ return null; // no manager, no transform
423+ } else {
424+ return mgr.transform( loader,
425+ classname,
426+ classBeingRedefined,
427+ protectionDomain,
428+ classfileBuffer);
429+ }
430+ }
431+}