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