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*/ abstract class BoundMethodHandle extends MethodHandle {
52
53     /*non-public*/ 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             switch (xtype) {
66             case L_TYPE:
67                 return bindSingle(type, form, x);  // Use known fast path.
68             case I_TYPE:
69                 return (BoundMethodHandle) SPECIALIZER.topSpecies().extendWith(I_TYPE_NUM).factory().invokeBasic(type, form, ValueConversions.widenSubword(x));
70             case J_TYPE:
71                 return (BoundMethodHandle) SPECIALIZER.topSpecies().extendWith(J_TYPE_NUM).factory().invokeBasic(type, form, (long) x);
72             case F_TYPE:
73                 return (BoundMethodHandle) SPECIALIZER.topSpecies().extendWith(F_TYPE_NUM).factory().invokeBasic(type, form, (float) x);
74             case D_TYPE:
75                 return (BoundMethodHandle) SPECIALIZER.topSpecies().extendWith(D_TYPE_NUM).factory().invokeBasic(type, form, (double) x);
76             default : throw newInternalError("unexpected xtype: " + xtype);
77             }
78         } catch (Throwable t) {
79             throw uncaughtException(t);
80         }
81     }
82
83     /*non-public*/
84     LambdaFormEditor editor() {
85         return form.editor();
86     }
87
88     static BoundMethodHandle bindSingle(MethodType type, LambdaForm form, Object x) {
89         return Species_L.make(type, form, x);
90     }
91
92     @Override // there is a default binder in the super classfor 'L' types only
93     /*non-public*/
94     BoundMethodHandle bindArgumentL(int pos, Object value) {
95         return editor().bindArgumentL(this, pos, value);
96     }
97
98     /*non-public*/
99     BoundMethodHandle bindArgumentI(int pos, int value) {
100         return editor().bindArgumentI(this, pos, value);
101     }
102     /*non-public*/
103     BoundMethodHandle bindArgumentJ(int pos, long value) {
104         return editor().bindArgumentJ(this, pos, value);
105     }
106     /*non-public*/
107     BoundMethodHandle bindArgumentF(int pos, float value) {
108         return editor().bindArgumentF(this, pos, value);
109     }
110     /*non-public*/
111     BoundMethodHandle bindArgumentD(int pos, double value) {
112         return editor().bindArgumentD(this, pos, value);
113     }
114     @Override
115     BoundMethodHandle rebind() {
116         if (!tooComplex()) {
117             return this;
118         }
119         return makeReinvoker(this);
120     }
121
122     private boolean tooComplex() {
123         return (fieldCount() > FIELD_COUNT_THRESHOLD ||
124                 form.expressionCount() > FORM_EXPRESSION_THRESHOLD);
125     }
126     private static final int FIELD_COUNT_THRESHOLD = 12;      // largest convenient BMH field count
127     private static final int FORM_EXPRESSION_THRESHOLD = 24;  // largest convenient BMH expression count
128
129     /**
130      * A reinvoker MH has this form:
131      * {@code lambda (bmh, arg*) { thismh = bmh[0]; invokeBasic(thismh, arg*) }}
132      */

133     static BoundMethodHandle makeReinvoker(MethodHandle target) {
134         LambdaForm form = DelegatingMethodHandle.makeReinvokerForm(
135                 target, MethodTypeForm.LF_REBIND,
136                 Species_L.BMH_SPECIES, Species_L.BMH_SPECIES.getterFunction(0));
137         return Species_L.make(target.type(), form, target);
138     }
139
140     /**
141      * Return the {@link BoundMethodHandle.SpeciesData} instance representing this BMH species. All subclasses must provide a
142      * static field containing this value, and they must accordingly implement this method.
143      */

144     /*non-public*/ abstract BoundMethodHandle.SpeciesData speciesData();
145
146     /*non-public*/ static BoundMethodHandle.SpeciesData speciesDataFor(LambdaForm form) {
147         Object c = form.names[0].constraint;
148         if (c instanceof SpeciesData) {
149             return (SpeciesData) c;
150         }
151         // if there is no BMH constraint, then use the null constraint
152         return SPECIALIZER.topSpecies();
153     }
154
155     /**
156      * Return the number of fields in this BMH.  Equivalent to speciesData().fieldCount().
157      */

