--- old/test/java/lang/instrument/ATransformerManagementTestCase.java Tue Aug 14 15:56:08 2012 +++ new/test/java/lang/instrument/ATransformerManagementTestCase.java Tue Aug 14 15:56:06 2012 @@ -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 Tue Aug 14 15:56:13 2012 +++ new/test/java/lang/instrument/DummyClassWithLVT.java Tue Aug 14 15:56:11 2012 @@ -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 Tue Aug 14 15:56:19 2012 +++ new/test/java/lang/instrument/VerifyLocalVariableTableOnRetransformTest.java Tue Aug 14 15:56:17 2012 @@ -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://javaweb.sfbay/javare/jdk/6.0/promoted/latest/doc/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 Tue Aug 14 15:56:22 2012 +++ new/test/java/lang/instrument/VerifyLocalVariableTableOnRetransformTest.sh Tue Aug 14 15:56:21 2012 @@ -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 Tue Aug 14 15:56:25 2012 +++ new/test/java/lang/instrument/retransformAgent.mf Tue Aug 14 15:56:24 2012 @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Premain-Class: InstrumentationHandoff +Can-Retransform-Classes: true