feat(jdk8): move files to new folder to avoid resources compiled.
This commit is contained in:
435
jdkSrc/jdk8/sun/instrument/InstrumentationImpl.java
Normal file
435
jdkSrc/jdk8/sun/instrument/InstrumentationImpl.java
Normal file
@@ -0,0 +1,435 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package sun.instrument;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.AccessibleObject;
|
||||
|
||||
import java.lang.instrument.ClassFileTransformer;
|
||||
import java.lang.instrument.ClassDefinition;
|
||||
import java.lang.instrument.Instrumentation;
|
||||
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.security.ProtectionDomain;
|
||||
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
/*
|
||||
* Copyright 2003 Wily Technology, Inc.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The Java side of the JPLIS implementation. Works in concert with a native JVMTI agent
|
||||
* to implement the JPLIS API set. Provides both the Java API implementation of
|
||||
* the Instrumentation interface and utility Java routines to support the native code.
|
||||
* Keeps a pointer to the native data structure in a scalar field to allow native
|
||||
* processing behind native methods.
|
||||
*/
|
||||
public class InstrumentationImpl implements Instrumentation {
|
||||
private final TransformerManager mTransformerManager;
|
||||
private TransformerManager mRetransfomableTransformerManager;
|
||||
// needs to store a native pointer, so use 64 bits
|
||||
private final long mNativeAgent;
|
||||
private final boolean mEnvironmentSupportsRedefineClasses;
|
||||
private volatile boolean mEnvironmentSupportsRetransformClassesKnown;
|
||||
private volatile boolean mEnvironmentSupportsRetransformClasses;
|
||||
private final boolean mEnvironmentSupportsNativeMethodPrefix;
|
||||
|
||||
private
|
||||
InstrumentationImpl(long nativeAgent,
|
||||
boolean environmentSupportsRedefineClasses,
|
||||
boolean environmentSupportsNativeMethodPrefix) {
|
||||
mTransformerManager = new TransformerManager(false);
|
||||
mRetransfomableTransformerManager = null;
|
||||
mNativeAgent = nativeAgent;
|
||||
mEnvironmentSupportsRedefineClasses = environmentSupportsRedefineClasses;
|
||||
mEnvironmentSupportsRetransformClassesKnown = false; // false = need to ask
|
||||
mEnvironmentSupportsRetransformClasses = false; // don't know yet
|
||||
mEnvironmentSupportsNativeMethodPrefix = environmentSupportsNativeMethodPrefix;
|
||||
}
|
||||
|
||||
public void
|
||||
addTransformer(ClassFileTransformer transformer) {
|
||||
addTransformer(transformer, false);
|
||||
}
|
||||
|
||||
public synchronized void
|
||||
addTransformer(ClassFileTransformer transformer, boolean canRetransform) {
|
||||
if (transformer == null) {
|
||||
throw new NullPointerException("null passed as 'transformer' in addTransformer");
|
||||
}
|
||||
if (canRetransform) {
|
||||
if (!isRetransformClassesSupported()) {
|
||||
throw new UnsupportedOperationException(
|
||||
"adding retransformable transformers is not supported in this environment");
|
||||
}
|
||||
if (mRetransfomableTransformerManager == null) {
|
||||
mRetransfomableTransformerManager = new TransformerManager(true);
|
||||
}
|
||||
mRetransfomableTransformerManager.addTransformer(transformer);
|
||||
if (mRetransfomableTransformerManager.getTransformerCount() == 1) {
|
||||
setHasRetransformableTransformers(mNativeAgent, true);
|
||||
}
|
||||
} else {
|
||||
mTransformerManager.addTransformer(transformer);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized boolean
|
||||
removeTransformer(ClassFileTransformer transformer) {
|
||||
if (transformer == null) {
|
||||
throw new NullPointerException("null passed as 'transformer' in removeTransformer");
|
||||
}
|
||||
TransformerManager mgr = findTransformerManager(transformer);
|
||||
if (mgr != null) {
|
||||
mgr.removeTransformer(transformer);
|
||||
if (mgr.isRetransformable() && mgr.getTransformerCount() == 0) {
|
||||
setHasRetransformableTransformers(mNativeAgent, false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean
|
||||
isModifiableClass(Class<?> theClass) {
|
||||
if (theClass == null) {
|
||||
throw new NullPointerException(
|
||||
"null passed as 'theClass' in isModifiableClass");
|
||||
}
|
||||
return isModifiableClass0(mNativeAgent, theClass);
|
||||
}
|
||||
|
||||
public boolean
|
||||
isRetransformClassesSupported() {
|
||||
// ask lazily since there is some overhead
|
||||
if (!mEnvironmentSupportsRetransformClassesKnown) {
|
||||
mEnvironmentSupportsRetransformClasses = isRetransformClassesSupported0(mNativeAgent);
|
||||
mEnvironmentSupportsRetransformClassesKnown = true;
|
||||
}
|
||||
return mEnvironmentSupportsRetransformClasses;
|
||||
}
|
||||
|
||||
public void
|
||||
retransformClasses(Class<?>... classes) {
|
||||
if (!isRetransformClassesSupported()) {
|
||||
throw new UnsupportedOperationException(
|
||||
"retransformClasses is not supported in this environment");
|
||||
}
|
||||
retransformClasses0(mNativeAgent, classes);
|
||||
}
|
||||
|
||||
public boolean
|
||||
isRedefineClassesSupported() {
|
||||
return mEnvironmentSupportsRedefineClasses;
|
||||
}
|
||||
|
||||
public void
|
||||
redefineClasses(ClassDefinition... definitions)
|
||||
throws ClassNotFoundException {
|
||||
if (!isRedefineClassesSupported()) {
|
||||
throw new UnsupportedOperationException("redefineClasses is not supported in this environment");
|
||||
}
|
||||
if (definitions == null) {
|
||||
throw new NullPointerException("null passed as 'definitions' in redefineClasses");
|
||||
}
|
||||
for (int i = 0; i < definitions.length; ++i) {
|
||||
if (definitions[i] == null) {
|
||||
throw new NullPointerException("element of 'definitions' is null in redefineClasses");
|
||||
}
|
||||
}
|
||||
if (definitions.length == 0) {
|
||||
return; // short-circuit if there are no changes requested
|
||||
}
|
||||
|
||||
redefineClasses0(mNativeAgent, definitions);
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public Class[]
|
||||
getAllLoadedClasses() {
|
||||
return getAllLoadedClasses0(mNativeAgent);
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public Class[]
|
||||
getInitiatedClasses(ClassLoader loader) {
|
||||
return getInitiatedClasses0(mNativeAgent, loader);
|
||||
}
|
||||
|
||||
public long
|
||||
getObjectSize(Object objectToSize) {
|
||||
if (objectToSize == null) {
|
||||
throw new NullPointerException("null passed as 'objectToSize' in getObjectSize");
|
||||
}
|
||||
return getObjectSize0(mNativeAgent, objectToSize);
|
||||
}
|
||||
|
||||
public void
|
||||
appendToBootstrapClassLoaderSearch(JarFile jarfile) {
|
||||
appendToClassLoaderSearch0(mNativeAgent, jarfile.getName(), true);
|
||||
}
|
||||
|
||||
public void
|
||||
appendToSystemClassLoaderSearch(JarFile jarfile) {
|
||||
appendToClassLoaderSearch0(mNativeAgent, jarfile.getName(), false);
|
||||
}
|
||||
|
||||
public boolean
|
||||
isNativeMethodPrefixSupported() {
|
||||
return mEnvironmentSupportsNativeMethodPrefix;
|
||||
}
|
||||
|
||||
public synchronized void
|
||||
setNativeMethodPrefix(ClassFileTransformer transformer, String prefix) {
|
||||
if (!isNativeMethodPrefixSupported()) {
|
||||
throw new UnsupportedOperationException(
|
||||
"setNativeMethodPrefix is not supported in this environment");
|
||||
}
|
||||
if (transformer == null) {
|
||||
throw new NullPointerException(
|
||||
"null passed as 'transformer' in setNativeMethodPrefix");
|
||||
}
|
||||
TransformerManager mgr = findTransformerManager(transformer);
|
||||
if (mgr == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"transformer not registered in setNativeMethodPrefix");
|
||||
}
|
||||
mgr.setNativeMethodPrefix(transformer, prefix);
|
||||
String[] prefixes = mgr.getNativeMethodPrefixes();
|
||||
setNativeMethodPrefixes(mNativeAgent, prefixes, mgr.isRetransformable());
|
||||
}
|
||||
|
||||
private TransformerManager
|
||||
findTransformerManager(ClassFileTransformer transformer) {
|
||||
if (mTransformerManager.includesTransformer(transformer)) {
|
||||
return mTransformerManager;
|
||||
}
|
||||
if (mRetransfomableTransformerManager != null &&
|
||||
mRetransfomableTransformerManager.includesTransformer(transformer)) {
|
||||
return mRetransfomableTransformerManager;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Natives
|
||||
*/
|
||||
private native boolean
|
||||
isModifiableClass0(long nativeAgent, Class<?> theClass);
|
||||
|
||||
private native boolean
|
||||
isRetransformClassesSupported0(long nativeAgent);
|
||||
|
||||
private native void
|
||||
setHasRetransformableTransformers(long nativeAgent, boolean has);
|
||||
|
||||
private native void
|
||||
retransformClasses0(long nativeAgent, Class<?>[] classes);
|
||||
|
||||
private native void
|
||||
redefineClasses0(long nativeAgent, ClassDefinition[] definitions)
|
||||
throws ClassNotFoundException;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private native Class[]
|
||||
getAllLoadedClasses0(long nativeAgent);
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private native Class[]
|
||||
getInitiatedClasses0(long nativeAgent, ClassLoader loader);
|
||||
|
||||
private native long
|
||||
getObjectSize0(long nativeAgent, Object objectToSize);
|
||||
|
||||
private native void
|
||||
appendToClassLoaderSearch0(long nativeAgent, String jarfile, boolean bootLoader);
|
||||
|
||||
private native void
|
||||
setNativeMethodPrefixes(long nativeAgent, String[] prefixes, boolean isRetransformable);
|
||||
|
||||
static {
|
||||
System.loadLibrary("instrument");
|
||||
}
|
||||
|
||||
/*
|
||||
* Internals
|
||||
*/
|
||||
|
||||
|
||||
// Enable or disable Java programming language access checks on a
|
||||
// reflected object (for example, a method)
|
||||
private static void setAccessible(final AccessibleObject ao, final boolean accessible) {
|
||||
AccessController.doPrivileged(new PrivilegedAction<Object>() {
|
||||
public Object run() {
|
||||
ao.setAccessible(accessible);
|
||||
return null;
|
||||
}});
|
||||
}
|
||||
|
||||
// Attempt to load and start an agent
|
||||
private void
|
||||
loadClassAndStartAgent( String classname,
|
||||
String methodname,
|
||||
String optionsString)
|
||||
throws Throwable {
|
||||
|
||||
ClassLoader mainAppLoader = ClassLoader.getSystemClassLoader();
|
||||
Class<?> javaAgentClass = mainAppLoader.loadClass(classname);
|
||||
|
||||
Method m = null;
|
||||
NoSuchMethodException firstExc = null;
|
||||
boolean twoArgAgent = false;
|
||||
|
||||
// The agent class must have a premain or agentmain method that
|
||||
// has 1 or 2 arguments. We check in the following order:
|
||||
//
|
||||
// 1) declared with a signature of (String, Instrumentation)
|
||||
// 2) declared with a signature of (String)
|
||||
// 3) inherited with a signature of (String, Instrumentation)
|
||||
// 4) inherited with a signature of (String)
|
||||
//
|
||||
// So the declared version of either 1-arg or 2-arg always takes
|
||||
// primary precedence over an inherited version. After that, the
|
||||
// 2-arg version takes precedence over the 1-arg version.
|
||||
//
|
||||
// If no method is found then we throw the NoSuchMethodException
|
||||
// from the first attempt so that the exception text indicates
|
||||
// the lookup failed for the 2-arg method (same as JDK5.0).
|
||||
|
||||
try {
|
||||
m = javaAgentClass.getDeclaredMethod( methodname,
|
||||
new Class<?>[] {
|
||||
String.class,
|
||||
java.lang.instrument.Instrumentation.class
|
||||
}
|
||||
);
|
||||
twoArgAgent = true;
|
||||
} catch (NoSuchMethodException x) {
|
||||
// remember the NoSuchMethodException
|
||||
firstExc = x;
|
||||
}
|
||||
|
||||
if (m == null) {
|
||||
// now try the declared 1-arg method
|
||||
try {
|
||||
m = javaAgentClass.getDeclaredMethod(methodname,
|
||||
new Class<?>[] { String.class });
|
||||
} catch (NoSuchMethodException x) {
|
||||
// ignore this exception because we'll try
|
||||
// two arg inheritance next
|
||||
}
|
||||
}
|
||||
|
||||
if (m == null) {
|
||||
// now try the inherited 2-arg method
|
||||
try {
|
||||
m = javaAgentClass.getMethod( methodname,
|
||||
new Class<?>[] {
|
||||
String.class,
|
||||
java.lang.instrument.Instrumentation.class
|
||||
}
|
||||
);
|
||||
twoArgAgent = true;
|
||||
} catch (NoSuchMethodException x) {
|
||||
// ignore this exception because we'll try
|
||||
// one arg inheritance next
|
||||
}
|
||||
}
|
||||
|
||||
if (m == null) {
|
||||
// finally try the inherited 1-arg method
|
||||
try {
|
||||
m = javaAgentClass.getMethod(methodname,
|
||||
new Class<?>[] { String.class });
|
||||
} catch (NoSuchMethodException x) {
|
||||
// none of the methods exists so we throw the
|
||||
// first NoSuchMethodException as per 5.0
|
||||
throw firstExc;
|
||||
}
|
||||
}
|
||||
|
||||
// the premain method should not be required to be public,
|
||||
// make it accessible so we can call it
|
||||
// Note: The spec says the following:
|
||||
// The agent class must implement a public static premain method...
|
||||
setAccessible(m, true);
|
||||
|
||||
// invoke the 1 or 2-arg method
|
||||
if (twoArgAgent) {
|
||||
m.invoke(null, new Object[] { optionsString, this });
|
||||
} else {
|
||||
m.invoke(null, new Object[] { optionsString });
|
||||
}
|
||||
|
||||
// don't let others access a non-public premain method
|
||||
setAccessible(m, false);
|
||||
}
|
||||
|
||||
// WARNING: the native code knows the name & signature of this method
|
||||
private void
|
||||
loadClassAndCallPremain( String classname,
|
||||
String optionsString)
|
||||
throws Throwable {
|
||||
|
||||
loadClassAndStartAgent( classname, "premain", optionsString );
|
||||
}
|
||||
|
||||
|
||||
// WARNING: the native code knows the name & signature of this method
|
||||
private void
|
||||
loadClassAndCallAgentmain( String classname,
|
||||
String optionsString)
|
||||
throws Throwable {
|
||||
|
||||
loadClassAndStartAgent( classname, "agentmain", optionsString );
|
||||
}
|
||||
|
||||
// WARNING: the native code knows the name & signature of this method
|
||||
private byte[]
|
||||
transform( ClassLoader loader,
|
||||
String classname,
|
||||
Class<?> classBeingRedefined,
|
||||
ProtectionDomain protectionDomain,
|
||||
byte[] classfileBuffer,
|
||||
boolean isRetransformer) {
|
||||
TransformerManager mgr = isRetransformer?
|
||||
mRetransfomableTransformerManager :
|
||||
mTransformerManager;
|
||||
if (mgr == null) {
|
||||
return null; // no manager, no transform
|
||||
} else {
|
||||
return mgr.transform( loader,
|
||||
classname,
|
||||
classBeingRedefined,
|
||||
protectionDomain,
|
||||
classfileBuffer);
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user