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 /*
 25  * @test
 26  * @bug 8186046
 27  * @summary Test bootstrap arguments for condy
 28  * @library /java/lang/invoke/common
 29  * @build test.java.lang.invoke.lib.InstructionHelper
 30  * @enablePreview
 31  * @run testng CondyStaticArgumentsTest
 32  * @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyStaticArgumentsTest
 33  */
 34 
 35 import org.testng.Assert;
 36 import org.testng.annotations.Test;
 37 import test.java.lang.invoke.lib.InstructionHelper;
 38 
 39 import java.lang.constant.*;
 40 import java.lang.invoke.*;
 41 import java.lang.reflect.Method;
 42 import java.math.BigDecimal;
 43 import java.math.MathContext;
 44 import java.util.StringJoiner;
 45 import java.util.stream.Stream;
 46 
 47 import static java.lang.invoke.MethodType.methodType;
 48 
 49 public class CondyStaticArgumentsTest {
 50     static final MethodHandles.Lookup L = MethodHandles.lookup();
 51     private static final DirectMethodHandleDesc bigDecimalMhDesc = directMhDesc("bigDecimal");
 52     private static final DirectMethodHandleDesc mathContextMhDesc = directMhDesc("mathContext");
 53 
 54     static class BSMInfo {
 55         final String methodName;
 56         final MethodHandle handle;
 57         final String descriptor;
 58 
 59         BSMInfo(String name) {
 60             methodName = name;
 61 
 62             Method m = Stream.of(CondyStaticArgumentsTest.class.getDeclaredMethods())
 63                     .filter(x -> x.getName().equals(methodName)).findFirst()
 64                     .get();
 65             try {
 66                 handle = MethodHandles.lookup().unreflect(m);
 67             } catch (Exception e) {
 68                 throw new Error(e);
 69             }
 70             descriptor = handle.type().toMethodDescriptorString();
 71         }
 72 
 73         static BSMInfo of(String name) {
 74             return new BSMInfo(name);
 75         }
 76     }
 77 
 78     static String basicArgs(MethodHandles.Lookup l, String name, Class<?> type,
 79                             int i, long j, float f, double d,
 80                             Class<?> c, String s,
 81                             MethodType mt, MethodHandle mh) {
 82         return new StringJoiner("-")
 83                 .add(name)
 84                 .add(type.getSimpleName())
 85                 .add(Integer.toString(i))
 86                 .add(Long.toString(j))
 87                 .add(Float.toString(f))
 88                 .add(Double.toString(d))
 89                 .add(c.getSimpleName())
 90                 .add(s)
 91                 .add(mt.toString())
 92                 .add(Integer.toString(mh.type().parameterCount()))
 93                 .toString();
 94     }
 95 
 96     @Test
 97     public void testBasicArgs() throws Throwable {
 98         BSMInfo bi = BSMInfo.of("basicArgs");
 99         MethodHandleInfo mhi = MethodHandles.lookup().revealDirect(bi.handle);
100 
101         MethodHandle mh = InstructionHelper.ldcDynamicConstant(
102                 L, "constant-name", String.class,
103                 bi.methodName, bi.handle.type(),
104                 1, 2L, 3.0f, 4.0d,
105                 ClassDesc.ofDescriptor(Number.class.descriptorString()),
106                 "something",
107                 MethodTypeDesc.ofDescriptor("(IJFD)V"),
108                 MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.valueOf(mhi.getReferenceKind()),
109                         ClassDesc.ofDescriptor(mhi.getDeclaringClass().descriptorString()),
110                         mhi.getName(), MethodTypeDesc.ofDescriptor(mhi.getMethodType().descriptorString()))
111         );
112 
113         Assert.assertEquals(mh.invoke(), "constant-name-String-1-2-3.0-4.0-Number-something-(int,long,float,double)void-11");
114     }
115 
116     static MathContext mathContext(MethodHandles.Lookup l, String value, Class<?> type) {
117         switch (value) {
118             case "UNLIMITED":
119                 return MathContext.UNLIMITED;
120             case "DECIMAL32":
121                 return MathContext.DECIMAL32;
122             case "DECIMAL64":
123                 return MathContext.DECIMAL64;
124             case "DECIMAL128":
125                 return MathContext.DECIMAL128;
126             default:
127                 throw new UnsupportedOperationException();
128         }
129     }
130 
131     static BigDecimal bigDecimal(MethodHandles.Lookup l, String name, Class<?> type,
132                                  String value, MathContext mc) {
133         return new BigDecimal(value, mc);
134     }
135 
136     static String condyWithCondy(MethodHandles.Lookup l, String name, Class<?> type,
137                                  BigDecimal d) {
138         return new StringJoiner("-")
139                 .add(name)
140                 .add(type.getSimpleName())
141                 .add(d.toString())
142                 .add(Integer.toString(d.precision()))
143                 .toString();
144     }
145 
146     @Test
147     public void testCondyWithCondy() throws Throwable {
148         BSMInfo bi = BSMInfo.of("condyWithCondy");
149 
150         MethodHandle mh = InstructionHelper.ldcDynamicConstant(
151                 L, "big-decimal-math-context", String.class,
152                 bi.methodName, bi.handle.type(),
153                 DynamicConstantDesc.ofNamed(
154                         bigDecimalMhDesc,
155                         "big-decimal",
156                         InstructionHelper.classDesc(BigDecimal.class),
157                         "3.14159265358979323846",
158                         DynamicConstantDesc.ofNamed(
159                                 mathContextMhDesc,
160                                 "DECIMAL32",
161                                 InstructionHelper.classDesc(MathContext.class)
162                         )
163                 )
164         );
165         Assert.assertEquals(mh.invoke(), "big-decimal-math-context-String-3.141593-7");
166     }
167 
168 
169     static ConstantCallSite indyWithCondy(MethodHandles.Lookup l, String name, MethodType type,
170                                           BigDecimal d) {
171         String s = new StringJoiner("-")
172                 .add(name)
173                 .add(type.toMethodDescriptorString())
174                 .add(d.toString())
175                 .add(Integer.toString(d.precision()))
176                 .toString();
177         return new ConstantCallSite(MethodHandles.constant(String.class, s));
178     }
179 
180     @Test
181     public void testIndyWithCondy() throws Throwable {
182         BSMInfo bi = BSMInfo.of("indyWithCondy");
183 
184         MethodHandle mh = InstructionHelper.invokedynamic(
185                 L, "big-decimal-math-context", methodType(String.class),
186                 bi.methodName, bi.handle.type(),
187                 DynamicConstantDesc.ofNamed(
188                         bigDecimalMhDesc,
189                         "big-decimal",
190                         InstructionHelper.classDesc(BigDecimal.class),
191                         "3.14159265358979323846",
192                         DynamicConstantDesc.ofNamed(
193                                 mathContextMhDesc,
194                                 "DECIMAL32",
195                                 InstructionHelper.classDesc(MathContext.class)
196                         )
197                 ));
198         Assert.assertEquals(mh.invoke(), "big-decimal-math-context-()Ljava/lang/String;-3.141593-7");
199     }
200 
201     private static DirectMethodHandleDesc directMhDesc(String methodName) {
202         MethodHandleInfo mhi = MethodHandles.lookup().revealDirect(BSMInfo.of(methodName).handle);
203         return MethodHandleDesc.of(
204                 DirectMethodHandleDesc.Kind.valueOf(mhi.getReferenceKind()),
205                 ClassDesc.ofDescriptor(mhi.getDeclaringClass().descriptorString()),
206                 mhi.getName(),
207                 mhi.getMethodType().descriptorString()
208         );
209     }
210 }