Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/test/java/lang/invoke/PrivateInvokeTest.java
47216 views
/*1* Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/* @test24* @summary white-box testing of method handle sub-primitives25* @run junit test.java.lang.invoke.PrivateInvokeTest26*/2728package test.java.lang.invoke;2930import java.lang.invoke.*;31import static java.lang.invoke.MethodHandles.*;32import static java.lang.invoke.MethodType.*;33import java.lang.reflect.*;34import java.util.ArrayList;35import java.util.Arrays;36import java.util.logging.Level;37import java.util.logging.Logger;38import org.junit.*;39import static org.junit.Assert.*;4041public class PrivateInvokeTest {42// Utility functions43private static final Lookup LOOKUP = lookup();44private static final Class<?> THIS_CLASS = PrivateInvokeTest.class;45private static final int46REF_NONE = 0, // null value47REF_getField = 1,48REF_getStatic = 2,49REF_putField = 3,50REF_putStatic = 4,51REF_invokeVirtual = 5,52REF_invokeStatic = 6,53REF_invokeSpecial = 7,54REF_newInvokeSpecial = 8,55REF_invokeInterface = 9,56REF_LIMIT = 10,57REF_MH_invokeBasic = REF_NONE;;58private static final String[] REF_KIND_NAMES = {59"MH::invokeBasic",60"REF_getField", "REF_getStatic", "REF_putField", "REF_putStatic",61"REF_invokeVirtual", "REF_invokeStatic", "REF_invokeSpecial",62"REF_newInvokeSpecial", "REF_invokeInterface"63};64private int verbose;65//{ verbose = 99; } // for debugging66{67String vstr = System.getProperty(THIS_CLASS.getSimpleName()+".verbose");68if (vstr == null)69vstr = System.getProperty(THIS_CLASS.getName()+".verbose");70if (vstr == null)71vstr = System.getProperty("test.verbose");72if (vstr != null) verbose = Integer.parseInt(vstr);73}74private static int referenceKind(Method m) {75if (Modifier.isStatic(m.getModifiers()))76return REF_invokeStatic;77else if (m.getDeclaringClass().isInterface())78return REF_invokeInterface;79else if (Modifier.isFinal(m.getModifiers()) ||80Modifier.isFinal(m.getDeclaringClass().getModifiers()))81return REF_invokeSpecial;82else83return REF_invokeVirtual;84}85private static MethodType basicType(MethodType mtype) {86MethodType btype = mtype.erase();87if (btype.hasPrimitives()) {88for (int i = -1; i < mtype.parameterCount(); i++) {89Class<?> type = (i < 0 ? mtype.returnType() : mtype.parameterType(i));90if (type == boolean.class ||91type == byte.class ||92type == char.class ||93type == short.class) {94type = int.class;95if (i < 0)96btype = btype.changeReturnType(type);97else98btype = btype.changeParameterType(i, type);99}100}101}102return btype;103}104private static Method getMethod(Class<?> defc, String name, Class<?>... ptypes) {105try {106return defc.getDeclaredMethod(name, ptypes);107} catch (NoSuchMethodException ex) {108}109try {110return defc.getMethod(name, ptypes);111} catch (NoSuchMethodException ex) {112throw new IllegalArgumentException(ex);113}114}115private static MethodHandle unreflect(Method m) {116try {117MethodHandle mh = LOOKUP.unreflect(m);118if (Modifier.isTransient(m.getModifiers()))119mh = mh.asFixedArity(); // remove varargs wrapper120return mh;121} catch (IllegalAccessException ex) {122throw new IllegalArgumentException(ex);123}124}125private static final Lookup DIRECT_INVOKER_LOOKUP;126private static final Class<?> MEMBER_NAME_CLASS;127private static final MethodHandle MH_INTERNAL_MEMBER_NAME;128private static final MethodHandle MH_DEBUG_STRING;129static {130try {131// This is white box testing. Use reflection to grab private implementation bits.132String magicName = "IMPL_LOOKUP";133Field magicLookup = MethodHandles.Lookup.class.getDeclaredField(magicName);134// This unit test will fail if a security manager is installed.135magicLookup.setAccessible(true);136// Forbidden fruit...137DIRECT_INVOKER_LOOKUP = (Lookup) magicLookup.get(null);138MEMBER_NAME_CLASS = Class.forName("java.lang.invoke.MemberName", false, MethodHandle.class.getClassLoader());139MH_INTERNAL_MEMBER_NAME = DIRECT_INVOKER_LOOKUP140.findVirtual(MethodHandle.class, "internalMemberName", methodType(MEMBER_NAME_CLASS))141.asType(methodType(Object.class, MethodHandle.class));142MH_DEBUG_STRING = DIRECT_INVOKER_LOOKUP143.findVirtual(MethodHandle.class, "debugString", methodType(String.class));144} catch (ReflectiveOperationException ex) {145throw new Error(ex);146}147}148private Object internalMemberName(MethodHandle mh) {149try {150return MH_INTERNAL_MEMBER_NAME.invokeExact(mh);151} catch (Throwable ex) {152throw new Error(ex);153}154}155private String debugString(MethodHandle mh) {156try {157return (String) MH_DEBUG_STRING.invokeExact(mh);158} catch (Throwable ex) {159throw new Error(ex);160}161}162private static MethodHandle directInvoker(int refKind, MethodType mtype) {163return directInvoker(REF_KIND_NAMES[refKind], mtype);164}165private static MethodHandle directInvoker(String name, MethodType mtype) {166boolean isStatic;167mtype = mtype.erase();168if (name.startsWith("MH::")) {169isStatic = false;170name = strip("MH::", name);171} else if (name.startsWith("REF_")) {172isStatic = true;173name = strip("REF_", name);174if (name.startsWith("invoke"))175name = "linkTo"+strip("invoke", name);176mtype = mtype.appendParameterTypes(MEMBER_NAME_CLASS);177} else {178throw new AssertionError("name="+name);179}180//System.out.println("directInvoker = "+name+mtype);181try {182if (isStatic)183return DIRECT_INVOKER_LOOKUP184.findStatic(MethodHandle.class, name, mtype);185else186return DIRECT_INVOKER_LOOKUP187.findVirtual(MethodHandle.class, name, mtype);188} catch (ReflectiveOperationException ex) {189throw new IllegalArgumentException(ex);190}191}192private Object invokeWithArguments(Method m, Object... args) {193Object recv = null;194if (!Modifier.isStatic(m.getModifiers())) {195recv = args[0];196args = pop(1, args);197}198try {199return m.invoke(recv, args);200} catch (IllegalAccessException|IllegalArgumentException|InvocationTargetException ex) {201throw new IllegalArgumentException(ex);202}203}204private Object invokeWithArguments(MethodHandle mh, Object... args) {205try {206return mh.invokeWithArguments(args);207} catch (Throwable ex) {208throw new IllegalArgumentException(ex);209}210}211private int counter;212private Object makeArgument(Class<?> type) {213final String cname = type.getSimpleName();214final int n = ++counter;215final int nn = (n << 10) + 13;216if (type.isAssignableFrom(String.class)) {217return "<"+cname+"#"+nn+">";218}219if (type == THIS_CLASS) return this.withCounter(nn);220if (type == Integer.class || type == int.class) return nn;221if (type == Character.class || type == char.class) return (char)(n % 100+' ');222if (type == Byte.class || type == byte.class) return (byte)-(n % 100);223if (type == Long.class || type == long.class) return (long)nn;224throw new IllegalArgumentException("don't know how to make argument of type: "+type);225}226private Object[] makeArguments(Class<?>... ptypes) {227Object[] args = new Object[ptypes.length];228for (int i = 0; i < args.length; i++)229args[i] = makeArgument(ptypes[i]);230return args;231}232private Object[] makeArguments(MethodType mtype) {233return makeArguments(mtype.parameterArray());234}235private Object[] pop(int n, Object[] args) {236if (n >= 0)237return Arrays.copyOfRange(args, n, args.length);238else239return Arrays.copyOfRange(args, 0, args.length+n);240}241private Object[] pushAtFront(Object arg1, Object[] args) {242Object[] res = new Object[1+args.length];243res[0] = arg1;244System.arraycopy(args, 0, res, 1, args.length);245return res;246}247private Object[] pushAtBack(Object[] args, Object argN) {248Object[] res = new Object[1+args.length];249System.arraycopy(args, 0, res, 0, args.length);250res[args.length] = argN;251return res;252}253private static String strip(String prefix, String s) {254assert(s.startsWith(prefix));255return s.substring(prefix.length());256}257258private final int[] refKindTestCounts = new int[REF_KIND_NAMES.length];259@After260public void printCounts() {261ArrayList<String> zeroes = new ArrayList<>();262for (int i = 0; i < refKindTestCounts.length; i++) {263final int count = refKindTestCounts[i];264final String name = REF_KIND_NAMES[i];265if (count == 0) {266if (name != null) zeroes.add(name);267continue;268}269if (verbose >= 0)270System.out.println("test count for "+name+" : "+count);271else if (name != null)272zeroes.add(name);273}274if (verbose >= 0)275System.out.println("test counts zero for "+zeroes);276}277278// Test subjects279public static String makeString(Object x) { return "makeString("+x+")"; }280public static String dupString(String x) { return "("+x+"+"+x+")"; }281public static String intString(int x) { return "intString("+x+")"; }282public static String byteString(byte x) { return "byteString("+x+")"; }283public static String longString(String x, long y, String z) { return "longString("+x+y+z+")"; }284285public final String toString() {286return "<"+getClass().getSimpleName()+"#"+counter+">";287}288public final String hello() { return "hello from "+this; }289private PrivateInvokeTest withCounter(int counter) {290PrivateInvokeTest res = new PrivateInvokeTest();291res.counter = counter;292return res;293}294295public static void main(String... av) throws Throwable {296new PrivateInvokeTest().run();297}298public void run() throws Throwable {299testFirst();300testInvokeDirect();301}302303@Test304public void testFirst() throws Throwable {305if (true) return; // nothing here306try {307System.out.println("start of testFirst");308} finally {309System.out.println("end of testFirst");310}311}312313@Test314public void testInvokeDirect() {315testInvokeDirect(getMethod(THIS_CLASS, "hello"));316testInvokeDirect(getMethod(Object.class, "toString"));317testInvokeDirect(getMethod(Comparable.class, "compareTo", Object.class));318testInvokeDirect(getMethod(THIS_CLASS, "makeString", Object.class));319testInvokeDirect(getMethod(THIS_CLASS, "dupString", String.class));320testInvokeDirect(getMethod(THIS_CLASS, "intString", int.class));321testInvokeDirect(getMethod(THIS_CLASS, "byteString", byte.class));322testInvokeDirect(getMethod(THIS_CLASS, "longString", String.class, long.class, String.class));323}324325void testInvokeDirect(Method m) {326final int refKind = referenceKind(m);327testInvokeDirect(m, refKind);328testInvokeDirect(m, REF_MH_invokeBasic);329}330void testInvokeDirect(Method m, int refKind) {331if (verbose >= 1)332System.out.println("testInvoke m="+m+" : "+REF_KIND_NAMES[refKind]);333final MethodHandle mh = unreflect(m);334Object[] args = makeArguments(mh.type());335Object res1 = invokeWithArguments(m, args);336// res1 comes from java.lang.reflect.Method::invoke337if (verbose >= 1)338System.out.println("m"+Arrays.asList(args)+" => "+res1);339// res2 comes from java.lang.invoke.MethodHandle::invoke340Object res2 = invokeWithArguments(mh, args);341assertEquals(res1, res2);342MethodType mtype = mh.type();343testInvokeVia("DMH invoker", refKind, directInvoker(refKind, mtype), mh, res1, args);344MethodType etype = mtype.erase();345if (etype != mtype) {346// Try a detuned invoker.347testInvokeVia("erased DMH invoker", refKind, directInvoker(refKind, etype), mh, res1, args);348}349MethodType btype = basicType(mtype);350if (btype != mtype && btype != etype) {351// Try a detuned invoker.352testInvokeVia("basic DMH invoker", refKind, directInvoker(refKind, btype), mh, res1, args);353}354if (false) {355// this can crash the JVM356testInvokeVia("generic DMH invoker", refKind, directInvoker(refKind, mtype.generic()), mh, res1, args);357}358refKindTestCounts[refKind] += 1;359}360361void testInvokeVia(String kind, int refKind, MethodHandle invoker, MethodHandle mh, Object res1, Object... args) {362Object[] args1;363if (refKind == REF_MH_invokeBasic)364args1 = pushAtFront(mh, args);365else366args1 = pushAtBack(args, internalMemberName(mh));367if (verbose >= 2) {368System.out.println(kind+" invoker="+invoker+" mh="+debugString(mh)+" args="+Arrays.asList(args1));369}370Object res3 = invokeWithArguments(invoker, args1);371assertEquals(res1, res3);372}373}374375376