Path: blob/master/src/java.instrument/share/classes/sun/instrument/TransformerManager.java
41153 views
/*1* Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.instrument;2627import java.lang.instrument.Instrumentation;28import java.lang.instrument.ClassFileTransformer;29import java.security.ProtectionDomain;3031/*32* Copyright 2003 Wily Technology, Inc.33*/3435/**36* Support class for the InstrumentationImpl. Manages the list of registered transformers.37* Keeps everything in the right order, deals with sync of the list,38* and actually does the calling of the transformers.39*/40public class TransformerManager41{42private class TransformerInfo {43final ClassFileTransformer mTransformer;44String mPrefix;4546TransformerInfo(ClassFileTransformer transformer) {47mTransformer = transformer;48mPrefix = null;49}5051ClassFileTransformer transformer() {52return mTransformer;53}5455String getPrefix() {56return mPrefix;57}5859void setPrefix(String prefix) {60mPrefix = prefix;61}62}6364/**65* a given instance of this list is treated as immutable to simplify sync;66* we pay copying overhead whenever the list is changed rather than every time67* the list is referenced.68* The array is kept in the order the transformers are added via addTransformer69* (first added is 0, last added is length-1)70* Use an array, not a List or other Collection. This keeps the set of classes71* used by this code to a minimum. We want as few dependencies as possible in this72* code, since it is used inside the class definition system. Any class referenced here73* cannot be transformed by Java code.74*/75private TransformerInfo[] mTransformerList;7677/***78* Is this TransformerManager for transformers capable of retransformation?79*/80private boolean mIsRetransformable;8182TransformerManager(boolean isRetransformable) {83mTransformerList = new TransformerInfo[0];84mIsRetransformable = isRetransformable;85}8687boolean isRetransformable() {88return mIsRetransformable;89}9091public synchronized void92addTransformer( ClassFileTransformer transformer) {93TransformerInfo[] oldList = mTransformerList;94TransformerInfo[] newList = new TransformerInfo[oldList.length + 1];95System.arraycopy( oldList,960,97newList,980,99oldList.length);100newList[oldList.length] = new TransformerInfo(transformer);101mTransformerList = newList;102}103104public synchronized boolean105removeTransformer(ClassFileTransformer transformer) {106boolean found = false;107TransformerInfo[] oldList = mTransformerList;108int oldLength = oldList.length;109int newLength = oldLength - 1;110111// look for it in the list, starting at the last added, and remember112// where it was if we found it113int matchingIndex = 0;114for ( int x = oldLength - 1; x >= 0; x-- ) {115if ( oldList[x].transformer() == transformer ) {116found = true;117matchingIndex = x;118break;119}120}121122// make a copy of the array without the matching element123if ( found ) {124TransformerInfo[] newList = new TransformerInfo[newLength];125126// copy up to but not including the match127if ( matchingIndex > 0 ) {128System.arraycopy( oldList,1290,130newList,1310,132matchingIndex);133}134135// if there is anything after the match, copy it as well136if ( matchingIndex < (newLength) ) {137System.arraycopy( oldList,138matchingIndex + 1,139newList,140matchingIndex,141(newLength) - matchingIndex);142}143mTransformerList = newList;144}145return found;146}147148synchronized boolean149includesTransformer(ClassFileTransformer transformer) {150for (TransformerInfo info : mTransformerList) {151if ( info.transformer() == transformer ) {152return true;153}154}155return false;156}157158// This function doesn't actually snapshot anything, but should be159// used to set a local variable, which will snapshot the transformer160// list because of the copying semantics of mTransformerList (see161// the comment for mTransformerList).162private TransformerInfo[]163getSnapshotTransformerList() {164return mTransformerList;165}166167public byte[]168transform( Module module,169ClassLoader loader,170String classname,171Class<?> classBeingRedefined,172ProtectionDomain protectionDomain,173byte[] classfileBuffer) {174boolean someoneTouchedTheBytecode = false;175176TransformerInfo[] transformerList = getSnapshotTransformerList();177178byte[] bufferToUse = classfileBuffer;179180// order matters, gotta run 'em in the order they were added181for ( int x = 0; x < transformerList.length; x++ ) {182TransformerInfo transformerInfo = transformerList[x];183ClassFileTransformer transformer = transformerInfo.transformer();184byte[] transformedBytes = null;185186try {187transformedBytes = transformer.transform( module,188loader,189classname,190classBeingRedefined,191protectionDomain,192bufferToUse);193}194catch (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? FIXME197}198199if ( transformedBytes != null ) {200someoneTouchedTheBytecode = true;201bufferToUse = transformedBytes;202}203}204205// if someone modified it, return the modified buffer.206// otherwise return null to mean "no transforms occurred"207byte [] result;208if ( someoneTouchedTheBytecode ) {209result = bufferToUse;210}211else {212result = null;213}214215return result;216}217218219int220getTransformerCount() {221TransformerInfo[] transformerList = getSnapshotTransformerList();222return transformerList.length;223}224225boolean226setNativeMethodPrefix(ClassFileTransformer transformer, String prefix) {227TransformerInfo[] transformerList = getSnapshotTransformerList();228229for ( int x = 0; x < transformerList.length; x++ ) {230TransformerInfo transformerInfo = transformerList[x];231ClassFileTransformer aTransformer = transformerInfo.transformer();232233if ( aTransformer == transformer ) {234transformerInfo.setPrefix(prefix);235return true;236}237}238return false;239}240241242String[]243getNativeMethodPrefixes() {244TransformerInfo[] transformerList = getSnapshotTransformerList();245String[] prefixes = new String[transformerList.length];246247for ( int x = 0; x < transformerList.length; x++ ) {248TransformerInfo transformerInfo = transformerList[x];249prefixes[x] = transformerInfo.getPrefix();250}251return prefixes;252}253}254255256