158     /*non-public*/ 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*/ final Object arg(int i) {
179         try {
180             Class<?> fieldType = speciesData().fieldTypes().get(i);
181             switch (BasicType.basicType(fieldType)) {
182                 case L_TYPE: return          speciesData().getter(i).invokeBasic(this);
183                 case I_TYPE: return (int)    speciesData().getter(i).invokeBasic(this);
184                 case J_TYPE: return (long)   speciesData().getter(i).invokeBasic(this);
185                 case F_TYPE: return (float)  speciesData().getter(i).invokeBasic(this);
186                 case D_TYPE: return (double) speciesData().getter(i).invokeBasic(this);
187             }
188         } catch (Throwable ex) {
189             throw uncaughtException(ex);
190         }
191         throw new InternalError("unexpected type: " + speciesData().key()+"."+i);
192     }
193
194     //
195     // cloning API
196     //
197
198     /*non-public*/ abstract BoundMethodHandle copyWith(MethodType mt, LambdaForm lf);
199     /*non-public*/ abstract BoundMethodHandle copyWithExtendL(MethodType mt, LambdaForm lf, Object narg);
200     /*non-public*/ abstract BoundMethodHandle copyWithExtendI(MethodType mt, LambdaForm lf, int    narg);
201     /*non-public*/ abstract BoundMethodHandle copyWithExtendJ(MethodType mt, LambdaForm lf, long   narg);
202     /*non-public*/ abstract BoundMethodHandle copyWithExtendF(MethodType mt, LambdaForm lf, float  narg);
203     /*non-public*/ abstract BoundMethodHandle copyWithExtendD(MethodType mt, LambdaForm lf, double narg);
204
205     //
206     // concrete BMH classes required to close bootstrap loops
207     //
208
209     private  // make it private to force users to access the enclosing class first
210     static final class Species_L extends BoundMethodHandle {
211
212         final Object argL0;
213
214         private Species_L(MethodType mt, LambdaForm lf, Object argL0) {
215             super(mt, lf);
216             this.argL0 = argL0;
217         }
218
219         @Override
220         /*non-public*/ SpeciesData speciesData() {
221             return BMH_SPECIES;
222         }
223
224         /*non-public*/ static @Stable SpeciesData BMH_SPECIES;
225
226         /*non-public*/ static BoundMethodHandle make(MethodType mt, LambdaForm lf, Object argL0) {
227             return new Species_L(mt, lf, argL0);
228         }
229         @Override
230         /*non-public*/ final BoundMethodHandle copyWith(MethodType mt, LambdaForm lf) {
231             return new Species_L(mt, lf, argL0);
232         }
233         @Override
234         /*non-public*/ final BoundMethodHandle copyWithExtendL(MethodType mt, LambdaForm lf, Object narg) {
235             try {
236                 return (BoundMethodHandle) BMH_SPECIES.extendWith(L_TYPE_NUM).factory().invokeBasic(mt, lf, argL0, narg);
237             } catch (Throwable ex) {
238                 throw uncaughtException(ex);
239             }
240         }
241         @Override
242         /*non-public*/ final BoundMethodHandle copyWithExtendI(MethodType mt, LambdaForm lf, int narg) {
243             try {
244                 return (BoundMethodHandle) BMH_SPECIES.extendWith(I_TYPE_NUM).factory().invokeBasic(mt, lf, argL0, narg);
245             } catch (Throwable ex) {
246                 throw uncaughtException(ex);
247             }
248         }
249         @Override
250         /*non-public*/ final BoundMethodHandle copyWithExtendJ(MethodType mt, LambdaForm lf, long narg) {
251             try {
252                 return (BoundMethodHandle) BMH_SPECIES.extendWith(J_TYPE_NUM).factory().invokeBasic(mt, lf, argL0, narg);
253             } catch (Throwable ex) {
254                 throw uncaughtException(ex);
255             }
256         }
257         @Override
258         /*non-public*/ final BoundMethodHandle copyWithExtendF(MethodType mt, LambdaForm lf, float narg) {
259             try {
260                 return (BoundMethodHandle) BMH_SPECIES.extendWith(F_TYPE_NUM).factory().invokeBasic(mt, lf, argL0, narg);
261             } catch (Throwable ex) {
262                 throw uncaughtException(ex);
263             }
264         }
265         @Override
266         /*non-public*/ final BoundMethodHandle copyWithExtendD(MethodType mt, LambdaForm lf, double narg) {
267             try {
268                 return (BoundMethodHandle) BMH_SPECIES.extendWith(D_TYPE_NUM).factory().invokeBasic(mt, lf, argL0, narg);
269             } catch (Throwable ex) {
270                 throw uncaughtException(ex);
271             }
272         }
273     }
274
275     //
276     // BMH species meta-data
277     //
278
279     /*non-public*/
280     static final class SpeciesData extends ClassSpecializer<BoundMethodHandle, String, SpeciesData>.SpeciesData {
281         // This array is filled in lazily, as new species come into being over time.
282         @Stable final private SpeciesData[] extensions = new SpeciesData[ARG_TYPE_LIMIT];
283
284         public SpeciesData(Specializer outer, String key) {
285             outer.super(key);
286         }
287
288         @Override
289         protected String deriveClassName() {
290             String typeString = deriveTypeString();
291             if (typeString.isEmpty()) {
292                 return SimpleMethodHandle.class.getName();
293             }
294             return BoundMethodHandle.class.getName() + "$Species_" + typeString;
295         }
296
297         @Override
298         protected List<Class<?>> deriveFieldTypes(String key) {
299             ArrayList<Class<?>> types = new ArrayList<>(key.length());
300             for (int i = 0; i < key.length(); i++) {
301                 types.add(basicType(key.charAt(i)).basicTypeClass());
302             }
303             return types;
304         }
305
306         @Override
307         protected String deriveTypeString() {
308             // (If/when we have to add nominal types, just inherit the more complex default.)
309             return key();
310         }
311
312         @Override
313         protected MethodHandle deriveTransformHelper(MemberName transform, int whichtm) {
314             if (whichtm == Specializer.TN_COPY_NO_EXTEND) {
315                 return factory();
316             } else if (whichtm < ARG_TYPE_LIMIT) {
317                 return extendWith((byte) whichtm).factory();
318             } else {
319                 throw newInternalError("bad transform");
320             }
321         }
322
323         @Override
324         protected <X> List<X> deriveTransformHelperArguments(MemberName transform, int whichtm, List<X> args, List<X> fields) {
325             assert(verifyTHAargs(transform, whichtm, args, fields));
326             // The rule is really simple:  Keep the first two arguments
327             // the same, then put in the fields, then put any other argument.
328             args.addAll(2, fields);
329             return args;
330         }
331
332         private boolean verifyTHAargs(MemberName transform, int whichtm, List<?> args, List<?> fields) {
333             assert(transform == Specializer.BMH_TRANSFORMS.get(whichtm));
334             assert(args.size() == transform.getMethodType().parameterCount());
335             assert(fields.size() == this.fieldCount());
336             final int MH_AND_LF = 2;
337             if (whichtm == Specializer.TN_COPY_NO_EXTEND) {
338                 assert(transform.getMethodType().parameterCount() == MH_AND_LF);
339             } else if (whichtm < ARG_TYPE_LIMIT) {
340                 assert(transform.getMethodType().parameterCount() == MH_AND_LF+1);
341                 final BasicType type = basicType((byte) whichtm);
342                 assert(transform.getParameterTypes()[MH_AND_LF] == type.basicTypeClass());
343             } else {
344                 return false;
345             }
346             return true;
347         }
348
349         /*non-public*/ SpeciesData extendWith(byte typeNum) {
350             SpeciesData sd = extensions[typeNum];
351             if (sd != null)  return sd;
352             sd = SPECIALIZER.findSpecies(key() + BasicType.basicType(typeNum).basicTypeChar());
353             extensions[typeNum] = sd;
354             return sd;
355         }
356     }
357
358     /*non-public*/
359     static final Specializer SPECIALIZER = new Specializer();
360     static {
361         SimpleMethodHandle.BMH_SPECIES = BoundMethodHandle.SPECIALIZER.findSpecies("");
362         Species_L.BMH_SPECIES = BoundMethodHandle.SPECIALIZER.findSpecies("L");
363     }
364
365     /*non-public*/
366     static final class Specializer extends ClassSpecializer<BoundMethodHandle, String, SpeciesData> {
367
368         private static final MemberName SPECIES_DATA_ACCESSOR;
369
370         static {
371             try {
372                 SPECIES_DATA_ACCESSOR = IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, BoundMethodHandle.class,
373                         "speciesData", MethodType.methodType(BoundMethodHandle.SpeciesData.class));
374             } catch (ReflectiveOperationException ex) {
375                 throw newInternalError("Bootstrap link error", ex);
376             }
377         }
378
379         private Specializer() {
380             super(  // Reified type parameters:
381                     BoundMethodHandle.class, String.class, BoundMethodHandle.SpeciesData.class,
382                     // Principal constructor type:
383                     MethodType.methodType(void.class, MethodType.class, LambdaForm.class),
384                     // Required linkage between class and species:
385                     SPECIES_DATA_ACCESSOR,
386                     "BMH_SPECIES",
387                     BMH_TRANSFORMS);
388         }
389
390         @Override
391         protected String topSpeciesKey() {
392             return "";
393         }
394
395         @Override
396         protected BoundMethodHandle.SpeciesData newSpeciesData(String key) {
397             return new BoundMethodHandle.SpeciesData(this, key);
398         }
399
400         static final List<MemberName> BMH_TRANSFORMS;
401         static final int TN_COPY_NO_EXTEND = V_TYPE_NUM;
402         static {
403             final Class<BoundMethodHandle> BMH = BoundMethodHandle.class;
404             // copyWithExtendLIJFD + copyWith
405             try {
406                 BMH_TRANSFORMS = List.of(
407                         IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, BMH, "copyWithExtendL", MethodType.methodType(BMH, MethodType.class, LambdaForm.class, Object.class)),
408                         IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, BMH, "copyWithExtendI", MethodType.methodType(BMH, MethodType.class, LambdaForm.classint.class)),
409                         IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, BMH, "copyWithExtendJ", MethodType.methodType(BMH, MethodType.class, LambdaForm.classlong.class)),
410                         IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, BMH, "copyWithExtendF", MethodType.methodType(BMH, MethodType.class, LambdaForm.classfloat.class)),
411                         IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, BMH, "copyWithExtendD", MethodType.methodType(BMH, MethodType.class, LambdaForm.classdouble.class)),
412                         IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, BMH, "copyWith", MethodType.methodType(BMH, MethodType.class, LambdaForm.class))
413                 );
414             } catch (ReflectiveOperationException ex) {
415                 throw newInternalError("Failed resolving copyWith methods", ex);
416             }
417
418             // as it happens, there is one transform per BasicType including V_TYPE
419             assert(BMH_TRANSFORMS.size() == TYPE_LIMIT);
420         }
421
422         /**
423          * Generation of concrete BMH classes.
424          *
425          * A concrete BMH species is fit for binding a number of values adhering to a
426          * given type pattern. Reference types are erased.
427          *
428          * BMH species are cached by type pattern.
429          *
430          * A BMH species has a number of fields with the concrete (possibly erased) types of
431          * bound values. Setters are provided as an API in BMH. Getters are exposed as MHs,
432          * which can be included as names in lambda forms.
433          */

434         class Factory extends ClassSpecializer<BoundMethodHandle, String, BoundMethodHandle.SpeciesData>.Factory {
435             @Override
436             protected String chooseFieldName(Class<?> type, int index) {
437                 return "arg" + super.chooseFieldName(type, index);
438             }
439         }
440
441         @Override
442         protected Factory makeFactory() {
443             return new Factory();
444         }
445       }
446
447     static SpeciesData speciesData_L()      { return Species_L.BMH_SPECIES; }
448     static SpeciesData speciesData_LL()     { return SPECIALIZER.findSpecies("LL"); }
449     static SpeciesData speciesData_LLL()    { return SPECIALIZER.findSpecies("LLL"); }
450     static SpeciesData speciesData_LLLL()   { return SPECIALIZER.findSpecies("LLLL"); }
451     static SpeciesData speciesData_LLLLL()  { return SPECIALIZER.findSpecies("LLLLL"); }
452 }
453