1 /*
   2  * Copyright (c) 2017, 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 import jdk.experimental.value.MethodHandleBuilder;
  25 import jdk.experimental.value.ValueType;
  26 import org.testng.annotations.Test;
  27 
  28 import java.lang.invoke.MethodHandle;
  29 import java.lang.invoke.MethodHandles;
  30 import java.lang.invoke.MethodType;
  31 
  32 import static org.testng.Assert.*;
  33 
  34 /*
  35  * @test
  36  * @run testng/othervm -XX:+EnableMVT -Dvalhalla.enablePoolPatches=true WithFieldTest
  37  */
  38 
  39 @Test
  40 public class WithFieldTest {
  41 
  42     static final ValueType<?> VT_Point = ValueType.forClass(Point.class);
  43 
  44     static final ValueType<?> VT_PrivatePoint = ValueType.forClass(PrivatePoint.class);
  45 
  46     static final MethodHandle MH_Point_get_x;
  47 
  48     static final MethodHandle MH_PrivatePoint_get_x;
  49 
  50     static {
  51         try {
  52             MH_Point_get_x = MethodHandles.lookup().findGetter(
  53                     Point.class, "x", int.class);
  54             MH_PrivatePoint_get_x = MethodHandles.lookup().findVirtual(
  55                     PrivatePoint.class, "getX", MethodType.methodType(int.class));
  56         } catch (Exception e) {
  57             throw new InternalError(e);
  58         }
  59     }
  60 
  61 
  62     public void testPrivateLookupPrivateFieldUsingVCC() throws Throwable {
  63         testPrivateAccess(VT_PrivatePoint, VT_PrivatePoint.boxClass(), MethodHandles.lookup(), MH_PrivatePoint_get_x);
  64     }
  65 
  66     public void testPrivateLookupPublicFieldUsingVCC() throws Throwable {
  67         testPrivateAccess(VT_Point, VT_Point.boxClass(), MethodHandles.lookup(), MH_Point_get_x);
  68     }
  69 
  70     public void testPrivateLookupPrivateFieldUsingDVT() throws Throwable {
  71         testPrivateAccess(VT_PrivatePoint, VT_PrivatePoint.valueClass(), MethodHandles.lookup(), MH_PrivatePoint_get_x);
  72     }
  73 
  74     public void testPrivateLookupPublicFieldUsingDVT() throws Throwable {
  75         testPrivateAccess(VT_Point, VT_Point.valueClass(), MethodHandles.lookup(), MH_Point_get_x);
  76     }
  77 
  78 
  79     @Test(expectedExceptions = IllegalAccessError.class)
  80     public void testLookupPrivateFieldUsingVCC() throws Throwable {
  81         testAccess(VT_PrivatePoint, MethodHandles.lookup(), MH_PrivatePoint_get_x);
  82     }
  83 
  84     @Test(expectedExceptions = IllegalAccessError.class)
  85     public void testLookupPublicFieldUsingVCC() throws Throwable {
  86         testAccess(VT_Point, MethodHandles.lookup(), MH_Point_get_x);
  87     }
  88 
  89     @Test(expectedExceptions = IllegalAccessError.class)
  90     public void testLookupPrivateFieldUsingDVT() throws Throwable {
  91         testAccess(VT_PrivatePoint, MethodHandles.lookup(), MH_PrivatePoint_get_x);
  92     }
  93 
  94     @Test(expectedExceptions = IllegalAccessError.class)
  95     public void testLookupPublicFieldUsingDVT() throws Throwable {
  96         testAccess(VT_Point, MethodHandles.lookup(), MH_Point_get_x);
  97     }
  98 
  99 
 100     static void testPrivateAccess(ValueType<?> vt, Class<?> lc, MethodHandles.Lookup l, MethodHandle getter) throws Throwable {
 101         testAccess(vt, MethodHandles.privateLookupIn(lc, l), getter);
 102     }
 103 
 104     static void testAccess(ValueType<?> vt, MethodHandles.Lookup l, MethodHandle getter) throws Throwable {
 105         MethodHandle mh = MethodHandles.collectArguments(vwithfield(l, vt, "x", int.class), 0, vt.defaultValueConstant());
 106 
 107         mh = MethodHandles.filterReturnValue(mh, vt.box());
 108 
 109         mh = MethodHandles.filterReturnValue(mh, getter);
 110 
 111         int actual = (int) mh.invoke(42);
 112         assertEquals(actual, 42);
 113     }
 114 
 115     static MethodHandle vwithfield(MethodHandles.Lookup lookup, ValueType<?> vt, String name, Class<?> type) {
 116         Class<?> dvt = vt.valueClass();
 117         return MethodHandleBuilder.loadCode(
 118                 lookup,
 119                 lookup.lookupClass().toString() + "_wither$" + name,
 120                 MethodType.methodType(dvt, dvt, type),
 121                 C -> C.vload(0).load(1).vwithfield(dvt, name, fieldDescriptor(type)).vreturn());
 122     }
 123 
 124     static String fieldDescriptor(Class<?> type) {
 125         String s = MethodType.methodType(type).toMethodDescriptorString();
 126         return s.substring(2);
 127     }
 128 
 129 }