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 static jdk.internal.org.objectweb.asm.Opcodes.*;
29 import static java.lang.invoke.LambdaForm.basicTypes;
30 import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeStatic;
31 import static java.lang.invoke.MethodHandleStatics.*;
32
33 import java.lang.invoke.LambdaForm.Name;
34 import java.lang.invoke.LambdaForm.NamedFunction;
35 import java.lang.invoke.MethodHandles.Lookup;
36 import java.lang.reflect.Field;
37 import java.util.Arrays;
38 import java.util.HashMap;
39
40 import sun.invoke.util.ValueConversions;
41 import sun.invoke.util.Wrapper;
42
43 import jdk.internal.org.objectweb.asm.ClassWriter;
44 import jdk.internal.org.objectweb.asm.MethodVisitor;
45 import jdk.internal.org.objectweb.asm.Type;
46
47 /**
48 * The flavor of method handle which emulates an invoke instruction
49 * on a predetermined argument. The JVM dispatches to the correct method
50 * when the handle is created, not when it is invoked.
51 *
52 * All bound arguments are encapsulated in dedicated species.
53 */
54 /* non-public */ abstract class BoundMethodHandle extends MethodHandle {
55
56 /* non-public */ BoundMethodHandle(MethodType type, LambdaForm form) {
57 super(type, form);
58 }
59
60 //
61 // BMH API and internals
62 //
63
64 static MethodHandle bindSingle(MethodType type, LambdaForm form, char xtype, Object x) {
65 // for some type signatures, there exist pre-defined concrete BMH classes
66 try {
67 switch (xtype) {
68 case 'L':
69 if (true) return bindSingle(type, form, x); // Use known fast path.
70 return (BoundMethodHandle) SpeciesData.EMPTY.extendWithType('L').constructor[0].invokeBasic(type, form, x);
71 case 'I':
72 return (BoundMethodHandle) SpeciesData.EMPTY.extendWithType('I').constructor[0].invokeBasic(type, form, ValueConversions.widenSubword(x));
73 case 'J':
74 return (BoundMethodHandle) SpeciesData.EMPTY.extendWithType('J').constructor[0].invokeBasic(type, form, (long) x);
75 case 'F':
76 return (BoundMethodHandle) SpeciesData.EMPTY.extendWithType('F').constructor[0].invokeBasic(type, form, (float) x);
77 case 'D':
78 return (BoundMethodHandle) SpeciesData.EMPTY.extendWithType('D').constructor[0].invokeBasic(type, form, (double) x);
79 default : throw new InternalError("unexpected xtype: " + xtype);
80 }
81 } catch (Throwable t) {
82 throw newInternalError(t);
83 }
84 }
85
86 static MethodHandle bindSingle(MethodType type, LambdaForm form, Object x) {
87 return new Species_L(type, form, x);
88 }
89
90 MethodHandle cloneExtend(MethodType type, LambdaForm form, char xtype, Object x) {
91 try {
92 switch (xtype) {
93 case 'L': return cloneExtendL(type, form, x);
94 case 'I': return cloneExtendI(type, form, ValueConversions.widenSubword(x));
95 case 'J': return cloneExtendJ(type, form, (long) x);
96 case 'F': return cloneExtendF(type, form, (float) x);
97 case 'D': return cloneExtendD(type, form, (double) x);
98 }
99 } catch (Throwable t) {
100 throw newInternalError(t);
101 }
102 throw new InternalError("unexpected type: " + xtype);
103 }
104
105 @Override
106 MethodHandle bindArgument(int pos, char basicType, Object value) {
107 MethodType type = type().dropParameterTypes(pos, pos+1);
108 LambdaForm form = internalForm().bind(1+pos, speciesData());
109 return cloneExtend(type, form, basicType, value);
110 }
111
112 @Override
113 MethodHandle dropArguments(MethodType srcType, int pos, int drops) {
114 LambdaForm form = internalForm().addArguments(pos, srcType.parameterList().subList(pos, pos+drops));
115 try {
116 return clone(srcType, form);
117 } catch (Throwable t) {
118 throw newInternalError(t);
119 }
120 }
121
122 @Override
123 MethodHandle permuteArguments(MethodType newType, int[] reorder) {
124 try {
125 return clone(newType, form.permuteArguments(1, reorder, basicTypes(newType.parameterList())));
126 } catch (Throwable t) {
127 throw newInternalError(t);
128 }
129 }
130
131 static final String EXTENSION_TYPES = "LIJFD";
132 static final byte INDEX_L = 0, INDEX_I = 1, INDEX_J = 2, INDEX_F = 3, INDEX_D = 4;
133 static byte extensionIndex(char type) {
134 int i = EXTENSION_TYPES.indexOf(type);
135 if (i < 0) throw new InternalError();
136 return (byte) i;
137 }
138
139 /**
140 * Return the {@link SpeciesData} instance representing this BMH species. All subclasses must provide a
141 * static field containing this value, and they must accordingly implement this method.
142 */
143 protected abstract SpeciesData speciesData();
144
145 @Override
146 final Object internalProperties() {
147 return "/BMH="+internalValues();
148 }
149
150 @Override
151 final Object internalValues() {
152 Object[] boundValues = new Object[speciesData().fieldCount()];
153 for (int i = 0; i < boundValues.length; ++i) {
154 boundValues[i] = arg(i);
155 }
156 return Arrays.asList(boundValues);
157 }
158
159 public final Object arg(int i) {
160 try {
161 switch (speciesData().fieldType(i)) {
162 case 'L': return argL(i);
163 case 'I': return argI(i);
164 case 'F': return argF(i);
165 case 'D': return argD(i);
166 case 'J': return argJ(i);
167 }
168 } catch (Throwable ex) {
169 throw newInternalError(ex);
170 }
171 throw new InternalError("unexpected type: " + speciesData().types+"."+i);
172 }
173 public final Object argL(int i) throws Throwable { return speciesData().getters[i].invokeBasic(this); }
174 public final int argI(int i) throws Throwable { return (int) speciesData().getters[i].invokeBasic(this); }
175 public final float argF(int i) throws Throwable { return (float) speciesData().getters[i].invokeBasic(this); }
176 public final double argD(int i) throws Throwable { return (double) speciesData().getters[i].invokeBasic(this); }
177 public final long argJ(int i) throws Throwable { return (long) speciesData().getters[i].invokeBasic(this); }
178
179 //
180 // cloning API
181 //
182
183 public abstract BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable;
184 public abstract BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable;
185 public abstract BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) throws Throwable;
186 public abstract BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) throws Throwable;
187 public abstract BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) throws Throwable;
188 public abstract BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable;
189
190 // The following is a grossly irregular hack:
191 @Override MethodHandle reinvokerTarget() {
192 try {
193 return (MethodHandle) argL(0);
194 } catch (Throwable ex) {
195 throw newInternalError(ex);
196 }
197 }
198
199 //
200 // concrete BMH classes required to close bootstrap loops
201 //
202
203 private // make it private to force users to access the enclosing class first
204 static final class Species_L extends BoundMethodHandle {
205 final Object argL0;
206 public Species_L(MethodType mt, LambdaForm lf, Object argL0) {
207 super(mt, lf);
208 this.argL0 = argL0;
209 }
210 // The following is a grossly irregular hack:
211 @Override MethodHandle reinvokerTarget() { return (MethodHandle) argL0; }
212 @Override
213 public SpeciesData speciesData() {
214 return SPECIES_DATA;
215 }
216 public static final SpeciesData SPECIES_DATA = SpeciesData.getForClass("L", Species_L.class);
217 @Override
218 public final BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable {
219 return new Species_L(mt, lf, argL0);
220 }
221 @Override
222 public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable {
223 return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_L).constructor[0].invokeBasic(mt, lf, argL0, narg);
224 }
225 @Override
226 public final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) throws Throwable {
227 return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_I).constructor[0].invokeBasic(mt, lf, argL0, narg);
228 }
229 @Override
230 public final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) throws Throwable {
231 return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_J).constructor[0].invokeBasic(mt, lf, argL0, narg);
232 }
233 @Override
234 public final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) throws Throwable {
235 return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_F).constructor[0].invokeBasic(mt, lf, argL0, narg);
236 }
237 @Override
238 public final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable {
239 return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_D).constructor[0].invokeBasic(mt, lf, argL0, narg);
240 }
241 }
242
243 /*
244 static final class Species_LL extends BoundMethodHandle {
245 final Object argL0;
246 final Object argL1;
247 public Species_LL(MethodType mt, LambdaForm lf, Object argL0, Object argL1) {
248 super(mt, lf);
249 this.argL0 = argL0;
250 this.argL1 = argL1;
251 }
252 @Override
253 public SpeciesData speciesData() {
254 return SPECIES_DATA;
255 }
256 public static final SpeciesData SPECIES_DATA = SpeciesData.getForClass("LL", Species_LL.class);
257 @Override
258 public final BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable {
259 return new Species_LL(mt, lf, argL0, argL1);
260 }
261 @Override
262 public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable {
263 return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_L).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
264 }
265 @Override
266 public final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) throws Throwable {
267 return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_I).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
268 }
269 @Override
270 public final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) throws Throwable {
271 return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_J).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
272 }
273 @Override
274 public final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) throws Throwable {
275 return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_F).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
276 }
277 @Override
278 public final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable {
279 return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_D).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
280 }
281 }
282
283 static final class Species_JL extends BoundMethodHandle {
284 final long argJ0;
285 final Object argL1;
286 public Species_JL(MethodType mt, LambdaForm lf, long argJ0, Object argL1) {
287 super(mt, lf);
288 this.argJ0 = argJ0;
289 this.argL1 = argL1;
290 }
291 @Override
292 public SpeciesData speciesData() {
293 return SPECIES_DATA;
294 }
295 public static final SpeciesData SPECIES_DATA = SpeciesData.getForClass("JL", Species_JL.class);
296 @Override public final long argJ0() { return argJ0; }
297 @Override public final Object argL1() { return argL1; }
298 @Override
299 public final BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable {
300 return new Species_JL(mt, lf, argJ0, argL1);
301 }
302 @Override
303 public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable {
304 return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_L).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
305 }
306 @Override
307 public final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) throws Throwable {
308 return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_I).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
309 }
310 @Override
311 public final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) throws Throwable {
312 return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_J).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
313 }
314 @Override
315 public final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) throws Throwable {
316 return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_F).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
317 }
318 @Override
319 public final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable {
320 return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_D).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
321 }
322 }
323 */
324
325 //
326 // BMH species meta-data
327 //
328
329 /**
330 * Meta-data wrapper for concrete BMH classes.
331 */
332 static class SpeciesData {
333 final String types;
334 final Class<? extends BoundMethodHandle> clazz;
335 // Bootstrapping requires circular relations MH -> BMH -> SpeciesData -> MH
336 // Therefore, we need a non-final link in the chain. Use array elements.
337 final MethodHandle[] constructor;
338 final MethodHandle[] getters;
339 final SpeciesData[] extensions;
340
341 public int fieldCount() {
342 return types.length();
343 }
344 public char fieldType(int i) {
345 return types.charAt(i);
346 }
347
348 public String toString() {
349 return "SpeciesData["+(isPlaceholder() ? "<placeholder>" : clazz.getSimpleName())+":"+types+"]";
350 }
351
352 /**
353 * Return a {@link LambdaForm.Name} containing a {@link LambdaForm.NamedFunction} that
354 * represents a MH bound to a generic invoker, which in turn forwards to the corresponding
355 * getter.
356 */
357 Name getterName(Name mhName, int i) {
358 MethodHandle mh = getters[i];
359 assert(mh != null) : this+"."+i;
360 return new Name(mh, mhName);
361 }
362
363 NamedFunction getterFunction(int i) {
364 return new NamedFunction(getters[i]);
365 }
366
367 static final SpeciesData EMPTY = new SpeciesData("", BoundMethodHandle.class);
368
369 private SpeciesData(String types, Class<? extends BoundMethodHandle> clazz) {
370 this.types = types;
371 this.clazz = clazz;
372 if (!INIT_DONE) {
373 this.constructor = new MethodHandle[1];
374 this.getters = new MethodHandle[types.length()];
375 } else {
376 this.constructor = Factory.makeCtors(clazz, types, null);
377 this.getters = Factory.makeGetters(clazz, types, null);
378 }
379 this.extensions = new SpeciesData[EXTENSION_TYPES.length()];
380 }
381
382 private void initForBootstrap() {
383 assert(!INIT_DONE);
384 if (constructor[0] == null) {
385 Factory.makeCtors(clazz, types, this.constructor);
386 Factory.makeGetters(clazz, types, this.getters);
387 }
388 }
389
390 private SpeciesData(String types) {
391 // Placeholder only.
392 this.types = types;
393 this.clazz = null;
394 this.constructor = null;
395 this.getters = null;
396 this.extensions = null;
397 }
398 private boolean isPlaceholder() { return clazz == null; }
399
400 private static final HashMap<String, SpeciesData> CACHE = new HashMap<>();
401 static { CACHE.put("", EMPTY); } // make bootstrap predictable
402 private static final boolean INIT_DONE; // set after <clinit> finishes...
403
404 SpeciesData extendWithType(char type) {
405 int i = extensionIndex(type);
406 SpeciesData d = extensions[i];
407 if (d != null) return d;
408 extensions[i] = d = get(types+type);
409 return d;
410 }
411
412 SpeciesData extendWithIndex(byte index) {
413 SpeciesData d = extensions[index];
414 if (d != null) return d;
415 extensions[index] = d = get(types+EXTENSION_TYPES.charAt(index));
416 return d;
417 }
418
419 private static SpeciesData get(String types) {
420 // Acquire cache lock for query.
421 SpeciesData d = lookupCache(types);
422 if (!d.isPlaceholder())
423 return d;
424 synchronized (d) {
425 // Use synch. on the placeholder to prevent multiple instantiation of one species.
426 // Creating this class forces a recursive call to getForClass.
427 if (lookupCache(types).isPlaceholder())
428 Factory.generateConcreteBMHClass(types);
429 }
430 // Reacquire cache lock.
431 d = lookupCache(types);
432 // Class loading must have upgraded the cache.
433 assert(d != null && !d.isPlaceholder());
434 return d;
435 }
439 }
440 private static synchronized SpeciesData lookupCache(String types) {
441 SpeciesData d = CACHE.get(types);
442 if (d != null) return d;
443 d = new SpeciesData(types);
444 assert(d.isPlaceholder());
445 CACHE.put(types, d);
446 return d;
447 }
448 private static synchronized SpeciesData updateCache(String types, SpeciesData d) {
449 SpeciesData d2;
450 assert((d2 = CACHE.get(types)) == null || d2.isPlaceholder());
451 assert(!d.isPlaceholder());
452 CACHE.put(types, d);
453 return d;
454 }
455
456 static {
457 // pre-fill the BMH speciesdata cache with BMH's inner classes
458 final Class<BoundMethodHandle> rootCls = BoundMethodHandle.class;
459 SpeciesData d0 = BoundMethodHandle.SPECIES_DATA; // trigger class init
460 assert(d0 == null || d0 == lookupCache("")) : d0;
461 try {
462 for (Class<?> c : rootCls.getDeclaredClasses()) {
463 if (rootCls.isAssignableFrom(c)) {
464 final Class<? extends BoundMethodHandle> cbmh = c.asSubclass(BoundMethodHandle.class);
465 SpeciesData d = Factory.speciesDataFromConcreteBMHClass(cbmh);
466 assert(d != null) : cbmh.getName();
467 assert(d.clazz == cbmh);
468 assert(d == lookupCache(d.types));
469 }
470 }
471 } catch (Throwable e) {
472 throw newInternalError(e);
473 }
474
475 for (SpeciesData d : CACHE.values()) {
476 d.initForBootstrap();
477 }
478 // Note: Do not simplify this, because INIT_DONE must not be
479 // a compile-time constant during bootstrapping.
480 INIT_DONE = Boolean.TRUE;
481 }
482 }
483
484 static SpeciesData getSpeciesData(String types) {
485 return SpeciesData.get(types);
486 }
487
488 /**
499 */
500 static class Factory {
501
502 static final String JLO_SIG = "Ljava/lang/Object;";
503 static final String JLS_SIG = "Ljava/lang/String;";
504 static final String JLC_SIG = "Ljava/lang/Class;";
505 static final String MH = "java/lang/invoke/MethodHandle";
506 static final String MH_SIG = "L"+MH+";";
507 static final String BMH = "java/lang/invoke/BoundMethodHandle";
508 static final String BMH_SIG = "L"+BMH+";";
509 static final String SPECIES_DATA = "java/lang/invoke/BoundMethodHandle$SpeciesData";
510 static final String SPECIES_DATA_SIG = "L"+SPECIES_DATA+";";
511
512 static final String SPECIES_PREFIX_NAME = "Species_";
513 static final String SPECIES_PREFIX_PATH = BMH + "$" + SPECIES_PREFIX_NAME;
514
515 static final String BMHSPECIES_DATA_EWI_SIG = "(B)" + SPECIES_DATA_SIG;
516 static final String BMHSPECIES_DATA_GFC_SIG = "(" + JLS_SIG + JLC_SIG + ")" + SPECIES_DATA_SIG;
517 static final String MYSPECIES_DATA_SIG = "()" + SPECIES_DATA_SIG;
518 static final String VOID_SIG = "()V";
519
520 static final String SIG_INCIPIT = "(Ljava/lang/invoke/MethodType;Ljava/lang/invoke/LambdaForm;";
521
522 static final Class<?>[] TYPES = new Class<?>[] { Object.class, int.class, long.class, float.class, double.class };
523
524 static final String[] E_THROWABLE = new String[] { "java/lang/Throwable" };
525
526 /**
527 * Generate a concrete subclass of BMH for a given combination of bound types.
528 *
529 * A concrete BMH species adheres to the following schema:
530 *
531 * <pre>
532 * class Species_[[types]] extends BoundMethodHandle {
533 * [[fields]]
534 * final SpeciesData speciesData() { return SpeciesData.get("[[types]]"); }
535 * }
536 * </pre>
537 *
538 * The {@code [[types]]} signature is precisely the string that is passed to this
539 * method.
540 *
541 * The {@code [[fields]]} section consists of one field definition per character in
542 * the type signature, adhering to the naming schema described in the definition of
543 * {@link #makeFieldName}.
544 *
545 * For example, a concrete BMH species for two reference and one integral bound values
546 * would have the following shape:
547 *
548 * <pre>
549 * class BoundMethodHandle { ... private static
550 * final class Species_LLI extends BoundMethodHandle {
551 * final Object argL0;
552 * final Object argL1;
553 * final int argI2;
554 * public Species_LLI(MethodType mt, LambdaForm lf, Object argL0, Object argL1, int argI2) {
555 * super(mt, lf);
556 * this.argL0 = argL0;
557 * this.argL1 = argL1;
558 * this.argI2 = argI2;
559 * }
560 * public final SpeciesData speciesData() { return SPECIES_DATA; }
561 * public static final SpeciesData SPECIES_DATA = SpeciesData.getForClass("LLI", Species_LLI.class);
562 * public final BoundMethodHandle clone(MethodType mt, LambdaForm lf) {
563 * return SPECIES_DATA.constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2);
564 * }
565 * public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) {
566 * return SPECIES_DATA.extendWithIndex(INDEX_L).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
567 * }
568 * public final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) {
569 * return SPECIES_DATA.extendWithIndex(INDEX_I).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
570 * }
571 * public final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) {
572 * return SPECIES_DATA.extendWithIndex(INDEX_J).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
573 * }
574 * public final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) {
575 * return SPECIES_DATA.extendWithIndex(INDEX_F).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
576 * }
577 * public final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) {
578 * return SPECIES_DATA.extendWithIndex(INDEX_D).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
579 * }
580 * }
581 * </pre>
582 *
583 * @param types the type signature, wherein reference types are erased to 'L'
584 * @return the generated concrete BMH class
585 */
586 static Class<? extends BoundMethodHandle> generateConcreteBMHClass(String types) {
587 final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
588
589 final String className = SPECIES_PREFIX_PATH + types;
590 final String sourceFile = SPECIES_PREFIX_NAME + types;
591 cw.visit(V1_6, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, className, null, BMH, null);
592 cw.visitSource(sourceFile, null);
593
594 // emit static types and SPECIES_DATA fields
595 cw.visitField(ACC_PUBLIC + ACC_STATIC, "SPECIES_DATA", SPECIES_DATA_SIG, null, null).visitEnd();
596
597 // emit bound argument fields
598 for (int i = 0; i < types.length(); ++i) {
599 final char t = types.charAt(i);
600 final String fieldName = makeFieldName(types, i);
601 final String fieldDesc = t == 'L' ? JLO_SIG : String.valueOf(t);
602 cw.visitField(ACC_FINAL, fieldName, fieldDesc, null, null).visitEnd();
603 }
604
605 MethodVisitor mv;
606
607 // emit constructor
608 mv = cw.visitMethod(ACC_PUBLIC, "<init>", makeSignature(types, true), null, null);
609 mv.visitCode();
610 mv.visitVarInsn(ALOAD, 0);
611 mv.visitVarInsn(ALOAD, 1);
612 mv.visitVarInsn(ALOAD, 2);
613
614 mv.visitMethodInsn(INVOKESPECIAL, BMH, "<init>", makeSignature("", true), false);
615
616 for (int i = 0, j = 0; i < types.length(); ++i, ++j) {
617 // i counts the arguments, j counts corresponding argument slots
618 char t = types.charAt(i);
619 mv.visitVarInsn(ALOAD, 0);
620 mv.visitVarInsn(typeLoadOp(t), j + 3); // parameters start at 3
621 mv.visitFieldInsn(PUTFIELD, className, makeFieldName(types, i), typeSig(t));
622 if (t == 'J' || t == 'D') {
623 ++j; // adjust argument register access
624 }
625 }
626
627 mv.visitInsn(RETURN);
628 mv.visitMaxs(0, 0);
629 mv.visitEnd();
630
631 // emit implementation of reinvokerTarget()
632 mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "reinvokerTarget", "()" + MH_SIG, null, null);
633 mv.visitCode();
634 mv.visitVarInsn(ALOAD, 0);
635 mv.visitFieldInsn(GETFIELD, className, "argL0", JLO_SIG);
636 mv.visitTypeInsn(CHECKCAST, MH);
637 mv.visitInsn(ARETURN);
638 mv.visitMaxs(0, 0);
639 mv.visitEnd();
640
641 // emit implementation of speciesData()
642 mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "speciesData", MYSPECIES_DATA_SIG, null, null);
643 mv.visitCode();
644 mv.visitFieldInsn(GETSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG);
645 mv.visitInsn(ARETURN);
646 mv.visitMaxs(0, 0);
647 mv.visitEnd();
648
649 // emit clone()
650 mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "clone", makeSignature("", false), null, E_THROWABLE);
651 mv.visitCode();
652 // return speciesData().constructor[0].invokeBasic(mt, lf, argL0, ...)
653 // obtain constructor
654 mv.visitVarInsn(ALOAD, 0);
655 mv.visitFieldInsn(GETSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG);
656 mv.visitFieldInsn(GETFIELD, SPECIES_DATA, "constructor", "[" + MH_SIG);
657 mv.visitInsn(ICONST_0);
658 mv.visitInsn(AALOAD);
659 // load mt, lf
660 mv.visitVarInsn(ALOAD, 1);
661 mv.visitVarInsn(ALOAD, 2);
662 // put fields on the stack
663 emitPushFields(types, className, mv);
664 // finally, invoke the constructor and return
665 mv.visitMethodInsn(INVOKEVIRTUAL, MH, "invokeBasic", makeSignature(types, false), false);
666 mv.visitInsn(ARETURN);
667 mv.visitMaxs(0, 0);
668 mv.visitEnd();
669
670 // for each type, emit cloneExtendT()
671 for (Class<?> c : TYPES) {
672 char t = Wrapper.basicTypeChar(c);
673 mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "cloneExtend" + t, makeSignature(String.valueOf(t), false), null, E_THROWABLE);
674 mv.visitCode();
675 // return SPECIES_DATA.extendWithIndex(extensionIndex(t)).constructor[0].invokeBasic(mt, lf, argL0, ..., narg)
676 // obtain constructor
677 mv.visitFieldInsn(GETSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG);
678 int iconstInsn = ICONST_0 + extensionIndex(t);
679 assert(iconstInsn <= ICONST_5);
680 mv.visitInsn(iconstInsn);
681 mv.visitMethodInsn(INVOKEVIRTUAL, SPECIES_DATA, "extendWithIndex", BMHSPECIES_DATA_EWI_SIG, false);
682 mv.visitFieldInsn(GETFIELD, SPECIES_DATA, "constructor", "[" + MH_SIG);
683 mv.visitInsn(ICONST_0);
684 mv.visitInsn(AALOAD);
685 // load mt, lf
686 mv.visitVarInsn(ALOAD, 1);
687 mv.visitVarInsn(ALOAD, 2);
688 // put fields on the stack
689 emitPushFields(types, className, mv);
690 // put narg on stack
691 mv.visitVarInsn(typeLoadOp(t), 3);
692 // finally, invoke the constructor and return
693 mv.visitMethodInsn(INVOKEVIRTUAL, MH, "invokeBasic", makeSignature(types + t, false), false);
694 mv.visitInsn(ARETURN);
695 mv.visitMaxs(0, 0);
696 mv.visitEnd();
697 }
698
699 // emit class initializer
700 mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "<clinit>", VOID_SIG, null, null);
701 mv.visitCode();
702 mv.visitLdcInsn(types);
703 mv.visitLdcInsn(Type.getObjectType(className));
704 mv.visitMethodInsn(INVOKESTATIC, SPECIES_DATA, "getForClass", BMHSPECIES_DATA_GFC_SIG, false);
705 mv.visitFieldInsn(PUTSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG);
706 mv.visitInsn(RETURN);
707 mv.visitMaxs(0, 0);
708 mv.visitEnd();
709
710 cw.visitEnd();
711
712 // load class
713 final byte[] classFile = cw.toByteArray();
714 InvokerBytecodeGenerator.maybeDump(className, classFile);
715 Class<? extends BoundMethodHandle> bmhClass =
716 //UNSAFE.defineAnonymousClass(BoundMethodHandle.class, classFile, null).asSubclass(BoundMethodHandle.class);
717 UNSAFE.defineClass(className, classFile, 0, classFile.length,
718 BoundMethodHandle.class.getClassLoader(), null)
719 .asSubclass(BoundMethodHandle.class);
720 UNSAFE.ensureClassInitialized(bmhClass);
721
722 return bmhClass;
723 }
724
725 private static int typeLoadOp(char t) {
726 switch (t) {
727 case 'L': return ALOAD;
728 case 'I': return ILOAD;
729 case 'J': return LLOAD;
730 case 'F': return FLOAD;
731 case 'D': return DLOAD;
732 default : throw new InternalError("unrecognized type " + t);
733 }
734 }
735
736 private static void emitPushFields(String types, String className, MethodVisitor mv) {
737 for (int i = 0; i < types.length(); ++i) {
738 char tc = types.charAt(i);
739 mv.visitVarInsn(ALOAD, 0);
740 mv.visitFieldInsn(GETFIELD, className, makeFieldName(types, i), typeSig(tc));
741 }
742 }
743
744 static String typeSig(char t) {
745 return t == 'L' ? JLO_SIG : String.valueOf(t);
746 }
747
748 //
749 // Getter MH generation.
750 //
751
752 private static MethodHandle makeGetter(Class<?> cbmhClass, String types, int index) {
753 String fieldName = makeFieldName(types, index);
754 Class<?> fieldType = Wrapper.forBasicType(types.charAt(index)).primitiveType();
755 try {
756 return LOOKUP.findGetter(cbmhClass, fieldName, fieldType);
757 } catch (NoSuchFieldException | IllegalAccessException e) {
758 throw newInternalError(e);
759 }
760 }
761
762 static MethodHandle[] makeGetters(Class<?> cbmhClass, String types, MethodHandle[] mhs) {
763 if (mhs == null) mhs = new MethodHandle[types.length()];
764 for (int i = 0; i < mhs.length; ++i) {
765 mhs[i] = makeGetter(cbmhClass, types, i);
766 assert(mhs[i].internalMemberName().getDeclaringClass() == cbmhClass);
767 }
768 return mhs;
769 }
770
771 static MethodHandle[] makeCtors(Class<? extends BoundMethodHandle> cbmh, String types, MethodHandle mhs[]) {
772 if (mhs == null) mhs = new MethodHandle[1];
773 mhs[0] = makeCbmhCtor(cbmh, types);
774 return mhs;
775 }
776
777 //
778 // Auxiliary methods.
779 //
780
781 static SpeciesData speciesDataFromConcreteBMHClass(Class<? extends BoundMethodHandle> cbmh) {
782 try {
783 Field F_SPECIES_DATA = cbmh.getDeclaredField("SPECIES_DATA");
784 return (SpeciesData) F_SPECIES_DATA.get(null);
785 } catch (ReflectiveOperationException ex) {
786 throw newInternalError(ex);
787 }
788 }
789
790 /**
791 * Field names in concrete BMHs adhere to this pattern:
792 * arg + type + index
793 * where type is a single character (L, I, J, F, D).
794 */
795 private static String makeFieldName(String types, int index) {
796 assert index >= 0 && index < types.length();
797 return "arg" + types.charAt(index) + index;
798 }
799
800 private static String makeSignature(String types, boolean ctor) {
801 StringBuilder buf = new StringBuilder(SIG_INCIPIT);
802 for (char c : types.toCharArray()) {
803 buf.append(typeSig(c));
804 }
805 return buf.append(')').append(ctor ? "V" : BMH_SIG).toString();
806 }
807
808 static MethodHandle makeCbmhCtor(Class<? extends BoundMethodHandle> cbmh, String types) {
809 try {
810 return linkConstructor(LOOKUP.findConstructor(cbmh, MethodType.fromMethodDescriptorString(makeSignature(types, true), null)));
811 } catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException | TypeNotPresentException e) {
812 throw newInternalError(e);
813 }
814 }
815
816 /**
817 * Wrap a constructor call in a {@link LambdaForm}.
818 *
819 * If constructors ({@code <init>} methods) are called in LFs, problems might arise if the LFs
820 * are turned into bytecode, because the call to the allocator is routed through an MH, and the
821 * verifier cannot find a {@code NEW} instruction preceding the {@code INVOKESPECIAL} to
822 * {@code <init>}. To avoid this, we add an indirection by invoking {@code <init>} through
823 * {@link MethodHandle#linkToSpecial}.
824 *
825 * The last {@link LambdaForm.Name Name} in the argument's form is expected to be the {@code void}
826 * result of the {@code <init>} invocation. This entry is replaced.
827 */
828 private static MethodHandle linkConstructor(MethodHandle cmh) {
829 final LambdaForm lf = cmh.form;
830 final int initNameIndex = lf.names.length - 1;
831 final Name initName = lf.names[initNameIndex];
832 final MemberName ctorMN = initName.function.member;
833 final MethodType ctorMT = ctorMN.getInvocationType();
834
835 // obtain function member (call target)
836 // linker method type replaces initial parameter (BMH species) with BMH to avoid naming a species (anonymous class!)
837 final MethodType linkerMT = ctorMT.changeParameterType(0, BoundMethodHandle.class).appendParameterTypes(MemberName.class);
838 MemberName linkerMN = new MemberName(MethodHandle.class, "linkToSpecial", linkerMT, REF_invokeStatic);
839 try {
840 linkerMN = MemberName.getFactory().resolveOrFail(REF_invokeStatic, linkerMN, null, NoSuchMethodException.class);
841 assert(linkerMN.isStatic());
842 } catch (ReflectiveOperationException ex) {
843 throw newInternalError(ex);
844 }
845 // extend arguments array
846 Object[] newArgs = Arrays.copyOf(initName.arguments, initName.arguments.length + 1);
847 newArgs[newArgs.length - 1] = ctorMN;
848 // replace function
849 final NamedFunction nf = new NamedFunction(linkerMN);
850 final Name linkedCtor = new Name(nf, newArgs);
851 linkedCtor.initIndex(initNameIndex);
852 lf.names[initNameIndex] = linkedCtor;
853 return cmh;
854 }
855
856 }
857
858 private static final Lookup LOOKUP = Lookup.IMPL_LOOKUP;
859
860 /**
861 * All subclasses must provide such a value describing their type signature.
862 */
863 static final SpeciesData SPECIES_DATA = SpeciesData.EMPTY;
864
865 private static final SpeciesData[] SPECIES_DATA_CACHE = new SpeciesData[5];
866 private static SpeciesData checkCache(int size, String types) {
867 int idx = size - 1;
868 SpeciesData data = SPECIES_DATA_CACHE[idx];
869 if (data != null) return data;
870 SPECIES_DATA_CACHE[idx] = data = getSpeciesData(types);
871 return data;
872 }
873 static SpeciesData speciesData_L() { return checkCache(1, "L"); }
874 static SpeciesData speciesData_LL() { return checkCache(2, "LL"); }
875 static SpeciesData speciesData_LLL() { return checkCache(3, "LLL"); }
|
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 static jdk.internal.org.objectweb.asm.Opcodes.*;
29 import static java.lang.invoke.LambdaForm.*;
30 import static java.lang.invoke.LambdaForm.BasicType.*;
31 import static java.lang.invoke.MethodHandleStatics.*;
32
33 import java.lang.invoke.LambdaForm.NamedFunction;
34 import java.lang.invoke.MethodHandles.Lookup;
35 import java.lang.reflect.Field;
36 import java.util.Arrays;
37 import java.util.HashMap;
38
39 import sun.invoke.util.ValueConversions;
40 import sun.invoke.util.Wrapper;
41
42 import jdk.internal.org.objectweb.asm.ClassWriter;
43 import jdk.internal.org.objectweb.asm.MethodVisitor;
44 import jdk.internal.org.objectweb.asm.Type;
45
46 /**
47 * The flavor of method handle which emulates an invoke instruction
48 * on a predetermined argument. The JVM dispatches to the correct method
49 * when the handle is created, not when it is invoked.
50 *
51 * All bound arguments are encapsulated in dedicated species.
52 */
53 /* non-public */ abstract class BoundMethodHandle extends MethodHandle {
54
55 /* non-public */ BoundMethodHandle(MethodType type, LambdaForm form) {
56 super(type, form);
57 }
58
59 //
60 // BMH API and internals
61 //
62
63 static MethodHandle bindSingle(MethodType type, LambdaForm form, BasicType xtype, Object x) {
64 // for some type signatures, there exist pre-defined concrete BMH classes
65 try {
66 switch (xtype) {
67 case L_TYPE:
68 if (true) return bindSingle(type, form, x); // Use known fast path.
69 return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(L_TYPE).constructor[0].invokeBasic(type, form, x);
70 case I_TYPE:
71 return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(I_TYPE).constructor[0].invokeBasic(type, form, ValueConversions.widenSubword(x));
72 case J_TYPE:
73 return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(J_TYPE).constructor[0].invokeBasic(type, form, (long) x);
74 case F_TYPE:
75 return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(F_TYPE).constructor[0].invokeBasic(type, form, (float) x);
76 case D_TYPE:
77 return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(D_TYPE).constructor[0].invokeBasic(type, form, (double) x);
78 default : throw newInternalError("unexpected xtype: " + xtype);
79 }
80 } catch (Throwable t) {
81 throw newInternalError(t);
82 }
83 }
84
85 static MethodHandle bindSingle(MethodType type, LambdaForm form, Object x) {
86 return new Species_L(type, form, x);
87 }
88
89 MethodHandle cloneExtend(MethodType type, LambdaForm form, BasicType xtype, Object x) {
90 try {
91 switch (xtype) {
92 case L_TYPE: return copyWithExtendL(type, form, x);
93 case I_TYPE: return copyWithExtendI(type, form, ValueConversions.widenSubword(x));
94 case J_TYPE: return copyWithExtendJ(type, form, (long) x);
95 case F_TYPE: return copyWithExtendF(type, form, (float) x);
96 case D_TYPE: return copyWithExtendD(type, form, (double) x);
97 }
98 } catch (Throwable t) {
99 throw newInternalError(t);
100 }
101 throw newInternalError("unexpected type: " + xtype);
102 }
103
104 @Override
105 MethodHandle bindArgument(int pos, BasicType basicType, Object value) {
106 MethodType type = type().dropParameterTypes(pos, pos+1);
107 LambdaForm form = internalForm().bind(1+pos, speciesData());
108 return cloneExtend(type, form, basicType, value);
109 }
110
111 @Override
112 MethodHandle dropArguments(MethodType srcType, int pos, int drops) {
113 LambdaForm form = internalForm().addArguments(pos, srcType.parameterList().subList(pos, pos + drops));
114 try {
115 return copyWith(srcType, form);
116 } catch (Throwable t) {
117 throw newInternalError(t);
118 }
119 }
120
121 @Override
122 MethodHandle permuteArguments(MethodType newType, int[] reorder) {
123 try {
124 return copyWith(newType, form.permuteArguments(1, reorder, basicTypes(newType.parameterList())));
125 } catch (Throwable t) {
126 throw newInternalError(t);
127 }
128 }
129
130 /**
131 * Return the {@link SpeciesData} instance representing this BMH species. All subclasses must provide a
132 * static field containing this value, and they must accordingly implement this method.
133 */
134 public abstract SpeciesData speciesData();
135
136 /**
137 * Return the number of fields in this BMH. Equivalent to speciesData().fieldCount().
138 */
139 public abstract int fieldCount();
140
141 @Override
142 final Object internalProperties() {
143 return "/BMH="+internalValues();
144 }
145
146 @Override
147 final Object internalValues() {
148 Object[] boundValues = new Object[speciesData().fieldCount()];
149 for (int i = 0; i < boundValues.length; ++i) {
150 boundValues[i] = arg(i);
151 }
152 return Arrays.asList(boundValues);
153 }
154
155 public final Object arg(int i) {
156 try {
157 switch (speciesData().fieldType(i)) {
158 case L_TYPE: return speciesData().getters[i].invokeBasic(this);
159 case I_TYPE: return (int) speciesData().getters[i].invokeBasic(this);
160 case J_TYPE: return (long) speciesData().getters[i].invokeBasic(this);
161 case F_TYPE: return (float) speciesData().getters[i].invokeBasic(this);
162 case D_TYPE: return (double) speciesData().getters[i].invokeBasic(this);
163 }
164 } catch (Throwable ex) {
165 throw newInternalError(ex);
166 }
167 throw new InternalError("unexpected type: " + speciesData().typeChars+"."+i);
168 }
169
170 //
171 // cloning API
172 //
173
174 // The following is a grossly irregular hack:
175 @Override MethodHandle reinvokerTarget() {
176 try {
177 return (MethodHandle) arg(0);
178 } catch (Throwable ex) {
179 throw newInternalError(ex);
180 }
181 }
182
183 public abstract BoundMethodHandle copyWith(MethodType mt, LambdaForm lf);
184 public abstract BoundMethodHandle copyWithExtendL(MethodType mt, LambdaForm lf, Object narg);
185 public abstract BoundMethodHandle copyWithExtendI(MethodType mt, LambdaForm lf, int narg);
186 public abstract BoundMethodHandle copyWithExtendJ(MethodType mt, LambdaForm lf, long narg);
187 public abstract BoundMethodHandle copyWithExtendF(MethodType mt, LambdaForm lf, float narg);
188 public abstract BoundMethodHandle copyWithExtendD(MethodType mt, LambdaForm lf, double narg);
189
190 //
191 // concrete BMH classes required to close bootstrap loops
192 //
193
194 private // make it private to force users to access the enclosing class first
195 static final class Species_L extends BoundMethodHandle {
196 final Object argL0;
197 private Species_L(MethodType mt, LambdaForm lf, Object argL0) {
198 super(mt, lf);
199 this.argL0 = argL0;
200 }
201 @Override
202 public SpeciesData speciesData() {
203 return SPECIES_DATA;
204 }
205 @Override
206 public int fieldCount() {
207 return 1;
208 }
209 public static final SpeciesData SPECIES_DATA = SpeciesData.getForClass("L", Species_L.class);
210 public static BoundMethodHandle make(MethodType mt, LambdaForm lf, Object argL0) {
211 return new Species_L(mt, lf, argL0);
212 }
213 @Override
214 public final BoundMethodHandle copyWith(MethodType mt, LambdaForm lf) {
215 return new Species_L(mt, lf, argL0);
216 }
217 @Override
218 public final BoundMethodHandle copyWithExtendL(MethodType mt, LambdaForm lf, Object narg) {
219 try {
220 return (BoundMethodHandle) SPECIES_DATA.extendWith(L_TYPE).constructor[0].invokeBasic(mt, lf, argL0, narg);
221 } catch (Throwable ex) {
222 throw uncaughtException(ex);
223 }
224 }
225 @Override
226 public final BoundMethodHandle copyWithExtendI(MethodType mt, LambdaForm lf, int narg) {
227 try {
228 return (BoundMethodHandle) SPECIES_DATA.extendWith(I_TYPE).constructor[0].invokeBasic(mt, lf, argL0, narg);
229 } catch (Throwable ex) {
230 throw uncaughtException(ex);
231 }
232 }
233 @Override
234 public final BoundMethodHandle copyWithExtendJ(MethodType mt, LambdaForm lf, long narg) {
235 try {
236 return (BoundMethodHandle) SPECIES_DATA.extendWith(J_TYPE).constructor[0].invokeBasic(mt, lf, argL0, narg);
237 } catch (Throwable ex) {
238 throw uncaughtException(ex);
239 }
240 }
241 @Override
242 public final BoundMethodHandle copyWithExtendF(MethodType mt, LambdaForm lf, float narg) {
243 try {
244 return (BoundMethodHandle) SPECIES_DATA.extendWith(F_TYPE).constructor[0].invokeBasic(mt, lf, argL0, narg);
245 } catch (Throwable ex) {
246 throw uncaughtException(ex);
247 }
248 }
249 @Override
250 public final BoundMethodHandle copyWithExtendD(MethodType mt, LambdaForm lf, double narg) {
251 try {
252 return (BoundMethodHandle) SPECIES_DATA.extendWith(D_TYPE).constructor[0].invokeBasic(mt, lf, argL0, narg);
253 } catch (Throwable ex) {
254 throw uncaughtException(ex);
255 }
256 }
257 }
258
259 //
260 // BMH species meta-data
261 //
262
263 /**
264 * Meta-data wrapper for concrete BMH types.
265 * Each BMH type corresponds to a given sequence of basic field types (LIJFD).
266 * The fields are immutable; their values are fully specified at object construction.
267 * Each BMH type supplies an array of getter functions which may be used in lambda forms.
268 * A BMH is constructed by cloning a shorter BMH and adding one or more new field values.
269 * As a degenerate and common case, the "shorter BMH" can be missing, and contributes zero prior fields.
270 */
271 static class SpeciesData {
272 final String typeChars;
273 final BasicType[] typeCodes;
274 final Class<? extends BoundMethodHandle> clazz;
275 // Bootstrapping requires circular relations MH -> BMH -> SpeciesData -> MH
276 // Therefore, we need a non-final link in the chain. Use array elements.
277 final MethodHandle[] constructor;
278 final MethodHandle[] getters;
279 final NamedFunction[] nominalGetters;
280 final SpeciesData[] extensions;
281
282 public int fieldCount() {
283 return typeCodes.length;
284 }
285 public BasicType fieldType(int i) {
286 return typeCodes[i];
287 }
288 public char fieldTypeChar(int i) {
289 return typeChars.charAt(i);
290 }
291
292 public String toString() {
293 return "SpeciesData["+(isPlaceholder() ? "<placeholder>" : clazz.getSimpleName())+":"+typeChars+"]";
294 }
295
296 /**
297 * Return a {@link LambdaForm.Name} containing a {@link LambdaForm.NamedFunction} that
298 * represents a MH bound to a generic invoker, which in turn forwards to the corresponding
299 * getter.
300 */
301 NamedFunction getterFunction(int i) {
302 return nominalGetters[i];
303 }
304
305 static final SpeciesData EMPTY = new SpeciesData("", BoundMethodHandle.class);
306
307 private SpeciesData(String types, Class<? extends BoundMethodHandle> clazz) {
308 this.typeChars = types;
309 this.typeCodes = basicTypes(types);
310 this.clazz = clazz;
311 if (!INIT_DONE) {
312 this.constructor = new MethodHandle[1]; // only one ctor
313 this.getters = new MethodHandle[types.length()];
314 this.nominalGetters = new NamedFunction[types.length()];
315 } else {
316 this.constructor = Factory.makeCtors(clazz, types, null);
317 this.getters = Factory.makeGetters(clazz, types, null);
318 this.nominalGetters = Factory.makeNominalGetters(types, null, this.getters);
319 }
320 this.extensions = new SpeciesData[ARG_TYPE_LIMIT];
321 }
322
323 private void initForBootstrap() {
324 assert(!INIT_DONE);
325 if (constructor[0] == null) {
326 String types = typeChars;
327 Factory.makeCtors(clazz, types, this.constructor);
328 Factory.makeGetters(clazz, types, this.getters);
329 Factory.makeNominalGetters(types, this.nominalGetters, this.getters);
330 }
331 }
332
333 private SpeciesData(String typeChars) {
334 // Placeholder only.
335 this.typeChars = typeChars;
336 this.typeCodes = basicTypes(typeChars);
337 this.clazz = null;
338 this.constructor = null;
339 this.getters = null;
340 this.nominalGetters = null;
341 this.extensions = null;
342 }
343 private boolean isPlaceholder() { return clazz == null; }
344
345 private static final HashMap<String, SpeciesData> CACHE = new HashMap<>();
346 static { CACHE.put("", EMPTY); } // make bootstrap predictable
347 private static final boolean INIT_DONE; // set after <clinit> finishes...
348
349 SpeciesData extendWith(byte type) {
350 return extendWith(BasicType.basicType(type));
351 }
352
353 SpeciesData extendWith(BasicType type) {
354 int ord = type.ordinal();
355 SpeciesData d = extensions[ord];
356 if (d != null) return d;
357 extensions[ord] = d = get(typeChars+type.basicTypeChar());
358 return d;
359 }
360
361 private static SpeciesData get(String types) {
362 // Acquire cache lock for query.
363 SpeciesData d = lookupCache(types);
364 if (!d.isPlaceholder())
365 return d;
366 synchronized (d) {
367 // Use synch. on the placeholder to prevent multiple instantiation of one species.
368 // Creating this class forces a recursive call to getForClass.
369 if (lookupCache(types).isPlaceholder())
370 Factory.generateConcreteBMHClass(types);
371 }
372 // Reacquire cache lock.
373 d = lookupCache(types);
374 // Class loading must have upgraded the cache.
375 assert(d != null && !d.isPlaceholder());
376 return d;
377 }
381 }
382 private static synchronized SpeciesData lookupCache(String types) {
383 SpeciesData d = CACHE.get(types);
384 if (d != null) return d;
385 d = new SpeciesData(types);
386 assert(d.isPlaceholder());
387 CACHE.put(types, d);
388 return d;
389 }
390 private static synchronized SpeciesData updateCache(String types, SpeciesData d) {
391 SpeciesData d2;
392 assert((d2 = CACHE.get(types)) == null || d2.isPlaceholder());
393 assert(!d.isPlaceholder());
394 CACHE.put(types, d);
395 return d;
396 }
397
398 static {
399 // pre-fill the BMH speciesdata cache with BMH's inner classes
400 final Class<BoundMethodHandle> rootCls = BoundMethodHandle.class;
401 try {
402 for (Class<?> c : rootCls.getDeclaredClasses()) {
403 if (rootCls.isAssignableFrom(c)) {
404 final Class<? extends BoundMethodHandle> cbmh = c.asSubclass(BoundMethodHandle.class);
405 SpeciesData d = Factory.speciesDataFromConcreteBMHClass(cbmh);
406 assert(d != null) : cbmh.getName();
407 assert(d.clazz == cbmh);
408 assert(d == lookupCache(d.typeChars));
409 }
410 }
411 } catch (Throwable e) {
412 throw newInternalError(e);
413 }
414
415 for (SpeciesData d : CACHE.values()) {
416 d.initForBootstrap();
417 }
418 // Note: Do not simplify this, because INIT_DONE must not be
419 // a compile-time constant during bootstrapping.
420 INIT_DONE = Boolean.TRUE;
421 }
422 }
423
424 static SpeciesData getSpeciesData(String types) {
425 return SpeciesData.get(types);
426 }
427
428 /**
439 */
440 static class Factory {
441
442 static final String JLO_SIG = "Ljava/lang/Object;";
443 static final String JLS_SIG = "Ljava/lang/String;";
444 static final String JLC_SIG = "Ljava/lang/Class;";
445 static final String MH = "java/lang/invoke/MethodHandle";
446 static final String MH_SIG = "L"+MH+";";
447 static final String BMH = "java/lang/invoke/BoundMethodHandle";
448 static final String BMH_SIG = "L"+BMH+";";
449 static final String SPECIES_DATA = "java/lang/invoke/BoundMethodHandle$SpeciesData";
450 static final String SPECIES_DATA_SIG = "L"+SPECIES_DATA+";";
451
452 static final String SPECIES_PREFIX_NAME = "Species_";
453 static final String SPECIES_PREFIX_PATH = BMH + "$" + SPECIES_PREFIX_NAME;
454
455 static final String BMHSPECIES_DATA_EWI_SIG = "(B)" + SPECIES_DATA_SIG;
456 static final String BMHSPECIES_DATA_GFC_SIG = "(" + JLS_SIG + JLC_SIG + ")" + SPECIES_DATA_SIG;
457 static final String MYSPECIES_DATA_SIG = "()" + SPECIES_DATA_SIG;
458 static final String VOID_SIG = "()V";
459 static final String INT_SIG = "()I";
460
461 static final String SIG_INCIPIT = "(Ljava/lang/invoke/MethodType;Ljava/lang/invoke/LambdaForm;";
462
463 static final String[] E_THROWABLE = new String[] { "java/lang/Throwable" };
464
465 /**
466 * Generate a concrete subclass of BMH for a given combination of bound types.
467 *
468 * A concrete BMH species adheres to the following schema:
469 *
470 * <pre>
471 * class Species_[[types]] extends BoundMethodHandle {
472 * [[fields]]
473 * final SpeciesData speciesData() { return SpeciesData.get("[[types]]"); }
474 * }
475 * </pre>
476 *
477 * The {@code [[types]]} signature is precisely the string that is passed to this
478 * method.
479 *
480 * The {@code [[fields]]} section consists of one field definition per character in
481 * the type signature, adhering to the naming schema described in the definition of
482 * {@link #makeFieldName}.
483 *
484 * For example, a concrete BMH species for two reference and one integral bound values
485 * would have the following shape:
486 *
487 * <pre>
488 * class BoundMethodHandle { ... private static
489 * final class Species_LLI extends BoundMethodHandle {
490 * final Object argL0;
491 * final Object argL1;
492 * final int argI2;
493 * private Species_LLI(MethodType mt, LambdaForm lf, Object argL0, Object argL1, int argI2) {
494 * super(mt, lf);
495 * this.argL0 = argL0;
496 * this.argL1 = argL1;
497 * this.argI2 = argI2;
498 * }
499 * public final SpeciesData speciesData() { return SPECIES_DATA; }
500 * public final int fieldCount() { return 3; }
501 * public static final SpeciesData SPECIES_DATA = SpeciesData.getForClass("LLI", Species_LLI.class);
502 * public BoundMethodHandle make(MethodType mt, LambdaForm lf, Object argL0, Object argL1, int argI2) {
503 * return new Species_LLI(mt, lf, argL0, argL1, argI2);
504 * }
505 * public final BoundMethodHandle copyWith(MethodType mt, LambdaForm lf) {
506 * return new Species_LLI(mt, lf, argL0, argL1, argI2);
507 * }
508 * public final BoundMethodHandle copyWithExtendL(MethodType mt, LambdaForm lf, Object narg) {
509 * return SPECIES_DATA.extendWith(L_TYPE).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
510 * }
511 * public final BoundMethodHandle copyWithExtendI(MethodType mt, LambdaForm lf, int narg) {
512 * return SPECIES_DATA.extendWith(I_TYPE).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
513 * }
514 * public final BoundMethodHandle copyWithExtendJ(MethodType mt, LambdaForm lf, long narg) {
515 * return SPECIES_DATA.extendWith(J_TYPE).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
516 * }
517 * public final BoundMethodHandle copyWithExtendF(MethodType mt, LambdaForm lf, float narg) {
518 * return SPECIES_DATA.extendWith(F_TYPE).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
519 * }
520 * public final BoundMethodHandle copyWithExtendD(MethodType mt, LambdaForm lf, double narg) {
521 * return SPECIES_DATA.extendWith(D_TYPE).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
522 * }
523 * }
524 * </pre>
525 *
526 * @param types the type signature, wherein reference types are erased to 'L'
527 * @return the generated concrete BMH class
528 */
529 static Class<? extends BoundMethodHandle> generateConcreteBMHClass(String types) {
530 final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
531
532 String shortTypes = LambdaForm.shortenSignature(types);
533 final String className = SPECIES_PREFIX_PATH + shortTypes;
534 final String sourceFile = SPECIES_PREFIX_NAME + shortTypes;
535 cw.visit(V1_6, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, className, null, BMH, null);
536 cw.visitSource(sourceFile, null);
537
538 // emit static types and SPECIES_DATA fields
539 cw.visitField(ACC_PUBLIC + ACC_STATIC, "SPECIES_DATA", SPECIES_DATA_SIG, null, null).visitEnd();
540
541 // emit bound argument fields
542 for (int i = 0; i < types.length(); ++i) {
543 final char t = types.charAt(i);
544 final String fieldName = makeFieldName(types, i);
545 final String fieldDesc = t == 'L' ? JLO_SIG : String.valueOf(t);
546 cw.visitField(ACC_FINAL, fieldName, fieldDesc, null, null).visitEnd();
547 }
548
549 MethodVisitor mv;
550
551 // emit constructor
552 mv = cw.visitMethod(ACC_PRIVATE, "<init>", makeSignature(types, true), null, null);
553 mv.visitCode();
554 mv.visitVarInsn(ALOAD, 0); // this
555 mv.visitVarInsn(ALOAD, 1); // type
556 mv.visitVarInsn(ALOAD, 2); // form
557
558 mv.visitMethodInsn(INVOKESPECIAL, BMH, "<init>", makeSignature("", true), false);
559
560 for (int i = 0, j = 0; i < types.length(); ++i, ++j) {
561 // i counts the arguments, j counts corresponding argument slots
562 char t = types.charAt(i);
563 mv.visitVarInsn(ALOAD, 0);
564 mv.visitVarInsn(typeLoadOp(t), j + 3); // parameters start at 3
565 mv.visitFieldInsn(PUTFIELD, className, makeFieldName(types, i), typeSig(t));
566 if (t == 'J' || t == 'D') {
567 ++j; // adjust argument register access
568 }
569 }
570
571 mv.visitInsn(RETURN);
572 mv.visitMaxs(0, 0);
573 mv.visitEnd();
574
575 // emit implementation of speciesData()
576 mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "speciesData", MYSPECIES_DATA_SIG, null, null);
577 mv.visitCode();
578 mv.visitFieldInsn(GETSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG);
579 mv.visitInsn(ARETURN);
580 mv.visitMaxs(0, 0);
581 mv.visitEnd();
582
583 // emit implementation of fieldCount()
584 mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "fieldCount", INT_SIG, null, null);
585 mv.visitCode();
586 int fc = types.length();
587 if (fc <= (ICONST_5 - ICONST_0)) {
588 mv.visitInsn(ICONST_0 + fc);
589 } else {
590 mv.visitIntInsn(SIPUSH, fc);
591 }
592 mv.visitInsn(IRETURN);
593 mv.visitMaxs(0, 0);
594 mv.visitEnd();
595 // emit make() ...factory method wrapping constructor
596 mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "make", makeSignature(types, false), null, null);
597 mv.visitCode();
598 // make instance
599 mv.visitTypeInsn(NEW, className);
600 mv.visitInsn(DUP);
601 // load mt, lf
602 mv.visitVarInsn(ALOAD, 0); // type
603 mv.visitVarInsn(ALOAD, 1); // form
604 // load factory method arguments
605 for (int i = 0, j = 0; i < types.length(); ++i, ++j) {
606 // i counts the arguments, j counts corresponding argument slots
607 char t = types.charAt(i);
608 mv.visitVarInsn(typeLoadOp(t), j + 2); // parameters start at 3
609 if (t == 'J' || t == 'D') {
610 ++j; // adjust argument register access
611 }
612 }
613
614 // finally, invoke the constructor and return
615 mv.visitMethodInsn(INVOKESPECIAL, className, "<init>", makeSignature(types, true), false);
616 mv.visitInsn(ARETURN);
617 mv.visitMaxs(0, 0);
618 mv.visitEnd();
619
620 // emit copyWith()
621 mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "copyWith", makeSignature("", false), null, null);
622 mv.visitCode();
623 // make instance
624 mv.visitTypeInsn(NEW, className);
625 mv.visitInsn(DUP);
626 // load mt, lf
627 mv.visitVarInsn(ALOAD, 1);
628 mv.visitVarInsn(ALOAD, 2);
629 // put fields on the stack
630 emitPushFields(types, className, mv);
631 // finally, invoke the constructor and return
632 mv.visitMethodInsn(INVOKESPECIAL, className, "<init>", makeSignature(types, true), false);
633 mv.visitInsn(ARETURN);
634 mv.visitMaxs(0, 0);
635 mv.visitEnd();
636
637 // for each type, emit copyWithExtendT()
638 for (BasicType type : BasicType.ARG_TYPES) {
639 int ord = type.ordinal();
640 char btChar = type.basicTypeChar();
641 mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "copyWithExtend" + btChar, makeSignature(String.valueOf(btChar), false), null, E_THROWABLE);
642 mv.visitCode();
643 // return SPECIES_DATA.extendWith(t).constructor[0].invokeBasic(mt, lf, argL0, ..., narg)
644 // obtain constructor
645 mv.visitFieldInsn(GETSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG);
646 int iconstInsn = ICONST_0 + ord;
647 assert(iconstInsn <= ICONST_5);
648 mv.visitInsn(iconstInsn);
649 mv.visitMethodInsn(INVOKEVIRTUAL, SPECIES_DATA, "extendWith", BMHSPECIES_DATA_EWI_SIG, false);
650 mv.visitFieldInsn(GETFIELD, SPECIES_DATA, "constructor", "[" + MH_SIG);
651 mv.visitInsn(ICONST_0);
652 mv.visitInsn(AALOAD);
653 // load mt, lf
654 mv.visitVarInsn(ALOAD, 1);
655 mv.visitVarInsn(ALOAD, 2);
656 // put fields on the stack
657 emitPushFields(types, className, mv);
658 // put narg on stack
659 mv.visitVarInsn(typeLoadOp(btChar), 3);
660 // finally, invoke the constructor and return
661 mv.visitMethodInsn(INVOKEVIRTUAL, MH, "invokeBasic", makeSignature(types + btChar, false), false);
662 mv.visitInsn(ARETURN);
663 mv.visitMaxs(0, 0);
664 mv.visitEnd();
665 }
666
667 // emit class initializer
668 mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "<clinit>", VOID_SIG, null, null);
669 mv.visitCode();
670 mv.visitLdcInsn(types);
671 mv.visitLdcInsn(Type.getObjectType(className));
672 mv.visitMethodInsn(INVOKESTATIC, SPECIES_DATA, "getForClass", BMHSPECIES_DATA_GFC_SIG, false);
673 mv.visitFieldInsn(PUTSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG);
674 mv.visitInsn(RETURN);
675 mv.visitMaxs(0, 0);
676 mv.visitEnd();
677
678 cw.visitEnd();
679
680 // load class
681 final byte[] classFile = cw.toByteArray();
682 InvokerBytecodeGenerator.maybeDump(className, classFile);
683 Class<? extends BoundMethodHandle> bmhClass =
684 //UNSAFE.defineAnonymousClass(BoundMethodHandle.class, classFile, null).asSubclass(BoundMethodHandle.class);
685 UNSAFE.defineClass(className, classFile, 0, classFile.length,
686 BoundMethodHandle.class.getClassLoader(), null)
687 .asSubclass(BoundMethodHandle.class);
688 UNSAFE.ensureClassInitialized(bmhClass);
689
690 return bmhClass;
691 }
692
693 private static int typeLoadOp(char t) {
694 switch (t) {
695 case 'L': return ALOAD;
696 case 'I': return ILOAD;
697 case 'J': return LLOAD;
698 case 'F': return FLOAD;
699 case 'D': return DLOAD;
700 default : throw newInternalError("unrecognized type " + t);
701 }
702 }
703
704 private static void emitPushFields(String types, String className, MethodVisitor mv) {
705 for (int i = 0; i < types.length(); ++i) {
706 char tc = types.charAt(i);
707 mv.visitVarInsn(ALOAD, 0);
708 mv.visitFieldInsn(GETFIELD, className, makeFieldName(types, i), typeSig(tc));
709 }
710 }
711
712 static String typeSig(char t) {
713 return t == 'L' ? JLO_SIG : String.valueOf(t);
714 }
715
716 //
717 // Getter MH generation.
718 //
719
720 private static MethodHandle makeGetter(Class<?> cbmhClass, String types, int index) {
721 String fieldName = makeFieldName(types, index);
722 Class<?> fieldType = Wrapper.forBasicType(types.charAt(index)).primitiveType();
723 try {
724 return LOOKUP.findGetter(cbmhClass, fieldName, fieldType);
725 } catch (NoSuchFieldException | IllegalAccessException e) {
726 throw newInternalError(e);
727 }
728 }
729
730 static MethodHandle[] makeGetters(Class<?> cbmhClass, String types, MethodHandle[] mhs) {
731 if (mhs == null) mhs = new MethodHandle[types.length()];
732 for (int i = 0; i < mhs.length; ++i) {
733 mhs[i] = makeGetter(cbmhClass, types, i);
734 assert(mhs[i].internalMemberName().getDeclaringClass() == cbmhClass);
735 }
736 return mhs;
737 }
738
739 static MethodHandle[] makeCtors(Class<? extends BoundMethodHandle> cbmh, String types, MethodHandle mhs[]) {
740 if (mhs == null) mhs = new MethodHandle[1];
741 if (types.equals("")) return mhs; // hack for empty BMH species
742 mhs[0] = makeCbmhCtor(cbmh, types);
743 return mhs;
744 }
745
746 static NamedFunction[] makeNominalGetters(String types, NamedFunction[] nfs, MethodHandle[] getters) {
747 if (nfs == null) nfs = new NamedFunction[types.length()];
748 for (int i = 0; i < nfs.length; ++i) {
749 nfs[i] = new NamedFunction(getters[i]);
750 }
751 return nfs;
752 }
753
754 //
755 // Auxiliary methods.
756 //
757
758 static SpeciesData speciesDataFromConcreteBMHClass(Class<? extends BoundMethodHandle> cbmh) {
759 try {
760 Field F_SPECIES_DATA = cbmh.getDeclaredField("SPECIES_DATA");
761 return (SpeciesData) F_SPECIES_DATA.get(null);
762 } catch (ReflectiveOperationException ex) {
763 throw newInternalError(ex);
764 }
765 }
766
767 /**
768 * Field names in concrete BMHs adhere to this pattern:
769 * arg + type + index
770 * where type is a single character (L, I, J, F, D).
771 */
772 private static String makeFieldName(String types, int index) {
773 assert index >= 0 && index < types.length();
774 return "arg" + types.charAt(index) + index;
775 }
776
777 private static String makeSignature(String types, boolean ctor) {
778 StringBuilder buf = new StringBuilder(SIG_INCIPIT);
779 for (char c : types.toCharArray()) {
780 buf.append(typeSig(c));
781 }
782 return buf.append(')').append(ctor ? "V" : BMH_SIG).toString();
783 }
784
785 static MethodHandle makeCbmhCtor(Class<? extends BoundMethodHandle> cbmh, String types) {
786 try {
787 return LOOKUP.findStatic(cbmh, "make", MethodType.fromMethodDescriptorString(makeSignature(types, false), null));
788 } catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException | TypeNotPresentException e) {
789 throw newInternalError(e);
790 }
791 }
792 }
793
794 private static final Lookup LOOKUP = Lookup.IMPL_LOOKUP;
795
796 /**
797 * All subclasses must provide such a value describing their type signature.
798 */
799 static final SpeciesData SPECIES_DATA = SpeciesData.EMPTY;
800
801 private static final SpeciesData[] SPECIES_DATA_CACHE = new SpeciesData[5];
802 private static SpeciesData checkCache(int size, String types) {
803 int idx = size - 1;
804 SpeciesData data = SPECIES_DATA_CACHE[idx];
805 if (data != null) return data;
806 SPECIES_DATA_CACHE[idx] = data = getSpeciesData(types);
807 return data;
808 }
809 static SpeciesData speciesData_L() { return checkCache(1, "L"); }
810 static SpeciesData speciesData_LL() { return checkCache(2, "LL"); }
811 static SpeciesData speciesData_LLL() { return checkCache(3, "LLL"); }
|