jdk/src/share/classes/sun/instrument/TransformerManager.java
changeset 2 90ce3da70b43
child 5506 202f599c92aa
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/instrument/TransformerManager.java	Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,253 @@
+/*
+ * Copyright 2003-2005 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.instrument;
+
+
+import java.lang.instrument.Instrumentation;
+import java.lang.instrument.ClassFileTransformer;
+import java.security.ProtectionDomain;
+
+/*
+ * Copyright 2003 Wily Technology, Inc.
+ */
+
+/**
+ * Support class for the InstrumentationImpl. Manages the list of registered transformers.
+ * Keeps everything in the right order, deals with sync of the list,
+ * and actually does the calling of the transformers.
+ */
+public class TransformerManager
+{
+    private class TransformerInfo {
+        final ClassFileTransformer  mTransformer;
+        String                      mPrefix;
+
+        TransformerInfo(ClassFileTransformer transformer) {
+            mTransformer = transformer;
+            mPrefix = null;
+        }
+
+        ClassFileTransformer transformer() {
+            return  mTransformer;
+        }
+
+        String getPrefix() {
+            return mPrefix;
+        }
+
+        void setPrefix(String prefix) {
+            mPrefix = prefix;
+        }
+    }
+
+    /**
+     * a given instance of this list is treated as immutable to simplify sync;
+     * we pay copying overhead whenever the list is changed rather than every time
+     * the list is referenced.
+     * The array is kept in the order the transformers are added via addTransformer
+     * (first added is 0, last added is length-1)
+     * Use an array, not a List or other Collection. This keeps the set of classes
+     * used by this code to a minimum. We want as few dependencies as possible in this
+     * code, since it is used inside the class definition system. Any class referenced here
+     * cannot be transformed by Java code.
+     */
+    private TransformerInfo[]  mTransformerList;
+
+    /***
+     * Is this TransformerManager for transformers capable of retransformation?
+     */
+    private boolean            mIsRetransformable;
+
+    TransformerManager(boolean isRetransformable) {
+        mTransformerList    = new TransformerInfo[0];
+        mIsRetransformable  = isRetransformable;
+    }
+
+    boolean isRetransformable() {
+        return mIsRetransformable;
+    }
+
+    public synchronized void
+    addTransformer( ClassFileTransformer    transformer) {
+        TransformerInfo[] oldList = mTransformerList;
+        TransformerInfo[] newList = new TransformerInfo[oldList.length + 1];
+        System.arraycopy(   oldList,
+                            0,
+                            newList,
+                            0,
+                            oldList.length);
+        newList[oldList.length] = new TransformerInfo(transformer);
+        mTransformerList = newList;
+    }
+
+    public synchronized boolean
+    removeTransformer(ClassFileTransformer  transformer) {
+        boolean                 found           = false;
+        TransformerInfo[]       oldList         = mTransformerList;
+        int                     oldLength       = oldList.length;
+        int                     newLength       = oldLength - 1;
+
+        // look for it in the list, starting at the last added, and remember
+        // where it was if we found it
+        int matchingIndex   = 0;
+        for ( int x = oldLength - 1; x >= 0; x-- ) {
+            if ( oldList[x].transformer() == transformer ) {
+                found           = true;
+                matchingIndex   = x;
+                break;
+            }
+        }
+
+        // make a copy of the array without the matching element
+        if ( found ) {
+            TransformerInfo[]  newList = new TransformerInfo[newLength];
+
+            // copy up to but not including the match
+            if ( matchingIndex > 0 ) {
+                System.arraycopy(   oldList,
+                                    0,
+                                    newList,
+                                    0,
+                                    matchingIndex);
+            }
+
+            // if there is anything after the match, copy it as well
+            if ( matchingIndex < (newLength) ) {
+                System.arraycopy(   oldList,
+                                    matchingIndex + 1,
+                                    newList,
+                                    matchingIndex,
+                                    (newLength) - matchingIndex);
+            }
+            mTransformerList = newList;
+        }
+        return found;
+    }
+
+    synchronized boolean
+    includesTransformer(ClassFileTransformer transformer) {
+        for (TransformerInfo info : mTransformerList) {
+            if ( info.transformer() == transformer ) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    // This function doesn't actually snapshot anything, but should be
+    // used to set a local variable, which will snapshot the transformer
+    // list because of the copying semantics of mTransformerList (see
+    // the comment for mTransformerList).
+    private TransformerInfo[]
+    getSnapshotTransformerList() {
+        return mTransformerList;
+    }
+
+    public byte[]
+    transform(  ClassLoader         loader,
+                String              classname,
+                Class               classBeingRedefined,
+                ProtectionDomain    protectionDomain,
+                byte[]              classfileBuffer) {
+        boolean someoneTouchedTheBytecode = false;
+
+        TransformerInfo[]  transformerList = getSnapshotTransformerList();
+
+        byte[]  bufferToUse = classfileBuffer;
+
+        // order matters, gotta run 'em in the order they were added
+        for ( int x = 0; x < transformerList.length; x++ ) {
+            TransformerInfo         transformerInfo = transformerList[x];
+            ClassFileTransformer    transformer = transformerInfo.transformer();
+            byte[]                  transformedBytes = null;
+
+            try {
+                transformedBytes = transformer.transform(   loader,
+                                                            classname,
+                                                            classBeingRedefined,
+                                                            protectionDomain,
+                                                            bufferToUse);
+            }
+            catch (Throwable t) {
+                // don't let any one transformer mess it up for the others.
+                // This is where we need to put some logging. What should go here? FIXME
+            }
+
+            if ( transformedBytes != null ) {
+                someoneTouchedTheBytecode = true;
+                bufferToUse = transformedBytes;
+            }
+        }
+
+        // if someone modified it, return the modified buffer.
+        // otherwise return null to mean "no transforms occurred"
+        byte [] result;
+        if ( someoneTouchedTheBytecode ) {
+            result = bufferToUse;
+        }
+        else {
+            result = null;
+        }
+
+        return result;
+    }
+
+
+    int
+    getTransformerCount() {
+        TransformerInfo[]  transformerList = getSnapshotTransformerList();
+        return transformerList.length;
+    }
+
+    boolean
+    setNativeMethodPrefix(ClassFileTransformer transformer, String prefix) {
+        TransformerInfo[]  transformerList = getSnapshotTransformerList();
+
+        for ( int x = 0; x < transformerList.length; x++ ) {
+            TransformerInfo         transformerInfo = transformerList[x];
+            ClassFileTransformer    aTransformer = transformerInfo.transformer();
+
+            if ( aTransformer == transformer ) {
+                transformerInfo.setPrefix(prefix);
+                return true;
+            }
+        }
+        return false;
+    }
+
+
+    String[]
+    getNativeMethodPrefixes() {
+        TransformerInfo[]  transformerList = getSnapshotTransformerList();
+        String[] prefixes                  = new String[transformerList.length];
+
+        for ( int x = 0; x < transformerList.length; x++ ) {
+            TransformerInfo         transformerInfo = transformerList[x];
+            prefixes[x] = transformerInfo.getPrefix();
+        }
+        return prefixes;
+    }
+}