CallSiteDepContextTest.java revision 10420:c558850fac57
1/* 2 * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24/** 25 * @test 26 * @bug 8057967 27 * @modules java.base/jdk.internal.org.objectweb.asm 28 * @library patches 29 * @build java.base/java.lang.invoke.MethodHandleHelper 30 * @run main/bootclasspath -Xbatch -XX:+IgnoreUnrecognizedVMOptions -Xlog:classunload 31 * -XX:+PrintCompilation -XX:+TraceDependencies -XX:+TraceReferenceGC 32 * -verbose:gc compiler.jsr292.CallSiteDepContextTest 33 */ 34 35package compiler.jsr292; 36 37import java.lang.invoke.CallSite; 38import java.lang.invoke.MethodHandle; 39import java.lang.invoke.MethodHandleHelper; 40import java.lang.invoke.MethodHandles; 41import java.lang.invoke.MethodType; 42import java.lang.invoke.MutableCallSite; 43import java.lang.ref.PhantomReference; 44import java.lang.ref.Reference; 45import java.lang.ref.ReferenceQueue; 46import java.lang.reflect.Field; 47 48import jdk.internal.org.objectweb.asm.*; 49import sun.misc.Unsafe; 50 51import static jdk.internal.org.objectweb.asm.Opcodes.*; 52 53public class CallSiteDepContextTest { 54 static final Unsafe UNSAFE = Unsafe.getUnsafe(); 55 static final MethodHandles.Lookup LOOKUP = MethodHandleHelper.IMPL_LOOKUP; 56 static final String CLASS_NAME = "java/lang/invoke/Test"; 57 static final String METHOD_NAME = "m"; 58 static final MethodType TYPE = MethodType.methodType(int.class); 59 60 static MutableCallSite mcs; 61 static MethodHandle bsmMH; 62 63 static { 64 try { 65 bsmMH = LOOKUP.findStatic( 66 CallSiteDepContextTest.class, "bootstrap", 67 MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class)); 68 } catch(Throwable e) { 69 throw new InternalError(e); 70 } 71 } 72 73 public static CallSite bootstrap(MethodHandles.Lookup caller, 74 String invokedName, 75 MethodType invokedType) { 76 return mcs; 77 } 78 79 static class T { 80 static int f1() { return 1; } 81 static int f2() { return 2; } 82 } 83 84 static byte[] getClassFile(String suffix) { 85 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); 86 MethodVisitor mv; 87 cw.visit(52, ACC_PUBLIC | ACC_SUPER, CLASS_NAME + suffix, null, "java/lang/Object", null); 88 { 89 mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, METHOD_NAME, TYPE.toMethodDescriptorString(), null, null); 90 mv.visitCode(); 91 Handle bsm = new Handle(H_INVOKESTATIC, 92 CallSiteDepContextTest.class.getName().replace(".", "/"), 93 "bootstrap", 94 bsmMH.type().toMethodDescriptorString()); 95 mv.visitInvokeDynamicInsn("methodName", TYPE.toMethodDescriptorString(), bsm); 96 mv.visitInsn(IRETURN); 97 mv.visitMaxs(0, 0); 98 mv.visitEnd(); 99 } 100 cw.visitEnd(); 101 return cw.toByteArray(); 102 } 103 104 private static void execute(int expected, MethodHandle... mhs) throws Throwable { 105 for (int i = 0; i < 20_000; i++) { 106 for (MethodHandle mh : mhs) { 107 int r = (int) mh.invokeExact(); 108 if (r != expected) { 109 throw new Error(r + " != " + expected); 110 } 111 } 112 } 113 } 114 115 public static void testHiddenDepField() { 116 try { 117 Field f = MethodHandleHelper.MHN_CALL_SITE_CONTEXT_CLASS.getDeclaredField("vmdependencies"); 118 throw new AssertionError("Context.dependencies field should be hidden"); 119 } catch(NoSuchFieldException e) { /* expected */ } 120 } 121 122 public static void testSharedCallSite() throws Throwable { 123 Class<?> cls1 = UNSAFE.defineAnonymousClass(Object.class, getClassFile("CS_1"), null); 124 Class<?> cls2 = UNSAFE.defineAnonymousClass(Object.class, getClassFile("CS_2"), null); 125 126 MethodHandle[] mhs = new MethodHandle[] { 127 LOOKUP.findStatic(cls1, METHOD_NAME, TYPE), 128 LOOKUP.findStatic(cls2, METHOD_NAME, TYPE) 129 }; 130 131 mcs = new MutableCallSite(LOOKUP.findStatic(T.class, "f1", TYPE)); 132 execute(1, mhs); 133 mcs.setTarget(LOOKUP.findStatic(T.class, "f2", TYPE)); 134 execute(2, mhs); 135 } 136 137 public static void testNonBoundCallSite() throws Throwable { 138 mcs = new MutableCallSite(LOOKUP.findStatic(T.class, "f1", TYPE)); 139 140 // mcs.context == null 141 MethodHandle mh = mcs.dynamicInvoker(); 142 execute(1, mh); 143 144 // mcs.context == cls1 145 Class<?> cls1 = UNSAFE.defineAnonymousClass(Object.class, getClassFile("NonBound_1"), null); 146 MethodHandle mh1 = LOOKUP.findStatic(cls1, METHOD_NAME, TYPE); 147 148 execute(1, mh1); 149 150 mcs.setTarget(LOOKUP.findStatic(T.class, "f2", TYPE)); 151 152 execute(2, mh, mh1); 153 } 154 155 static ReferenceQueue rq = new ReferenceQueue(); 156 static PhantomReference ref; 157 158 public static void testGC(boolean clear, boolean precompile) throws Throwable { 159 String id = "_" + clear + "_" + precompile; 160 161 mcs = new MutableCallSite(LOOKUP.findStatic(T.class, "f1", TYPE)); 162 163 Class<?>[] cls = new Class[] { 164 UNSAFE.defineAnonymousClass(Object.class, getClassFile("GC_1" + id), null), 165 UNSAFE.defineAnonymousClass(Object.class, getClassFile("GC_2" + id), null), 166 }; 167 168 MethodHandle[] mhs = new MethodHandle[] { 169 LOOKUP.findStatic(cls[0], METHOD_NAME, TYPE), 170 LOOKUP.findStatic(cls[1], METHOD_NAME, TYPE), 171 }; 172 173 // mcs.context == cls[0] 174 int r = (int) mhs[0].invokeExact(); 175 176 execute(1, mhs); 177 178 ref = new PhantomReference<>(cls[0], rq); 179 cls[0] = UNSAFE.defineAnonymousClass(Object.class, getClassFile("GC_3" + id), null); 180 mhs[0] = LOOKUP.findStatic(cls[0], METHOD_NAME, TYPE); 181 182 do { 183 System.gc(); 184 try { 185 Reference ref1 = rq.remove(100); 186 if (ref1 == ref) { 187 break; 188 } 189 } catch(InterruptedException e) { /* ignore */ } 190 } while (true); 191 192 if (clear) { 193 ref.clear(); 194 System.gc(); // Ensure that the stale context is unloaded 195 } 196 if (precompile) { 197 execute(1, mhs); 198 } 199 mcs.setTarget(LOOKUP.findStatic(T.class, "f2", TYPE)); 200 execute(2, mhs); 201 } 202 203 public static void main(String[] args) throws Throwable { 204 testHiddenDepField(); 205 testSharedCallSite(); 206 testNonBoundCallSite(); 207 testGC(false, false); 208 testGC(false, true); 209 testGC( true, false); 210 testGC( true, true); 211 System.out.println("TEST PASSED"); 212 } 213} 214 215