1 /*
2 * Copyright (c) 2008, 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. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.lang.invoke;
27
28 import jdk.internal.vm.annotation.Stable;
29 import sun.invoke.util.ValueConversions;
30
31 import java.util.ArrayList;
32 import java.util.List;
33
34 import static java.lang.invoke.LambdaForm.BasicType;
35 import static java.lang.invoke.LambdaForm.BasicType.*;
36 import static java.lang.invoke.LambdaForm.BasicType.V_TYPE_NUM;
37 import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
38 import static java.lang.invoke.MethodHandleNatives.Constants.*;
39 import static java.lang.invoke.MethodHandleStatics.newInternalError;
40 import static java.lang.invoke.MethodHandleStatics.uncaughtException;
41
42 /**
43 * The flavor of method handle which emulates an invoke instruction
44 * on a predetermined argument. The JVM dispatches to the correct method
45 * when the handle is created, not when it is invoked.
46 *
47 * All bound arguments are encapsulated in dedicated species.
48 */
49 /*non-public*/
50 abstract class BoundMethodHandle extends MethodHandle {
51
52 /*non-public*/
53 BoundMethodHandle(MethodType type, LambdaForm form) {
54 super(type, form);
55 assert(speciesData() == speciesDataFor(form));
56 }
57
58 //
59 // BMH API and internals
60 //
61
62 static BoundMethodHandle bindSingle(MethodType type, LambdaForm form, BasicType xtype, Object x) {
63 // for some type signatures, there exist pre-defined concrete BMH classes
64 try {
65 return switch (xtype) {
66 case L_TYPE -> bindSingle(type, form, x); // Use known fast path.
67 case I_TYPE -> (BoundMethodHandle) SPECIALIZER.topSpecies().extendWith(I_TYPE_NUM).factory().invokeBasic(type, form, ValueConversions.widenSubword(x));
68 case J_TYPE -> (BoundMethodHandle) SPECIALIZER.topSpecies().extendWith(J_TYPE_NUM).factory().invokeBasic(type, form, (long) x);
69 case F_TYPE -> (BoundMethodHandle) SPECIALIZER.topSpecies().extendWith(F_TYPE_NUM).factory().invokeBasic(type, form, (float) x);
70 case D_TYPE -> (BoundMethodHandle) SPECIALIZER.topSpecies().extendWith(D_TYPE_NUM).factory().invokeBasic(type, form, (double) x);
71 default -> throw newInternalError("unexpected xtype: " + xtype);
72 };
73 } catch (Throwable t) {
74 throw uncaughtException(t);
75 }
76 }
77
78 /*non-public*/
79 LambdaFormEditor editor() {
80 return form.editor();
81 }
82
83 static BoundMethodHandle bindSingle(MethodType type, LambdaForm form, Object x) {
84 return Species_L.make(type, form, x);
85 }
86
87 @Override // there is a default binder in the super class, for 'L' types only
88 /*non-public*/
89 BoundMethodHandle bindArgumentL(int pos, Object value) {
90 return editor().bindArgumentL(this, pos, value);
91 }
92
93 /*non-public*/
94 BoundMethodHandle bindArgumentI(int pos, int value) {
95 return editor().bindArgumentI(this, pos, value);
96 }
97 /*non-public*/
98 BoundMethodHandle bindArgumentJ(int pos, long value) {
99 return editor().bindArgumentJ(this, pos, value);
100 }
101 /*non-public*/
102 BoundMethodHandle bindArgumentF(int pos, float value) {
103 return editor().bindArgumentF(this, pos, value);
104 }
105 /*non-public*/
106 BoundMethodHandle bindArgumentD(int pos, double value) {
107 return editor().bindArgumentD(this, pos, value);
108 }
109 @Override
110 BoundMethodHandle rebind() {
111 if (!tooComplex()) {
112 return this;
113 }
114 return makeReinvoker(this);
115 }
116
117 private boolean tooComplex() {
118 return (fieldCount() > FIELD_COUNT_THRESHOLD ||
119 form.expressionCount() > FORM_EXPRESSION_THRESHOLD);
120 }
121 private static final int FIELD_COUNT_THRESHOLD = 12; // largest convenient BMH field count
122 private static final int FORM_EXPRESSION_THRESHOLD = 24; // largest convenient BMH expression count
123
124 /**
125 * A reinvoker MH has this form:
126 * {@code lambda (bmh, arg*) { thismh = bmh[0]; invokeBasic(thismh, arg*) }}
127 */
128 static BoundMethodHandle makeReinvoker(MethodHandle target) {
129 LambdaForm form = DelegatingMethodHandle.makeReinvokerForm(
130 target, MethodTypeForm.LF_REBIND,
131 Species_L.BMH_SPECIES, Species_L.BMH_SPECIES.getterFunction(0));
132 return Species_L.make(target.type(), form, target);
133 }
134
135 /**
136 * Return the {@link BoundMethodHandle.SpeciesData} instance representing this BMH species. All subclasses must provide a
137 * static field containing this value, and they must accordingly implement this method.
138 */
139 /*non-public*/
140 abstract BoundMethodHandle.SpeciesData speciesData();
141
142 /*non-public*/
143 static BoundMethodHandle.SpeciesData speciesDataFor(LambdaForm form) {
144 Object c = form.names[0].constraint;
145 if (c instanceof SpeciesData) {
146 return (SpeciesData) c;
147 }
148 // if there is no BMH constraint, then use the null constraint
149 return SPECIALIZER.topSpecies();
150 }
151
152 /**
153 * Return the number of fields in this BMH. Equivalent to speciesData().fieldCount().
154 */
155 /*non-public*/
156 final int fieldCount() { return speciesData().fieldCount(); }
157
158 @Override
159 Object internalProperties() {
160 return "\n& BMH="+internalValues();
161 }
162
163 @Override
164 final String internalValues() {
165 int count = fieldCount();
166 if (count == 1) {
167 return "[" + arg(0) + "]";
168 }
169 StringBuilder sb = new StringBuilder("[");
170 for (int i = 0; i < count; ++i) {
171 sb.append("\n ").append(i).append(": ( ").append(arg(i)).append(" )");
172 }
173 return sb.append("\n]").toString();
174 }
175
176 /*non-public*/
177 final Object arg(int i) {
178 try {
179 Class<?> fieldType = speciesData().fieldTypes().get(i);
180 switch (BasicType.basicType(fieldType)) {
181 case L_TYPE: return speciesData().getter(i).invokeBasic(this);
182 case I_TYPE: return (int) speciesData().getter(i).invokeBasic(this);
183 case J_TYPE: return (long) speciesData().getter(i).invokeBasic(this);
184 case F_TYPE: return (float) speciesData().getter(i).invokeBasic(this);
185 case D_TYPE: return (double) speciesData().getter(i).invokeBasic(this);
186 }
187 } catch (Throwable ex) {
188 throw uncaughtException(ex);
189 }
190 throw new InternalError("unexpected type: " + speciesData().key()+"."+i);
191 }
192
193 //
194 // cloning API
195 //
196
197 /*non-public*/
198 abstract BoundMethodHandle copyWith(MethodType mt, LambdaForm lf);
199 /*non-public*/
200 abstract BoundMethodHandle copyWithExtendL(MethodType mt, LambdaForm lf, Object narg);
201 /*non-public*/
202 abstract BoundMethodHandle copyWithExtendI(MethodType mt, LambdaForm lf, int narg);
203 /*non-public*/
204 abstract BoundMethodHandle copyWithExtendJ(MethodType mt, LambdaForm lf, long narg);
205 /*non-public*/
206 abstract BoundMethodHandle copyWithExtendF(MethodType mt, LambdaForm lf, float narg);
207 /*non-public*/
208 abstract BoundMethodHandle copyWithExtendD(MethodType mt, LambdaForm lf, double narg);
209
210 //
211 // concrete BMH classes required to close bootstrap loops
212 //
213
214 private // make it private to force users to access the enclosing class first
215 static final class Species_L extends BoundMethodHandle {
216
217 final Object argL0;
218
219 private Species_L(MethodType mt, LambdaForm lf, Object argL0) {
220 super(mt, lf);
221 this.argL0 = argL0;
222 }
223
224 @Override
225 /*non-public*/
226 SpeciesData speciesData() {
227 return BMH_SPECIES;
228 }
229
230 /*non-public*/
231 static @Stable SpeciesData BMH_SPECIES;
232
233 /*non-public*/
234 static BoundMethodHandle make(MethodType mt, LambdaForm lf, Object argL0) {
235 return new Species_L(mt, lf, argL0);
236 }
237 @Override
238 /*non-public*/
239 final BoundMethodHandle copyWith(MethodType mt, LambdaForm lf) {
240 return new Species_L(mt, lf, argL0);
241 }
242 @Override
243 /*non-public*/
244 final BoundMethodHandle copyWithExtendL(MethodType mt, LambdaForm lf, Object narg) {
245 try {
246 return (BoundMethodHandle) BMH_SPECIES.extendWith(L_TYPE_NUM).factory().invokeBasic(mt, lf, argL0, narg);
247 } catch (Throwable ex) {
248 throw uncaughtException(ex);
249 }
250 }
251 @Override
252 /*non-public*/
253 final BoundMethodHandle copyWithExtendI(MethodType mt, LambdaForm lf, int narg) {
254 try {
255 return (BoundMethodHandle) BMH_SPECIES.extendWith(I_TYPE_NUM).factory().invokeBasic(mt, lf, argL0, narg);
256 } catch (Throwable ex) {
257 throw uncaughtException(ex);
258 }
259 }
260 @Override
261 /*non-public*/
262 final BoundMethodHandle copyWithExtendJ(MethodType mt, LambdaForm lf, long narg) {
263 try {
264 return (BoundMethodHandle) BMH_SPECIES.extendWith(J_TYPE_NUM).factory().invokeBasic(mt, lf, argL0, narg);
265 } catch (Throwable ex) {
266 throw uncaughtException(ex);
267 }
268 }
269 @Override
270 /*non-public*/
271 final BoundMethodHandle copyWithExtendF(MethodType mt, LambdaForm lf, float narg) {
272 try {
273 return (BoundMethodHandle) BMH_SPECIES.extendWith(F_TYPE_NUM).factory().invokeBasic(mt, lf, argL0, narg);
274 } catch (Throwable ex) {
275 throw uncaughtException(ex);
276 }
277 }
278 @Override
279 /*non-public*/
280 final BoundMethodHandle copyWithExtendD(MethodType mt, LambdaForm lf, double narg) {
281 try {
282 return (BoundMethodHandle) BMH_SPECIES.extendWith(D_TYPE_NUM).factory().invokeBasic(mt, lf, argL0, narg);
283 } catch (Throwable ex) {
284 throw uncaughtException(ex);
285 }
286 }
287 }
288
289 //
290 // BMH species meta-data
291 //
292
293 /*non-public*/
294 static final class SpeciesData
295 extends ClassSpecializer<BoundMethodHandle, String, SpeciesData>.SpeciesData {
296 // This array is filled in lazily, as new species come into being over time.
297 @Stable private final SpeciesData[] extensions = new SpeciesData[ARG_TYPE_LIMIT];
298
299 public SpeciesData(Specializer outer, String key) {
300 outer.super(key);
301 }
302
303 @Override
304 protected String deriveClassName() {
305 String typeString = deriveTypeString();
306 if (typeString.isEmpty()) {
307 return SimpleMethodHandle.class.getName();
308 }
309 return BoundMethodHandle.class.getName() + "$Species_" + typeString;
310 }
311
312 @Override
313 protected List<Class<?>> deriveFieldTypes(String key) {
314 ArrayList<Class<?>> types = new ArrayList<>(key.length());
315 for (int i = 0; i < key.length(); i++) {
316 types.add(basicType(key.charAt(i)).basicTypeClass());
317 }
318 return types;
319 }
320
321 @Override
322 protected String deriveTypeString() {
323 // (If/when we have to add nominal types, just inherit the more complex default.)
324 return key();
325 }
326
327 @Override
328 protected MethodHandle deriveTransformHelper(MemberName transform, int whichtm) {
329 if (whichtm == Specializer.TN_COPY_NO_EXTEND) {
330 return factory();
331 } else if (whichtm < ARG_TYPE_LIMIT) {
332 return extendWith((byte) whichtm).factory();
333 } else {
334 throw newInternalError("bad transform");
335 }
336 }
337
338 @Override
339 protected <X> List<X> deriveTransformHelperArguments(MemberName transform, int whichtm, List<X> args, List<X> fields) {
340 assert(verifyTHAargs(transform, whichtm, args, fields));
341 // The rule is really simple: Keep the first two arguments
342 // the same, then put in the fields, then put any other argument.
343 args.addAll(2, fields);
344 return args;
345 }
346
347 private boolean verifyTHAargs(MemberName transform, int whichtm, List<?> args, List<?> fields) {
348 assert(transform == Specializer.BMH_TRANSFORMS.get(whichtm));
349 assert(args.size() == transform.getMethodType().parameterCount());
350 assert(fields.size() == this.fieldCount());
351 final int MH_AND_LF = 2;
352 if (whichtm == Specializer.TN_COPY_NO_EXTEND) {
353 assert(transform.getMethodType().parameterCount() == MH_AND_LF);
354 } else if (whichtm < ARG_TYPE_LIMIT) {
355 assert(transform.getMethodType().parameterCount() == MH_AND_LF+1);
356 final BasicType type = basicType((byte) whichtm);
357 assert(transform.getParameterTypes()[MH_AND_LF] == type.basicTypeClass());
358 } else {
359 return false;
360 }
361 return true;
362 }
363
364 /*non-public*/
365 SpeciesData extendWith(byte typeNum) {
366 SpeciesData sd = extensions[typeNum];
367 if (sd != null) return sd;
368 sd = SPECIALIZER.findSpecies(key() + BasicType.basicType(typeNum).basicTypeChar());
369 extensions[typeNum] = sd;
370 return sd;
371 }
372 }
373
374 /*non-public*/
375 static final Specializer SPECIALIZER = new Specializer();
376 static {
377 SimpleMethodHandle.BMH_SPECIES = BoundMethodHandle.SPECIALIZER.findSpecies("");
378 Species_L.BMH_SPECIES = BoundMethodHandle.SPECIALIZER.findSpecies("L");
379 }
380
381 /*non-public*/
382 static final class Specializer
383 extends ClassSpecializer<BoundMethodHandle, String, SpeciesData> {
384
385 private static final MemberName SPECIES_DATA_ACCESSOR;
386
387 static {
388 try {
389 SPECIES_DATA_ACCESSOR = IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, BoundMethodHandle.class,
390 "speciesData", MethodType.methodType(BoundMethodHandle.SpeciesData.class));
391 } catch (ReflectiveOperationException ex) {
392 throw newInternalError("Bootstrap link error", ex);
393 }
394 }
395
396 private Specializer() {
397 super( // Reified type parameters:
398 BoundMethodHandle.class, String.class, BoundMethodHandle.SpeciesData.class,
399 // Principal constructor type:
400 MethodType.methodType(void.class, MethodType.class, LambdaForm.class),
401 // Required linkage between class and species:
402 SPECIES_DATA_ACCESSOR,
403 "BMH_SPECIES",
404 BMH_TRANSFORMS);
405 }
406
407 @Override
408 protected String topSpeciesKey() {
409 return "";
410 }
411
412 @Override
413 protected BoundMethodHandle.SpeciesData newSpeciesData(String key) {
414 return new BoundMethodHandle.SpeciesData(this, key);
415 }
416
417 static final List<MemberName> BMH_TRANSFORMS;
418 static final int TN_COPY_NO_EXTEND = V_TYPE_NUM;
419 static {
420 final Class<BoundMethodHandle> BMH = BoundMethodHandle.class;
421 // copyWithExtendLIJFD + copyWith
422 try {
423 BMH_TRANSFORMS = List.of(
424 IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, BMH, "copyWithExtendL", MethodType.methodType(BMH, MethodType.class, LambdaForm.class, Object.class)),
425 IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, BMH, "copyWithExtendI", MethodType.methodType(BMH, MethodType.class, LambdaForm.class, int.class)),
426 IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, BMH, "copyWithExtendJ", MethodType.methodType(BMH, MethodType.class, LambdaForm.class, long.class)),
427 IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, BMH, "copyWithExtendF", MethodType.methodType(BMH, MethodType.class, LambdaForm.class, float.class)),
428 IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, BMH, "copyWithExtendD", MethodType.methodType(BMH, MethodType.class, LambdaForm.class, double.class)),
429 IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, BMH, "copyWith", MethodType.methodType(BMH, MethodType.class, LambdaForm.class))
430 );
431 } catch (ReflectiveOperationException ex) {
432 throw newInternalError("Failed resolving copyWith methods", ex);
433 }
434
435 // as it happens, there is one transform per BasicType including V_TYPE
436 assert(BMH_TRANSFORMS.size() == TYPE_LIMIT);
437 }
438
439 /**
440 * Generation of concrete BMH classes.
441 *
442 * A concrete BMH species is fit for binding a number of values adhering to a
443 * given type pattern. Reference types are erased.
444 *
445 * BMH species are cached by type pattern.
446 *
447 * A BMH species has a number of fields with the concrete (possibly erased) types of
448 * bound values. Setters are provided as an API in BMH. Getters are exposed as MHs,
449 * which can be included as names in lambda forms.
450 */
451 class Factory extends ClassSpecializer<BoundMethodHandle, String, BoundMethodHandle.SpeciesData>.Factory {
452 @Override
453 protected String chooseFieldName(Class<?> type, int index) {
454 return "arg" + super.chooseFieldName(type, index);
455 }
456 }
457
458 @Override
459 protected Factory makeFactory() {
460 return new Factory();
461 }
462 }
463
464 static SpeciesData speciesData_L() { return Species_L.BMH_SPECIES; }
465 static SpeciesData speciesData_LL() { return SPECIALIZER.findSpecies("LL"); }
466 static SpeciesData speciesData_LLL() { return SPECIALIZER.findSpecies("LLL"); }
467 static SpeciesData speciesData_LLLL() { return SPECIALIZER.findSpecies("LLLL"); }
468 static SpeciesData speciesData_LLLLL() { return SPECIALIZER.findSpecies("LLLLL"); }
469 }
--- EOF ---