1 /*
  2  * Copyright (c) 2021, 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 /*
 26  * @test
 27  * @summary test method handles with primitive narrowing/widening conversion
 28  * @run testng/othervm PrimitiveTypeConversionTest
 29  */
 30 
 31 import java.lang.invoke.*;
 32 
 33 import static java.lang.invoke.MethodType.*;
 34 
 35 import org.testng.annotations.Test;
 36 import static org.testng.Assert.*;
 37 
 38 public class PrimitiveTypeConversionTest {
 39     static primitive class Value {
 40         Point val;
 41         Point.ref ref;
 42         Value(Point p1, Point.ref p2) {
 43             this.val = p1;
 44             this.ref = p2;
 45         }
 46     }
 47 
 48     static Value narrow(Value.ref v) {
 49         return v;
 50     }
 51 
 52     static Value.ref widen(Value v) {
 53         if (((Object)v) == null) {
 54             throw new Error("should never reach here: should be caught by runtime");
 55         }
 56         return null;
 57     }
 58 
 59     static final Value VALUE = new Value(new Point(10,10), new Point(20, 20));
 60 
 61     @Test
 62     public static void primitiveWidening() throws Throwable {
 63         MethodHandles.Lookup lookup = MethodHandles.lookup();
 64         MethodHandle mh1 = lookup.findStatic(PrimitiveTypeConversionTest.class, "narrow", methodType(Value.class.asValueType(), Value.ref.class));
 65         MethodHandle mh2 = mh1.asType(methodType(Value.class.asValueType(), Value.class.asValueType()));
 66         Object v = mh1.invoke(VALUE);
 67         assertEquals(v, VALUE);
 68         try {
 69             Object v1 = mh1.invoke((Object)null);
 70             fail("Expected NullPointerException but not thrown");
 71         } catch (NullPointerException e) {}
 72 
 73         try {
 74             Object v2 = mh2.invoke((Object)null);
 75             fail("Expected NullPointerException but not thrown");
 76         } catch (NullPointerException e) {}
 77     }
 78 
 79     @Test
 80     public static void primitiveNarrowing() throws Throwable {
 81         MethodHandles.Lookup lookup = MethodHandles.lookup();
 82         MethodHandle mh = lookup.findStatic(PrimitiveTypeConversionTest.class, "widen", methodType(Value.ref.class, Value.class.asValueType()));
 83         Object v = mh.invoke(VALUE);
 84         assertTrue(v == null);
 85         try {
 86             Object v1 = mh.invoke((Object)null);
 87             fail("Expected NullPointerException but not thrown");
 88         } catch (NullPointerException e) {
 89             e.printStackTrace();
 90         }
 91         MethodHandle mh2 = mh.asType(methodType(Value.class.asValueType(), Value.ref.class));
 92         try {
 93             Value v2 = (Value) mh2.invoke((Value.ref)null);
 94             fail("Expected NullPointerException but not thrown");
 95         } catch (NullPointerException e) {
 96             e.printStackTrace();
 97         }
 98     }
 99 
100     @Test
101     public static void valToRef() throws Throwable {
102         MethodHandles.Lookup lookup = MethodHandles.lookup();
103         MethodHandle mh1 = lookup.findGetter(Value.class.asValueType(), "val", Point.class.asValueType());
104         MethodHandle mh2 = mh1.asType(methodType(Point.ref.class, Value.class.asValueType()));
105         Value v = new Value(new Point(10,10), null);
106 
107         Point p1 = (Point) mh1.invokeExact(VALUE);
108         Point.ref p2 = (Point.ref) mh2.invokeExact(VALUE);
109         assertEquals(p1, p2);
110     }
111 
112     @Test
113     public static void refToVal() throws Throwable {
114         MethodHandle mh1 = MethodHandles.lookup().findGetter(Value.class.asValueType(), "ref", Point.ref.class);
115         MethodHandle mh2 = mh1.asType(methodType(Point.class.asValueType(), Value.class.asValueType()));
116         Point.ref p1 = (Point.ref) mh1.invokeExact(VALUE);
117         Point p2 = (Point) mh2.invokeExact(VALUE);
118         assertEquals(p1, p2);
119     }
120 
121     @Test
122     public static void valToRef1() throws Throwable {
123         MethodHandles.Lookup lookup = MethodHandles.lookup();
124         MethodHandle mh1 = lookup.findGetter(Value.class.asValueType(), "val", Point.class.asValueType());
125         MethodHandle mh2 = mh1.asType(methodType(Point.class.asValueType(), Value.ref.class));
126 
127         Point p1 = (Point) mh1.invokeExact(VALUE);
128         Point p2 = (Point) mh2.invoke(VALUE);
129         Point p3 = (Point) mh2.invokeExact((Value.ref)VALUE);
130         assertEquals(p1, p2);
131         assertEquals(p1, p3);
132     }
133 
134     @Test
135     public static void refToVal1() throws Throwable {
136         MethodHandle mh1 = MethodHandles.lookup().findGetter(Value.class.asValueType(), "ref", Point.ref.class);
137         MethodHandle mh2 = mh1.asType(methodType(Point.ref.class, Value.ref.class));
138         Value v = new Value(new Point(10,10), null);
139 
140         Point.ref p1 = (Point.ref) mh1.invokeExact(v);
141         Point.ref p2 = (Point.ref) mh2.invoke(v);
142         Point.ref p3 = (Point.ref) mh2.invokeExact((Value.ref)v);
143         assertEquals(p1, p2);
144         assertEquals(p1, p3);
145     }
146 
147     @Test
148     public static void refToVal2() throws Throwable {
149         MethodHandle mh1 = MethodHandles.lookup().findGetter(Value.class.asValueType(), "ref", Point.ref.class);
150         MethodHandle mh2 = mh1.asType(methodType(Point.class.asValueType(), Value.class.asValueType()));
151         Value v = new Value(new Point(10,10), null);
152 
153         Point.ref p1 = (Point.ref) mh1.invokeExact(v);
154         try {
155             Point p2 = (Point) mh2.invokeExact(v);
156             fail("Expected NullPointerException but not thrown");
157         } catch (NullPointerException e) {}
158     }
159 }