//这是一个包装类:将需要重新定义的类和增强字节码包装在一起
package java.lang.instrument
//这个类作为Instrumentation.redefineClasses方法的参数
//用于将需要重新定义的类绑定到新的字节码中
public final class ClassDefinition {
//需要重新定义的类
private final Class> mClass;
//替换的字节码
private final byte[] mClassFile;
//创建一个新的类绑定类和类文件字节码。
//不复制提供的缓冲区,只是捕获对它的引用。只是赋值操作
public ClassDefinition(Class> theClass,byte[] theClassFile){
if (theClass == null || theClassFile == null) {
//传入参数为空
throw new NullPointerException();
}
//赋值操作
mClass=theClass;
mClassFile=theClassFile;
}
public Class> getDefinitionClass() {
return mClass;
}
//返回包含新类文件的字节数组。
public byte[] getDefinitionClassFile() {
return mClassFile;
}
}
package java.lang.instrument;
import java.security.ProtectionDomain;
/**
一个代理类提供了这个接口的实现用于转化class文件(字节码文件)。转换发生在class 被JVM定义之前。注意术语“class file”被用于定义在3.1节"Java™ Virtual Machine Specification",虚拟机规范是指类文件格式中的一系列字节,不管它们是否驻留在文件中。
**/
public interface ClassFileTransformer {
/**
此方法的实现可能会转换提供的类文件并返回一个新的替换类文件。有两种变换器,由java.lang.instrument.Instrumentation#addTransformer(ClassFileTransformer ,boolean)的“canRetransform”参数确定。
a.canRetransform=true 允许重新转换
b.canRetransform=false 不允许重新转换
c.addTransformer(ClassFileTransformer) 不允许重新转换
一旦转换器已经用java.lang.instrument.Instrumentation注册#addTransformer(ClassFileTransformer,boolean)
addTransformer,将为每个新的类定义和每个类的重新定义调用转换器。每个类重新转换也将调用能够转换的变换器.
/**
* The implementation of this method may transform the supplied class file and
* return a new replacement class file.
*
*
* There are two kinds of transformers, determined by the canRetransform
* parameter of
* {@link java.lang.instrument.Instrumentation#addTransformer(ClassFileTransformer,boolean)}:
*
* - retransformation capable transformers that were added with
*
canRetransform
as true
*
* - retransformation incapable transformers that were added with
*
canRetransform
as false or where added with
* {@link java.lang.instrument.Instrumentation#addTransformer(ClassFileTransformer)}
*
*
*
*
* Once a transformer has been registered with
* {@link java.lang.instrument.Instrumentation#addTransformer(ClassFileTransformer,boolean)
* addTransformer},
* the transformer will be called for every new class definition and every class redefinition.
* Retransformation capable transformers will also be called on every class retransformation.
* The request for a new class definition is made with
* {@link java.lang.ClassLoader#defineClass ClassLoader.defineClass}
* or its native equivalents.
* The request for a class redefinition is made with
* {@link java.lang.instrument.Instrumentation#redefineClasses Instrumentation.redefineClasses}
* or its native equivalents.
* The request for a class retransformation is made with
* {@link java.lang.instrument.Instrumentation#retransformClasses Instrumentation.retransformClasses}
* or its native equivalents.
* The transformer is called during the processing of the request, before the class file bytes
* have been verified or applied.
* When there are multiple transformers, transformations are composed by chaining the
* transform
calls.
* That is, the byte array returned by one call to transform
becomes the input
* (via the classfileBuffer
parameter) to the next call.
*
*
* Transformations are applied in the following order:
*
* - Retransformation incapable transformers
*
* - Retransformation incapable native transformers
*
* - Retransformation capable transformers
*
* - Retransformation capable native transformers
*
*
*
*
* For retransformations, the retransformation incapable transformers are not
* called, instead the result of the previous transformation is reused.
* In all other cases, this method is called.
* Within each of these groupings, transformers are called in the order registered.
* Native transformers are provided by the ClassFileLoadHook
event
* in the Java Virtual Machine Tool Interface).
*
*
* The input (via the classfileBuffer
parameter) to the first
* transformer is:
*
* - for new class definition,
* the bytes passed to
ClassLoader.defineClass
*
* - for class redefinition,
*
definitions.getDefinitionClassFile()
where
* definitions
is the parameter to
* {@link java.lang.instrument.Instrumentation#redefineClasses
* Instrumentation.redefineClasses}
*
* - for class retransformation,
* the bytes passed to the new class definition or, if redefined,
* the last redefinition, with all transformations made by retransformation
* incapable transformers reapplied automatically and unaltered;
* for details see
* {@link java.lang.instrument.Instrumentation#retransformClasses
* Instrumentation.retransformClasses}
*
*
*
*
* If the implementing method determines that no transformations are needed,
* it should return null
.
* Otherwise, it should create a new byte[]
array,
* copy the input classfileBuffer
into it,
* along with all desired transformations, and return the new array.
* The input classfileBuffer
must not be modified.
*
*
* In the retransform and redefine cases,
* the transformer must support the redefinition semantics:
* if a class that the transformer changed during initial definition is later
* retransformed or redefined, the
* transformer must insure that the second class output class file is a legal
* redefinition of the first output class file.
*
*
* If the transformer throws an exception (which it doesn't catch),
* subsequent transformers will still be called and the load, redefine
* or retransform will still be attempted.
* Thus, throwing an exception has the same effect as returning null
.
* To prevent unexpected behavior when unchecked exceptions are generated
* in transformer code, a transformer can catch Throwable
.
* If the transformer believes the classFileBuffer
does not
* represent a validly formatted class file, it should throw
* an IllegalClassFormatException
;
* while this has the same effect as returning null. it facilitates the
* logging or debugging of format corruptions.
*
* @param loader the defining loader of the class to be transformed,
* may be null
if the bootstrap loader
* @param className the name of the class in the internal form of fully
* qualified class and interface names as defined in
* The Java Virtual Machine Specification.
* For example, "java/util/List"
.
* @param classBeingRedefined if this is triggered by a redefine or retransform,
* the class being redefined or retransformed;
* if this is a class load, null
* @param protectionDomain the protection domain of the class being defined or redefined
* @param classfileBuffer the input byte buffer in class file format - must not be modified
*
* @throws IllegalClassFormatException if the input does not represent a well-formed class file
* @return a well-formed class file buffer (the result of the transform),
or null
if no transform is performed.
* @see Instrumentation#redefineClasses
*/
byte[] transform(
ClassLoader loader,
String className,
Class> classBeingRedefined,
ProtectionDomain protectionDomain,
byte[] classfileBuffer)
throws IllegalClassFormatException;
}
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package java.lang.instrument;
import java.io.File;
import java.io.IOException;
import java.util.jar.JarFile;
/*
* Copyright 2003 Wily Technology, Inc.
*/
/**
* This class provides services needed to instrument Java
* programming language code.
* Instrumentation is the addition of byte-codes to methods for the
* purpose of gathering data to be utilized by tools.
* Since the changes are purely additive, these tools do not modify
* application state or behavior.
* Examples of such benign tools include monitoring agents, profilers,
* coverage analyzers, and event loggers.
*
*
* There are two ways to obtain an instance of the
* Instrumentation
interface:
*
*
* When a JVM is launched in a way that indicates an agent
* class. In that case an Instrumentation
instance
* is passed to the premain
method of the agent class.
*
* When a JVM provides a mechanism to start agents sometime
* after the JVM is launched. In that case an Instrumentation
* instance is passed to the agentmain
method of the
* agent code.
*
*
* These mechanisms are described in the
* {@linkplain java.lang.instrument package specification}.
*
* Once an agent acquires an Instrumentation
instance,
* the agent may call methods on the instance at any time.
*
* @since 1.5
*/
public interface Instrumentation {
/**
* Registers the supplied transformer. All future class definitions
* will be seen by the transformer, except definitions of classes upon which any
* registered transformer is dependent.
* The transformer is called when classes are loaded, when they are
* {@linkplain #redefineClasses redefined}. and if canRetransform
is true,
* when they are {@linkplain #retransformClasses retransformed}.
* See {@link java.lang.instrument.ClassFileTransformer#transform
* ClassFileTransformer.transform} for the order
* of transform calls.
* If a transformer throws
* an exception during execution, the JVM will still call the other registered
* transformers in order. The same transformer may be added more than once,
* but it is strongly discouraged -- avoid this by creating a new instance of
* transformer class.
*
* This method is intended for use in instrumentation, as described in the
* {@linkplain Instrumentation class specification}.
*
* @param transformer the transformer to register
* @param canRetransform can this transformer's transformations be retransformed
* @throws java.lang.NullPointerException if passed a null
transformer
* @throws java.lang.UnsupportedOperationException if canRetransform
* is true and the current configuration of the JVM does not allow
* retransformation ({@link #isRetransformClassesSupported} is false)
* @since 1.6
*/
void
addTransformer(ClassFileTransformer transformer, boolean canRetransform);
/**
* Registers the supplied transformer.
*
* Same as addTransformer(transformer, false)
.
*
* @param transformer the transformer to register
* @throws java.lang.NullPointerException if passed a null
transformer
* @see #addTransformer(ClassFileTransformer,boolean)
*/
void
addTransformer(ClassFileTransformer transformer);
/**
* Unregisters the supplied transformer. Future class definitions will
* not be shown to the transformer. Removes the most-recently-added matching
* instance of the transformer. Due to the multi-threaded nature of
* class loading, it is possible for a transformer to receive calls
* after it has been removed. Transformers should be written defensively
* to expect this situation.
*
* @param transformer the transformer to unregister
* @return true if the transformer was found and removed, false if the
* transformer was not found
* @throws java.lang.NullPointerException if passed a null
transformer
*/
boolean
removeTransformer(ClassFileTransformer transformer);
/**
* Returns whether or not the current JVM configuration supports retransformation
* of classes.
* The ability to retransform an already loaded class is an optional capability
* of a JVM.
* Retransformation will only be supported if the
* Can-Retransform-Classes
manifest attribute is set to
* true
in the agent JAR file (as described in the
* {@linkplain java.lang.instrument package specification}) and the JVM supports
* this capability.
* During a single instantiation of a single JVM, multiple calls to this
* method will always return the same answer.
* @return true if the current JVM configuration supports retransformation of
* classes, false if not.
* @see #retransformClasses
* @since 1.6
*/
boolean
isRetransformClassesSupported();
/**
* Retransform the supplied set of classes.
*
*
* This function facilitates the instrumentation
* of already loaded classes.
* When classes are initially loaded or when they are
* {@linkplain #redefineClasses redefined},
* the initial class file bytes can be transformed with the
* {@link java.lang.instrument.ClassFileTransformer ClassFileTransformer}.
* This function reruns the transformation process
* (whether or not a transformation has previously occurred).
* This retransformation follows these steps:
*
* - starting from the initial class file bytes
*
* - for each transformer that was added with
canRetransform
* false, the bytes returned by
* {@link java.lang.instrument.ClassFileTransformer#transform transform}
* during the last class load or redefine are
* reused as the output of the transformation; note that this is
* equivalent to reapplying the previous transformation, unaltered;
* except that
* {@link java.lang.instrument.ClassFileTransformer#transform transform}
* is not called
*
* - for each transformer that was added with
canRetransform
* true, the
* {@link java.lang.instrument.ClassFileTransformer#transform transform}
* method is called in these transformers
*
* - the transformed class file bytes are installed as the new
* definition of the class
*
*
*
*
* The order of transformation is described in the
* {@link java.lang.instrument.ClassFileTransformer#transform transform} method.
* This same order is used in the automatic reapplication of retransformation
* incapable transforms.
*
*
* The initial class file bytes represent the bytes passed to
* {@link java.lang.ClassLoader#defineClass ClassLoader.defineClass} or
* {@link #redefineClasses redefineClasses}
* (before any transformations
* were applied), however they might not exactly match them.
* The constant pool might not have the same layout or contents.
* The constant pool may have more or fewer entries.
* Constant pool entries may be in a different order; however,
* constant pool indices in the bytecodes of methods will correspond.
* Some attributes may not be present.
* Where order is not meaningful, for example the order of methods,
* order might not be preserved.
*
*
* This method operates on
* a set in order to allow interdependent changes to more than one class at the same time
* (a retransformation of class A can require a retransformation of class B).
*
*
* If a retransformed method has active stack frames, those active frames continue to
* run the bytecodes of the original method.
* The retransformed method will be used on new invokes.
*
*
* This method does not cause any initialization except that which would occur
* under the customary JVM semantics. In other words, redefining a class
* does not cause its initializers to be run. The values of static variables
* will remain as they were prior to the call.
*
*
* Instances of the retransformed class are not affected.
*
*
* The retransformation may change method bodies, the constant pool and attributes.
* The retransformation must not add, remove or rename fields or methods, change the
* signatures of methods, or change inheritance. These restrictions maybe be
* lifted in future versions. The class file bytes are not checked, verified and installed
* until after the transformations have been applied, if the resultant bytes are in
* error this method will throw an exception.
*
*
* If this method throws an exception, no classes have been retransformed.
*
* This method is intended for use in instrumentation, as described in the
* {@linkplain Instrumentation class specification}.
*
* @param classes array of classes to retransform;
* a zero-length array is allowed, in this case, this method does nothing
* @throws java.lang.instrument.UnmodifiableClassException if a specified class cannot be modified
* ({@link #isModifiableClass} would return false
)
* @throws java.lang.UnsupportedOperationException if the current configuration of the JVM does not allow
* retransformation ({@link #isRetransformClassesSupported} is false) or the retransformation attempted
* to make unsupported changes
* @throws java.lang.ClassFormatError if the data did not contain a valid class
* @throws java.lang.NoClassDefFoundError if the name in the class file is not equal to the name of the class
* @throws java.lang.UnsupportedClassVersionError if the class file version numbers are not supported
* @throws java.lang.ClassCircularityError if the new classes contain a circularity
* @throws java.lang.LinkageError if a linkage error occurs
* @throws java.lang.NullPointerException if the supplied classes array or any of its components
* is null
.
*
* @see #isRetransformClassesSupported
* @see #addTransformer
* @see java.lang.instrument.ClassFileTransformer
* @since 1.6
*/
void
retransformClasses(Class>... classes) throws UnmodifiableClassException;
/**
* Returns whether or not the current JVM configuration supports redefinition
* of classes.
* The ability to redefine an already loaded class is an optional capability
* of a JVM.
* Redefinition will only be supported if the
* Can-Redefine-Classes
manifest attribute is set to
* true
in the agent JAR file (as described in the
* {@linkplain java.lang.instrument package specification}) and the JVM supports
* this capability.
* During a single instantiation of a single JVM, multiple calls to this
* method will always return the same answer.
* @return true if the current JVM configuration supports redefinition of classes,
* false if not.
* @see #redefineClasses
*/
boolean
isRedefineClassesSupported();
/**
* Redefine the supplied set of classes using the supplied class files.
*
*
* This method is used to replace the definition of a class without reference
* to the existing class file bytes, as one might do when recompiling from source
* for fix-and-continue debugging.
* Where the existing class file bytes are to be transformed (for
* example in bytecode instrumentation)
* {@link #retransformClasses retransformClasses}
* should be used.
*
*
* This method operates on
* a set in order to allow interdependent changes to more than one class at the same time
* (a redefinition of class A can require a redefinition of class B).
*
*
* If a redefined method has active stack frames, those active frames continue to
* run the bytecodes of the original method.
* The redefined method will be used on new invokes.
*
*
* This method does not cause any initialization except that which would occur
* under the customary JVM semantics. In other words, redefining a class
* does not cause its initializers to be run. The values of static variables
* will remain as they were prior to the call.
*
*
* Instances of the redefined class are not affected.
*
*
* The redefinition may change method bodies, the constant pool and attributes.
* The redefinition must not add, remove or rename fields or methods, change the
* signatures of methods, or change inheritance. These restrictions maybe be
* lifted in future versions. The class file bytes are not checked, verified and installed
* until after the transformations have been applied, if the resultant bytes are in
* error this method will throw an exception.
*
*
* If this method throws an exception, no classes have been redefined.
*
* This method is intended for use in instrumentation, as described in the
* {@linkplain Instrumentation class specification}.
*
* @param definitions array of classes to redefine with corresponding definitions;
* a zero-length array is allowed, in this case, this method does nothing
* @throws java.lang.instrument.UnmodifiableClassException if a specified class cannot be modified
* ({@link #isModifiableClass} would return false
)
* @throws java.lang.UnsupportedOperationException if the current configuration of the JVM does not allow
* redefinition ({@link #isRedefineClassesSupported} is false) or the redefinition attempted
* to make unsupported changes
* @throws java.lang.ClassFormatError if the data did not contain a valid class
* @throws java.lang.NoClassDefFoundError if the name in the class file is not equal to the name of the class
* @throws java.lang.UnsupportedClassVersionError if the class file version numbers are not supported
* @throws java.lang.ClassCircularityError if the new classes contain a circularity
* @throws java.lang.LinkageError if a linkage error occurs
* @throws java.lang.NullPointerException if the supplied definitions array or any of its components
* is null
* @throws java.lang.ClassNotFoundException Can never be thrown (present for compatibility reasons only)
*
* @see #isRedefineClassesSupported
* @see #addTransformer
* @see java.lang.instrument.ClassFileTransformer
*/
void
redefineClasses(ClassDefinition... definitions)
throws ClassNotFoundException, UnmodifiableClassException;
/**
* Determines whether a class is modifiable by
* {@linkplain #retransformClasses retransformation}
* or {@linkplain #redefineClasses redefinition}.
* If a class is modifiable then this method returns true
.
* If a class is not modifiable then this method returns false
.
*
* For a class to be retransformed, {@link #isRetransformClassesSupported} must also be true.
* But the value of isRetransformClassesSupported()
does not influence the value
* returned by this function.
* For a class to be redefined, {@link #isRedefineClassesSupported} must also be true.
* But the value of isRedefineClassesSupported()
does not influence the value
* returned by this function.
*
* Primitive classes (for example, java.lang.Integer.TYPE
)
* and array classes are never modifiable.
*
* @param theClass the class to check for being modifiable
* @return whether or not the argument class is modifiable
* @throws java.lang.NullPointerException if the specified class is null
.
*
* @see #retransformClasses
* @see #isRetransformClassesSupported
* @see #redefineClasses
* @see #isRedefineClassesSupported
* @since 1.6
*/
boolean
isModifiableClass(Class> theClass);
/**
* Returns an array of all classes currently loaded by the JVM.
*
* @return an array containing all the classes loaded by the JVM, zero-length if there are none
*/
@SuppressWarnings("rawtypes")
Class[]
getAllLoadedClasses();
/**
* Returns an array of all classes for which loader
is an initiating loader.
* If the supplied loader is null
, classes initiated by the bootstrap class
* loader are returned.
*
* @param loader the loader whose initiated class list will be returned
* @return an array containing all the classes for which loader is an initiating loader,
* zero-length if there are none
*/
@SuppressWarnings("rawtypes")
Class[]
getInitiatedClasses(ClassLoader loader);
/**
* Returns an implementation-specific approximation of the amount of storage consumed by
* the specified object. The result may include some or all of the object's overhead,
* and thus is useful for comparison within an implementation but not between implementations.
*
* The estimate may change during a single invocation of the JVM.
*
* @param objectToSize the object to size
* @return an implementation-specific approximation of the amount of storage consumed by the specified object
* @throws java.lang.NullPointerException if the supplied Object is null
.
*/
long
getObjectSize(Object objectToSize);
/**
* Specifies a JAR file with instrumentation classes to be defined by the
* bootstrap class loader.
*
*
When the virtual machine's built-in class loader, known as the "bootstrap
* class loader", unsuccessfully searches for a class, the entries in the {@link
* java.util.jar.JarFile JAR file} will be searched as well.
*
*
This method may be used multiple times to add multiple JAR files to be
* searched in the order that this method was invoked.
*
*
The agent should take care to ensure that the JAR does not contain any
* classes or resources other than those to be defined by the bootstrap
* class loader for the purpose of instrumentation.
* Failure to observe this warning could result in unexpected
* behavior that is difficult to diagnose. For example, suppose there is a
* loader L, and L's parent for delegation is the bootstrap class loader.
* Furthermore, a method in class C, a class defined by L, makes reference to
* a non-public accessor class C$1. If the JAR file contains a class C$1 then
* the delegation to the bootstrap class loader will cause C$1 to be defined
* by the bootstrap class loader. In this example an IllegalAccessError
* will be thrown that may cause the application to fail. One approach to
* avoiding these types of issues, is to use a unique package name for the
* instrumentation classes.
*
*
* The Java™ Virtual Machine Specification
* specifies that a subsequent attempt to resolve a symbolic
* reference that the Java virtual machine has previously unsuccessfully attempted
* to resolve always fails with the same error that was thrown as a result of the
* initial resolution attempt. Consequently, if the JAR file contains an entry
* that corresponds to a class for which the Java virtual machine has
* unsuccessfully attempted to resolve a reference, then subsequent attempts to
* resolve that reference will fail with the same error as the initial attempt.
*
* @param jarfile
* The JAR file to be searched when the bootstrap class loader
* unsuccessfully searches for a class.
*
* @throws NullPointerException
* If jarfile
is null
.
*
* @see #appendToSystemClassLoaderSearch
* @see java.lang.ClassLoader
* @see java.util.jar.JarFile
*
* @since 1.6
*/
void
appendToBootstrapClassLoaderSearch(JarFile jarfile);
/**
* Specifies a JAR file with instrumentation classes to be defined by the
* system class loader.
*
* When the system class loader for delegation (see
* {@link java.lang.ClassLoader#getSystemClassLoader getSystemClassLoader()})
* unsuccessfully searches for a class, the entries in the {@link
* java.util.jar.JarFile JarFile} will be searched as well.
*
*
This method may be used multiple times to add multiple JAR files to be
* searched in the order that this method was invoked.
*
*
The agent should take care to ensure that the JAR does not contain any
* classes or resources other than those to be defined by the system class
* loader for the purpose of instrumentation.
* Failure to observe this warning could result in unexpected
* behavior that is difficult to diagnose (see
* {@link #appendToBootstrapClassLoaderSearch
* appendToBootstrapClassLoaderSearch}).
*
*
The system class loader supports adding a JAR file to be searched if
* it implements a method named appendToClassPathForInstrumentation
* which takes a single parameter of type java.lang.String
. The
* method is not required to have public
access. The name of
* the JAR file is obtained by invoking the {@link java.util.zip.ZipFile#getName
* getName()} method on the jarfile
and this is provided as the
* parameter to the appendToClassPathForInstrumentation
method.
*
*
* The Java™ Virtual Machine Specification
* specifies that a subsequent attempt to resolve a symbolic
* reference that the Java virtual machine has previously unsuccessfully attempted
* to resolve always fails with the same error that was thrown as a result of the
* initial resolution attempt. Consequently, if the JAR file contains an entry
* that corresponds to a class for which the Java virtual machine has
* unsuccessfully attempted to resolve a reference, then subsequent attempts to
* resolve that reference will fail with the same error as the initial attempt.
*
*
This method does not change the value of java.class.path
* {@link java.lang.System#getProperties system property}.
*
* @param jarfile
* The JAR file to be searched when the system class loader
* unsuccessfully searches for a class.
*
* @throws UnsupportedOperationException
* If the system class loader does not support appending a
* a JAR file to be searched.
*
* @throws NullPointerException
* If jarfile
is null
.
*
* @see #appendToBootstrapClassLoaderSearch
* @see java.lang.ClassLoader#getSystemClassLoader
* @see java.util.jar.JarFile
* @since 1.6
*/
void
appendToSystemClassLoaderSearch(JarFile jarfile);
/**
* Returns whether the current JVM configuration supports
* {@linkplain #setNativeMethodPrefix(ClassFileTransformer,String)
* setting a native method prefix}.
* The ability to set a native method prefix is an optional
* capability of a JVM.
* Setting a native method prefix will only be supported if the
* Can-Set-Native-Method-Prefix
manifest attribute is set to
* true
in the agent JAR file (as described in the
* {@linkplain java.lang.instrument package specification}) and the JVM supports
* this capability.
* During a single instantiation of a single JVM, multiple
* calls to this method will always return the same answer.
* @return true if the current JVM configuration supports
* setting a native method prefix, false if not.
* @see #setNativeMethodPrefix
* @since 1.6
*/
boolean
isNativeMethodPrefixSupported();
/**
* This method modifies the failure handling of
* native method resolution by allowing retry
* with a prefix applied to the name.
* When used with the
* {@link java.lang.instrument.ClassFileTransformer ClassFileTransformer},
* it enables native methods to be
* instrumented.
*
* Since native methods cannot be directly instrumented
* (they have no bytecodes), they must be wrapped with
* a non-native method which can be instrumented.
* For example, if we had:
*
* native boolean foo(int x);
*
* We could transform the class file (with the
* ClassFileTransformer during the initial definition
* of the class) so that this becomes:
*
* boolean foo(int x) {
* ... record entry to foo ...
* return wrapped_foo(x);
* }
*
* native boolean wrapped_foo(int x);
*
* Where foo
becomes a wrapper for the actual native
* method with the appended prefix "wrapped_". Note that
* "wrapped_" would be a poor choice of prefix since it
* might conceivably form the name of an existing method
* thus something like "$$$MyAgentWrapped$$$_" would be
* better but would make these examples less readable.
*
* The wrapper will allow data to be collected on the native
* method call, but now the problem becomes linking up the
* wrapped method with the native implementation.
* That is, the method wrapped_foo
needs to be
* resolved to the native implementation of foo
,
* which might be:
*
* Java_somePackage_someClass_foo(JNIEnv* env, jint x)
*
* This function allows the prefix to be specified and the
* proper resolution to occur.
* Specifically, when the standard resolution fails, the
* resolution is retried taking the prefix into consideration.
* There are two ways that resolution occurs, explicit
* resolution with the JNI function RegisterNatives
* and the normal automatic resolution. For
* RegisterNatives
, the JVM will attempt this
* association:
*
{@code
* method(foo) -> nativeImplementation(foo)
* }
*
* When this fails, the resolution will be retried with
* the specified prefix prepended to the method name,
* yielding the correct resolution:
*
{@code
* method(wrapped_foo) -> nativeImplementation(foo)
* }
*
* For automatic resolution, the JVM will attempt:
*
{@code
* method(wrapped_foo) -> nativeImplementation(wrapped_foo)
* }
*
* When this fails, the resolution will be retried with
* the specified prefix deleted from the implementation name,
* yielding the correct resolution:
*
{@code
* method(wrapped_foo) -> nativeImplementation(foo)
* }
*
* Note that since the prefix is only used when standard
* resolution fails, native methods can be wrapped selectively.
*
* Since each ClassFileTransformer
* can do its own transformation of the bytecodes, more
* than one layer of wrappers may be applied. Thus each
* transformer needs its own prefix. Since transformations
* are applied in order, the prefixes, if applied, will
* be applied in the same order
* (see {@link #addTransformer(ClassFileTransformer,boolean) addTransformer}).
* Thus if three transformers applied
* wrappers, foo
might become
* $trans3_$trans2_$trans1_foo
. But if, say,
* the second transformer did not apply a wrapper to
* foo
it would be just
* $trans3_$trans1_foo
. To be able to
* efficiently determine the sequence of prefixes,
* an intermediate prefix is only applied if its non-native
* wrapper exists. Thus, in the last example, even though
* $trans1_foo
is not a native method, the
* $trans1_
prefix is applied since
* $trans1_foo
exists.
*
* @param transformer
* The ClassFileTransformer which wraps using this prefix.
* @param prefix
* The prefix to apply to wrapped native methods when
* retrying a failed native method resolution. If prefix
* is either null
or the empty string, then
* failed native method resolutions are not retried for
* this transformer.
* @throws java.lang.NullPointerException if passed a null
transformer.
* @throws java.lang.UnsupportedOperationException if the current configuration of
* the JVM does not allow setting a native method prefix
* ({@link #isNativeMethodPrefixSupported} is false).
* @throws java.lang.IllegalArgumentException if the transformer is not registered
* (see {@link #addTransformer(ClassFileTransformer,boolean) addTransformer}).
*
* @since 1.6
*/
void
setNativeMethodPrefix(ClassFileTransformer transformer, String prefix);
}