Wed, 21 Jan 2015 12:38:11 +0100
8068013: [TESTBUG] Aix support in hotspot jtreg tests
Reviewed-by: ctornqvi, fzhinkin, farvidsson
coleenp@7391 | 1 | /* |
coleenp@7391 | 2 | * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. |
coleenp@7391 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
coleenp@7391 | 4 | * |
coleenp@7391 | 5 | * This code is free software; you can redistribute it and/or modify it |
coleenp@7391 | 6 | * under the terms of the GNU General Public License version 2 only, as |
coleenp@7391 | 7 | * published by the Free Software Foundation. |
coleenp@7391 | 8 | * |
coleenp@7391 | 9 | * This code is distributed in the hope that it will be useful, but WITHOUT |
coleenp@7391 | 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
coleenp@7391 | 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
coleenp@7391 | 12 | * version 2 for more details (a copy is included in the LICENSE file that |
coleenp@7391 | 13 | * accompanied this code). |
coleenp@7391 | 14 | * |
coleenp@7391 | 15 | * You should have received a copy of the GNU General Public License version |
coleenp@7391 | 16 | * 2 along with this work; if not, write to the Free Software Foundation, |
coleenp@7391 | 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
coleenp@7391 | 18 | * |
coleenp@7391 | 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
coleenp@7391 | 20 | * or visit www.oracle.com if you need additional information or have any |
coleenp@7391 | 21 | * questions. |
coleenp@7391 | 22 | */ |
coleenp@7391 | 23 | |
coleenp@7391 | 24 | /** |
coleenp@7391 | 25 | * @test |
coleenp@7391 | 26 | * @bug 8042235 |
coleenp@7391 | 27 | * @summary redefining method used by multiple MethodHandles crashes VM |
coleenp@7391 | 28 | * @compile -XDignore.symbol.file RedefineMethodUsedByMultipleMethodHandles.java |
coleenp@7391 | 29 | * @run main RedefineMethodUsedByMultipleMethodHandles |
coleenp@7391 | 30 | */ |
coleenp@7391 | 31 | |
coleenp@7391 | 32 | import java.io.*; |
coleenp@7391 | 33 | import java.lang.instrument.*; |
coleenp@7391 | 34 | import java.lang.invoke.*; |
coleenp@7391 | 35 | import java.lang.invoke.MethodHandles.Lookup; |
coleenp@7391 | 36 | import java.lang.management.*; |
coleenp@7391 | 37 | import java.lang.reflect.*; |
coleenp@7391 | 38 | import java.nio.file.*; |
coleenp@7391 | 39 | import java.security.*; |
coleenp@7391 | 40 | import java.util.jar.*; |
coleenp@7391 | 41 | |
coleenp@7391 | 42 | import javax.tools.*; |
coleenp@7391 | 43 | |
coleenp@7391 | 44 | import jdk.internal.org.objectweb.asm.*; |
coleenp@7391 | 45 | |
coleenp@7391 | 46 | public class RedefineMethodUsedByMultipleMethodHandles { |
coleenp@7391 | 47 | |
coleenp@7391 | 48 | static class Foo { |
coleenp@7391 | 49 | public static Object getName() { |
coleenp@7391 | 50 | return "foo"; |
coleenp@7391 | 51 | } |
coleenp@7391 | 52 | } |
coleenp@7391 | 53 | |
coleenp@7391 | 54 | public static void main(String[] args) throws Throwable { |
coleenp@7391 | 55 | |
coleenp@7391 | 56 | Lookup lookup = MethodHandles.lookup(); |
coleenp@7391 | 57 | Method fooMethod = Foo.class.getDeclaredMethod("getName"); |
coleenp@7391 | 58 | |
coleenp@7391 | 59 | // fooMH2 displaces fooMH1 from the MemberNamesTable |
coleenp@7391 | 60 | MethodHandle fooMH1 = lookup.unreflect(fooMethod); |
coleenp@7391 | 61 | MethodHandle fooMH2 = lookup.unreflect(fooMethod); |
coleenp@7391 | 62 | |
coleenp@7391 | 63 | System.out.println("fooMH1.invoke = " + fooMH1.invokeExact()); |
coleenp@7391 | 64 | System.out.println("fooMH2.invoke = " + fooMH2.invokeExact()); |
coleenp@7391 | 65 | |
coleenp@7391 | 66 | // Redefining Foo.getName() causes vmtarget to be updated |
coleenp@7391 | 67 | // in fooMH2 but not fooMH1 |
coleenp@7391 | 68 | redefineFoo(); |
coleenp@7391 | 69 | |
coleenp@7391 | 70 | // Full GC causes fooMH1.vmtarget to be deallocated |
coleenp@7391 | 71 | System.gc(); |
coleenp@7391 | 72 | |
coleenp@7391 | 73 | // Calling fooMH1.vmtarget crashes the VM |
coleenp@7391 | 74 | System.out.println("fooMH1.invoke = " + fooMH1.invokeExact()); |
coleenp@7391 | 75 | } |
coleenp@7391 | 76 | |
coleenp@7391 | 77 | /** |
coleenp@7391 | 78 | * Adds the class file bytes for {@code c} to {@code jar}. |
coleenp@7391 | 79 | */ |
coleenp@7391 | 80 | static void add(JarOutputStream jar, Class<?> c) throws IOException { |
coleenp@7391 | 81 | String classAsPath = c.getName().replace('.', '/') + ".class"; |
coleenp@7391 | 82 | jar.putNextEntry(new JarEntry(classAsPath)); |
coleenp@7391 | 83 | InputStream stream = c.getClassLoader().getResourceAsStream(classAsPath); |
coleenp@7391 | 84 | |
coleenp@7391 | 85 | int b; |
coleenp@7391 | 86 | while ((b = stream.read()) != -1) { |
coleenp@7391 | 87 | jar.write(b); |
coleenp@7391 | 88 | } |
coleenp@7391 | 89 | } |
coleenp@7391 | 90 | |
coleenp@7391 | 91 | static void redefineFoo() throws Exception { |
coleenp@7391 | 92 | Manifest manifest = new Manifest(); |
coleenp@7391 | 93 | manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0"); |
coleenp@7391 | 94 | Attributes mainAttrs = manifest.getMainAttributes(); |
coleenp@7391 | 95 | mainAttrs.putValue("Agent-Class", FooAgent.class.getName()); |
coleenp@7391 | 96 | mainAttrs.putValue("Can-Redefine-Classes", "true"); |
coleenp@7391 | 97 | mainAttrs.putValue("Can-Retransform-Classes", "true"); |
coleenp@7391 | 98 | |
coleenp@7391 | 99 | Path jar = Files.createTempFile("myagent", ".jar"); |
coleenp@7391 | 100 | try { |
coleenp@7391 | 101 | JarOutputStream jarStream = new JarOutputStream(new FileOutputStream(jar.toFile()), manifest); |
coleenp@7391 | 102 | add(jarStream, FooAgent.class); |
coleenp@7391 | 103 | add(jarStream, FooTransformer.class); |
coleenp@7391 | 104 | jarStream.close(); |
coleenp@7391 | 105 | runAgent(jar); |
coleenp@7391 | 106 | } finally { |
coleenp@7391 | 107 | Files.deleteIfExists(jar); |
coleenp@7391 | 108 | } |
coleenp@7391 | 109 | } |
coleenp@7391 | 110 | |
coleenp@7391 | 111 | public static void runAgent(Path agent) throws Exception { |
coleenp@7391 | 112 | String vmName = ManagementFactory.getRuntimeMXBean().getName(); |
coleenp@7391 | 113 | int p = vmName.indexOf('@'); |
coleenp@7391 | 114 | assert p != -1 : "VM name not in <pid>@<host> format: " + vmName; |
coleenp@7391 | 115 | String pid = vmName.substring(0, p); |
coleenp@7391 | 116 | ClassLoader cl = ToolProvider.getSystemToolClassLoader(); |
coleenp@7391 | 117 | Class<?> c = Class.forName("com.sun.tools.attach.VirtualMachine", true, cl); |
coleenp@7391 | 118 | Method attach = c.getDeclaredMethod("attach", String.class); |
coleenp@7391 | 119 | Method loadAgent = c.getDeclaredMethod("loadAgent", String.class); |
coleenp@7391 | 120 | Method detach = c.getDeclaredMethod("detach"); |
coleenp@7391 | 121 | Object vm = attach.invoke(null, pid); |
coleenp@7391 | 122 | loadAgent.invoke(vm, agent.toString()); |
coleenp@7391 | 123 | detach.invoke(vm); |
coleenp@7391 | 124 | } |
coleenp@7391 | 125 | |
coleenp@7391 | 126 | public static class FooAgent { |
coleenp@7391 | 127 | |
coleenp@7391 | 128 | public static void agentmain(@SuppressWarnings("unused") String args, Instrumentation inst) throws Exception { |
coleenp@7391 | 129 | assert inst.isRedefineClassesSupported(); |
coleenp@7391 | 130 | assert inst.isRetransformClassesSupported(); |
coleenp@7391 | 131 | inst.addTransformer(new FooTransformer(), true); |
coleenp@7391 | 132 | Class<?>[] classes = inst.getAllLoadedClasses(); |
coleenp@7391 | 133 | for (int i = 0; i < classes.length; i++) { |
coleenp@7391 | 134 | Class<?> c = classes[i]; |
coleenp@7391 | 135 | if (c == Foo.class) { |
coleenp@7391 | 136 | inst.retransformClasses(new Class[]{c}); |
coleenp@7391 | 137 | } |
coleenp@7391 | 138 | } |
coleenp@7391 | 139 | } |
coleenp@7391 | 140 | } |
coleenp@7391 | 141 | |
coleenp@7391 | 142 | static class FooTransformer implements ClassFileTransformer { |
coleenp@7391 | 143 | |
coleenp@7391 | 144 | @Override |
coleenp@7391 | 145 | public byte[] transform(ClassLoader cl, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { |
coleenp@7391 | 146 | if (Foo.class.equals(classBeingRedefined)) { |
coleenp@7391 | 147 | System.out.println("redefining " + classBeingRedefined); |
coleenp@7391 | 148 | ClassReader cr = new ClassReader(classfileBuffer); |
coleenp@7391 | 149 | ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_FRAMES); |
coleenp@7391 | 150 | ClassVisitor adapter = new ClassVisitor(Opcodes.ASM5, cw) { |
coleenp@7391 | 151 | @Override |
coleenp@7391 | 152 | public MethodVisitor visitMethod(int access, String base, String desc, String signature, String[] exceptions) { |
coleenp@7391 | 153 | MethodVisitor mv = cv.visitMethod(access, base, desc, signature, exceptions); |
coleenp@7391 | 154 | if (mv != null) { |
coleenp@7391 | 155 | mv = new MethodVisitor(Opcodes.ASM5, mv) { |
coleenp@7391 | 156 | @Override |
coleenp@7391 | 157 | public void visitLdcInsn(Object cst) { |
coleenp@7391 | 158 | System.out.println("replacing \"" + cst + "\" with \"bar\""); |
coleenp@7391 | 159 | mv.visitLdcInsn("bar"); |
coleenp@7391 | 160 | } |
coleenp@7391 | 161 | }; |
coleenp@7391 | 162 | } |
coleenp@7391 | 163 | return mv; |
coleenp@7391 | 164 | } |
coleenp@7391 | 165 | }; |
coleenp@7391 | 166 | |
coleenp@7391 | 167 | cr.accept(adapter, ClassReader.SKIP_FRAMES); |
coleenp@7391 | 168 | cw.visitEnd(); |
coleenp@7391 | 169 | return cw.toByteArray(); |
coleenp@7391 | 170 | } |
coleenp@7391 | 171 | return classfileBuffer; |
coleenp@7391 | 172 | } |
coleenp@7391 | 173 | } |
coleenp@7391 | 174 | } |