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 }