7191322: add test for 7064927 to java.lang.instrument
authordcubed
Fri, 17 Aug 2012 12:51:23 -0700
changeset 13576 850377563282
parent 13575 017f49f1f3cb
child 13577 afcb909fea86
7191322: add test for 7064927 to java.lang.instrument Summary: Add support for canRetransform attribute to the test manager. Add test for 7064927. Reviewed-by: dsamersoff, sspitsyn, ohair
jdk/test/java/lang/instrument/ATransformerManagementTestCase.java
jdk/test/java/lang/instrument/DummyClassWithLVT.java
jdk/test/java/lang/instrument/VerifyLocalVariableTableOnRetransformTest.java
jdk/test/java/lang/instrument/VerifyLocalVariableTableOnRetransformTest.sh
jdk/test/java/lang/instrument/retransformAgent.mf
--- a/jdk/test/java/lang/instrument/ATransformerManagementTestCase.java	Fri Aug 17 14:32:50 2012 -0400
+++ b/jdk/test/java/lang/instrument/ATransformerManagementTestCase.java	Fri Aug 17 12:51:23 2012 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2012, 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
@@ -99,12 +99,28 @@
         Instrumentation         manager,
         ClassFileTransformer    transformer)
     {
+        addTransformerToManager(manager, transformer, false);
+    }
+
+    /**
+     * Method addTransformerToManager.
+     * @param manager
+     * @param transformer
+     * @param canRetransform
+     */
+    protected void
+    addTransformerToManager(
+        Instrumentation         manager,
+        ClassFileTransformer    transformer,
+        boolean                 canRetransform)
+    {
         if (transformer != null)
         {
             fTransformers.add(transformer);
         }
-        manager.addTransformer(transformer);
-        verbosePrint("Added transformer " + transformer);
+        manager.addTransformer(transformer, canRetransform);
+        verbosePrint("Added transformer " + transformer
+            + " with canRetransform=" + canRetransform);
     }
 
     /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/instrument/DummyClassWithLVT.java	Fri Aug 17 12:51:23 2012 -0700
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2012, 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.
+ *
+ * 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.
+ */
+
+public class DummyClassWithLVT
+{
+    public static void main(String[] args) {
+        boolean b  = true;
+        byte    by = 0x42;
+        char    c  = 'X';
+        double  d  = 1.1;
+        float   f  = (float) 1.2;
+        int     i  = 42;
+        long    l  = 0xCAFEBABE;
+        short   s  = 88;
+
+        System.out.println("b=" + b);
+        System.out.println("by=" + by);
+        System.out.println("c=" + c);
+        System.out.println("d=" + d);
+        System.out.println("f=" + f);
+        System.out.println("i=" + i);
+        System.out.println("l=" + l);
+        System.out.println("s=" + s);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/instrument/VerifyLocalVariableTableOnRetransformTest.java	Fri Aug 17 12:51:23 2012 -0700
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2012, 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.
+ *
+ * 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.
+ */
+
+import java.io.*;
+import java.lang.instrument.Instrumentation;
+import java.lang.instrument.ClassFileTransformer;
+import java.net.*;
+import java.security.ProtectionDomain;
+
+public class
+VerifyLocalVariableTableOnRetransformTest
+    extends ATransformerManagementTestCase
+{
+    private byte[]  fTargetClassBytes;
+    private boolean fTargetClassMatches;
+    private String  fTargetClassName = "DummyClassWithLVT";
+    private boolean fTargetClassSeen;
+
+    /**
+     * Constructor for VerifyLocalVariableTableOnRetransformTest.
+     * @param name
+     */
+    public VerifyLocalVariableTableOnRetransformTest(String name)
+    {
+        super(name);
+
+        String resourceName = fTargetClassName + ".class";
+        File f = new File(System.getProperty("test.classes", "."), resourceName);
+        System.out.println("Reading test class from " + f);
+        try
+        {
+            InputStream redefineStream = new FileInputStream(f);
+            fTargetClassBytes = NamedBuffer.loadBufferFromStream(redefineStream);
+            System.out.println("Read " + fTargetClassBytes.length + " bytes.");
+        }
+        catch (IOException e)
+        {
+            fail("Could not load the class: "+resourceName);
+        }
+    }
+
+    public static void
+    main (String[] args)
+        throws Throwable {
+        ATestCaseScaffold   test = new VerifyLocalVariableTableOnRetransformTest(args[0]);
+        test.runTest();
+    }
+
+    protected final void
+    doRunTest()
+        throws Throwable {
+        verifyClassFileBuffer();
+    }
+
+    public void
+    verifyClassFileBuffer()
+        throws  Throwable
+    {
+        beVerbose();
+
+        // With this call here, we will see the target class twice:
+        // first when it gets loaded and second when it gets retransformed.
+        addTransformerToManager(fInst, new MyObserver(), true);
+
+        ClassLoader loader = getClass().getClassLoader();
+
+        Class target = loader.loadClass(fTargetClassName);
+        assertEquals(fTargetClassName, target.getName());
+
+        // make an instance to prove the class was really loaded
+        Object testInstance = target.newInstance();
+
+        // With this call here, we will see the target class once:
+        // when it gets retransformed.
+        //addTransformerToManager(fInst, new MyObserver(), true);
+
+        assertTrue(fTargetClassName + " was not seen by transform()",
+            fTargetClassSeen);
+
+        // The HotSpot VM hands us class file bytes at initial class
+        // load time that match the .class file contents. However,
+        // according to the following spec that is not required:
+        // http://docs.oracle.com/javase/7/docs/api/java/lang/instrument/Instrumentation.html#retransformClasses(java.lang.Class...)
+        // This test exists to catch any unintentional change in
+        // behavior by the HotSpot VM. If this behavior is intentionally
+        // changed in the future, then this test will need to be
+        // updated.
+        assertTrue(fTargetClassName + " did not match .class file",
+            fTargetClassMatches);
+
+        fTargetClassSeen = false;
+        fTargetClassMatches = false;
+
+        fInst.retransformClasses(target);
+
+        assertTrue(fTargetClassName + " was not seen by transform()",
+            fTargetClassSeen);
+
+        // The HotSpot VM doesn't currently preserve the LocalVariable
+        // Table (LVT) attribute so the class file bytes seen by the
+        // retransformClasses() call will not match the class file bytes
+        // seen at initial class load time.
+        assertTrue(fTargetClassName + " did not match .class file",
+            fTargetClassMatches);
+    }
+
+    public class MyObserver implements ClassFileTransformer {
+        public MyObserver() {
+        }
+
+        public String toString() {
+            return MyObserver.this.getClass().getName();
+        }
+
+        private void saveMismatchedBytes(byte[] classfileBuffer) {
+            try {
+                FileOutputStream fos = null;
+                // This file will get created in the test execution
+                // directory so there is no conflict with the file
+                // in the test classes directory.
+                String resourceName = fTargetClassName + ".class";
+                fos = new FileOutputStream(resourceName);
+                fos.write(classfileBuffer);
+                fos.close();
+            } catch (IOException ex) {
+            }
+        }
+
+        public byte[]
+        transform(
+            ClassLoader loader,
+            String className,
+            Class<?> classBeingRedefined,
+            ProtectionDomain    protectionDomain,
+            byte[] classfileBuffer) {
+
+            System.out.println(this + ".transform() sees '" + className
+                + "' of " + classfileBuffer.length + " bytes.");
+            if (className.equals(fTargetClassName)) {
+                fTargetClassSeen = true;
+
+                if (classfileBuffer.length != fTargetClassBytes.length) {
+                    System.out.println("Warning: " + fTargetClassName
+                        + " lengths do not match.");
+                    fTargetClassMatches = false;
+                    saveMismatchedBytes(classfileBuffer);
+                    return null;
+                } else {
+                    System.out.println("Info: " + fTargetClassName
+                        + " lengths match.");
+                }
+
+                for (int i = 0; i < classfileBuffer.length; i++) {
+                    if (classfileBuffer[i] != fTargetClassBytes[i]) {
+                        System.out.println("Warning: " + fTargetClassName
+                            + "[" + i + "]: '" + classfileBuffer[i]
+                            + "' != '" + fTargetClassBytes[i] + "'");
+                        fTargetClassMatches = false;
+                        saveMismatchedBytes(classfileBuffer);
+                        return null;
+                    }
+                }
+
+                fTargetClassMatches = true;
+                System.out.println("Info: verified '" + fTargetClassName
+                    + ".class' matches 'classfileBuffer'.");
+            }
+
+            return null;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/instrument/VerifyLocalVariableTableOnRetransformTest.sh	Fri Aug 17 12:51:23 2012 -0700
@@ -0,0 +1,83 @@
+#
+# Copyright (c) 2012, 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.
+#
+# 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.
+#
+
+#
+
+# @test
+# @bug 7064927
+# @summary Verify LocalVariableTable (LVT) exists when passed to
+# transform() on a retransform operation.
+# @author Daniel D. Daugherty
+#
+# @run build VerifyLocalVariableTableOnRetransformTest
+# @run compile -g DummyClassWithLVT.java
+# @run shell MakeJAR.sh retransformAgent
+# @run shell VerifyLocalVariableTableOnRetransformTest.sh
+
+
+if [ "${TESTJAVA}" = "" ]
+then
+  echo "TESTJAVA not set.  Test cannot execute.  Failed."
+  exit 1
+fi
+
+if [ "${TESTSRC}" = "" ]
+then
+  echo "TESTSRC not set.  Test cannot execute.  Failed."
+  exit 1
+fi
+
+if [ "${TESTCLASSES}" = "" ]
+then
+  echo "TESTCLASSES not set.  Test cannot execute.  Failed."
+  exit 1
+fi
+
+JAVA="${TESTJAVA}"/bin/java
+
+"${JAVA}" ${TESTVMOPTS} -Dtest.classes="${TESTCLASSES}" \
+    -javaagent:retransformAgent.jar \
+    -classpath "${TESTCLASSES}" \
+    VerifyLocalVariableTableOnRetransformTest \
+    VerifyLocalVariableTableOnRetransformTest \
+    > output.log 2>&1
+cat output.log
+
+MESG="did not match .class file"
+grep "$MESG" output.log
+result=$?
+if [ "$result" = 0 ]; then
+    echo "FAIL: found '$MESG' in the test output"
+
+    echo "INFO: 'javap -v' comparison between the .class files:"
+    ${JAVA}p -v -classpath "${TESTCLASSES}" DummyClassWithLVT > orig.javap
+    ${JAVA}p -v DummyClassWithLVT > mismatched.javap
+    diff orig.javap mismatched.javap
+
+    result=1
+else
+    echo "PASS: did NOT find '$MESG' in the test output"
+    result=0
+fi
+
+exit $result
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/instrument/retransformAgent.mf	Fri Aug 17 12:51:23 2012 -0700
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Premain-Class: InstrumentationHandoff
+Can-Retransform-Classes: true