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 assert(speciesData() == speciesData(form));
58 }
59
60 //
61 // BMH API and internals
62 //
63
64 static BoundMethodHandle bindSingle(MethodType type, LambdaForm form, BasicType xtype, Object x) {
200
201 //
202 // concrete BMH classes required to close bootstrap loops
203 //
204
205 private // make it private to force users to access the enclosing class first
206 static final class Species_L extends BoundMethodHandle {
207 final Object argL0;
208 private Species_L(MethodType mt, LambdaForm lf, Object argL0) {
209 super(mt, lf);
210 this.argL0 = argL0;
211 }
212 @Override
213 /*non-public*/ SpeciesData speciesData() {
214 return SPECIES_DATA;
215 }
216 @Override
217 /*non-public*/ int fieldCount() {
218 return 1;
219 }
220 /*non-public*/ static final SpeciesData SPECIES_DATA = SpeciesData.getForClass("L", Species_L.class);
221 /*non-public*/ static BoundMethodHandle make(MethodType mt, LambdaForm lf, Object argL0) {
222 return new Species_L(mt, lf, argL0);
223 }
224 @Override
225 /*non-public*/ final BoundMethodHandle copyWith(MethodType mt, LambdaForm lf) {
226 return new Species_L(mt, lf, argL0);
227 }
228 @Override
229 /*non-public*/ final BoundMethodHandle copyWithExtendL(MethodType mt, LambdaForm lf, Object narg) {
230 try {
231 return (BoundMethodHandle) SPECIES_DATA.extendWith(L_TYPE).constructor().invokeBasic(mt, lf, argL0, narg);
232 } catch (Throwable ex) {
233 throw uncaughtException(ex);
234 }
235 }
236 @Override
237 /*non-public*/ final BoundMethodHandle copyWithExtendI(MethodType mt, LambdaForm lf, int narg) {
238 try {
239 return (BoundMethodHandle) SPECIES_DATA.extendWith(I_TYPE).constructor().invokeBasic(mt, lf, argL0, narg);
240 } catch (Throwable ex) {
318 */
319 NamedFunction getterFunction(int i) {
320 NamedFunction nf = nominalGetters[i];
321 assert(nf.memberDeclaringClassOrNull() == fieldHolder());
322 assert(nf.returnType() == fieldType(i));
323 return nf;
324 }
325
326 NamedFunction[] getterFunctions() {
327 return nominalGetters;
328 }
329
330 MethodHandle[] getterHandles() { return getters; }
331
332 MethodHandle constructor() {
333 return constructor[0];
334 }
335
336 static final SpeciesData EMPTY = new SpeciesData("", BoundMethodHandle.class);
337
338 private SpeciesData(String types, Class<? extends BoundMethodHandle> clazz) {
339 this.typeChars = types;
340 this.typeCodes = basicTypes(types);
341 this.clazz = clazz;
342 if (!INIT_DONE) {
343 this.constructor = new MethodHandle[1]; // only one ctor
344 this.getters = new MethodHandle[types.length()];
345 this.nominalGetters = new NamedFunction[types.length()];
346 } else {
347 this.constructor = Factory.makeCtors(clazz, types, null);
348 this.getters = Factory.makeGetters(clazz, types, null);
349 this.nominalGetters = Factory.makeNominalGetters(types, null, this.getters);
350 }
351 this.extensions = new SpeciesData[ARG_TYPE_LIMIT];
352 }
353
354 private void initForBootstrap() {
355 assert(!INIT_DONE);
356 if (constructor() == null) {
357 String types = typeChars;
358 Factory.makeCtors(clazz, types, this.constructor);
359 Factory.makeGetters(clazz, types, this.getters);
360 Factory.makeNominalGetters(types, this.nominalGetters, this.getters);
361 }
362 }
363
364 private SpeciesData(String typeChars) {
365 // Placeholder only.
366 this.typeChars = typeChars;
367 this.typeCodes = basicTypes(typeChars);
368 this.clazz = null;
369 this.constructor = null;
370 this.getters = null;
371 this.nominalGetters = null;
372 this.extensions = null;
373 }
374 private boolean isPlaceholder() { return clazz == null; }
375
376 private static final HashMap<String, SpeciesData> CACHE = new HashMap<>();
377 static { CACHE.put("", EMPTY); } // make bootstrap predictable
378 private static final boolean INIT_DONE; // set after <clinit> finishes...
379
380 SpeciesData extendWith(byte type) {
381 return extendWith(BasicType.basicType(type));
382 }
383
384 SpeciesData extendWith(BasicType type) {
385 int ord = type.ordinal();
386 SpeciesData d = extensions[ord];
387 if (d != null) return d;
388 extensions[ord] = d = get(typeChars+type.basicTypeChar());
389 return d;
390 }
391
392 private static SpeciesData get(String types) {
393 // Acquire cache lock for query.
394 SpeciesData d = lookupCache(types);
395 if (!d.isPlaceholder())
396 return d;
397 synchronized (d) {
398 // Use synch. on the placeholder to prevent multiple instantiation of one species.
399 // Creating this class forces a recursive call to getForClass.
400 if (lookupCache(types).isPlaceholder())
401 Factory.generateConcreteBMHClass(types);
402 }
403 // Reacquire cache lock.
404 d = lookupCache(types);
405 // Class loading must have upgraded the cache.
406 assert(d != null && !d.isPlaceholder());
407 return d;
408 }
409 static SpeciesData getForClass(String types, Class<? extends BoundMethodHandle> clazz) {
410 // clazz is a new class which is initializing its SPECIES_DATA field
411 return updateCache(types, new SpeciesData(types, clazz));
412 }
413 private static synchronized SpeciesData lookupCache(String types) {
414 SpeciesData d = CACHE.get(types);
415 if (d != null) return d;
416 d = new SpeciesData(types);
417 assert(d.isPlaceholder());
418 CACHE.put(types, d);
419 return d;
420 }
421 private static synchronized SpeciesData updateCache(String types, SpeciesData d) {
422 SpeciesData d2;
423 assert((d2 = CACHE.get(types)) == null || d2.isPlaceholder());
424 assert(!d.isPlaceholder());
425 CACHE.put(types, d);
426 return d;
427 }
428
429 static {
430 // pre-fill the BMH speciesdata cache with BMH's inner classes
431 final Class<BoundMethodHandle> rootCls = BoundMethodHandle.class;
432 try {
433 for (Class<?> c : rootCls.getDeclaredClasses()) {
434 if (rootCls.isAssignableFrom(c)) {
435 final Class<? extends BoundMethodHandle> cbmh = c.asSubclass(BoundMethodHandle.class);
436 SpeciesData d = Factory.speciesDataFromConcreteBMHClass(cbmh);
437 assert(d != null) : cbmh.getName();
438 assert(d.clazz == cbmh);
439 assert(d == lookupCache(d.typeChars));
440 }
441 }
442 } catch (Throwable e) {
443 throw newInternalError(e);
444 }
445
446 for (SpeciesData d : CACHE.values()) {
447 d.initForBootstrap();
448 }
449 // Note: Do not simplify this, because INIT_DONE must not be
450 // a compile-time constant during bootstrapping.
451 INIT_DONE = Boolean.TRUE;
452 }
453 }
454
455 static SpeciesData getSpeciesData(String types) {
456 return SpeciesData.get(types);
457 }
458
459 /**
460 * Generation of concrete BMH classes.
461 *
462 * A concrete BMH species is fit for binding a number of values adhering to a
463 * given type pattern. Reference types are erased.
464 *
465 * BMH species are cached by type pattern.
466 *
467 * A BMH species has a number of fields with the concrete (possibly erased) types of
468 * bound values. Setters are provided as an API in BMH. Getters are exposed as MHs,
469 * which can be included as names in lambda forms.
470 */
471 static class Factory {
472
473 static final String JLO_SIG = "Ljava/lang/Object;";
474 static final String JLS_SIG = "Ljava/lang/String;";
475 static final String JLC_SIG = "Ljava/lang/Class;";
476 static final String MH = "java/lang/invoke/MethodHandle";
477 static final String MH_SIG = "L"+MH+";";
478 static final String BMH = "java/lang/invoke/BoundMethodHandle";
479 static final String BMH_SIG = "L"+BMH+";";
480 static final String SPECIES_DATA = "java/lang/invoke/BoundMethodHandle$SpeciesData";
481 static final String SPECIES_DATA_SIG = "L"+SPECIES_DATA+";";
482
483 static final String SPECIES_PREFIX_NAME = "Species_";
484 static final String SPECIES_PREFIX_PATH = BMH + "$" + SPECIES_PREFIX_NAME;
485
486 static final String BMHSPECIES_DATA_EWI_SIG = "(B)" + SPECIES_DATA_SIG;
487 static final String BMHSPECIES_DATA_GFC_SIG = "(" + JLS_SIG + JLC_SIG + ")" + SPECIES_DATA_SIG;
488 static final String MYSPECIES_DATA_SIG = "()" + SPECIES_DATA_SIG;
489 static final String VOID_SIG = "()V";
490 static final String INT_SIG = "()I";
491
492 static final String SIG_INCIPIT = "(Ljava/lang/invoke/MethodType;Ljava/lang/invoke/LambdaForm;";
493
494 static final String[] E_THROWABLE = new String[] { "java/lang/Throwable" };
495
496 /**
497 * Generate a concrete subclass of BMH for a given combination of bound types.
498 *
499 * A concrete BMH species adheres to the following schema:
500 *
501 * <pre>
502 * class Species_[[types]] extends BoundMethodHandle {
503 * [[fields]]
504 * final SpeciesData speciesData() { return SpeciesData.get("[[types]]"); }
505 * }
506 * </pre>
507 *
508 * The {@code [[types]]} signature is precisely the string that is passed to this
509 * method.
510 *
511 * The {@code [[fields]]} section consists of one field definition per character in
512 * the type signature, adhering to the naming schema described in the definition of
513 * {@link #makeFieldName}.
514 *
515 * For example, a concrete BMH species for two reference and one integral bound values
516 * would have the following shape:
517 *
518 * <pre>
519 * class BoundMethodHandle { ... private static
520 * final class Species_LLI extends BoundMethodHandle {
521 * final Object argL0;
522 * final Object argL1;
523 * final int argI2;
524 * private Species_LLI(MethodType mt, LambdaForm lf, Object argL0, Object argL1, int argI2) {
525 * super(mt, lf);
526 * this.argL0 = argL0;
527 * this.argL1 = argL1;
528 * this.argI2 = argI2;
529 * }
530 * final SpeciesData speciesData() { return SPECIES_DATA; }
531 * final int fieldCount() { return 3; }
532 * static final SpeciesData SPECIES_DATA = SpeciesData.getForClass("LLI", Species_LLI.class);
533 * static BoundMethodHandle make(MethodType mt, LambdaForm lf, Object argL0, Object argL1, int argI2) {
534 * return new Species_LLI(mt, lf, argL0, argL1, argI2);
535 * }
536 * final BoundMethodHandle copyWith(MethodType mt, LambdaForm lf) {
537 * return new Species_LLI(mt, lf, argL0, argL1, argI2);
538 * }
539 * final BoundMethodHandle copyWithExtendL(MethodType mt, LambdaForm lf, Object narg) {
540 * return SPECIES_DATA.extendWith(L_TYPE).constructor().invokeBasic(mt, lf, argL0, argL1, argI2, narg);
541 * }
542 * final BoundMethodHandle copyWithExtendI(MethodType mt, LambdaForm lf, int narg) {
543 * return SPECIES_DATA.extendWith(I_TYPE).constructor().invokeBasic(mt, lf, argL0, argL1, argI2, narg);
544 * }
545 * final BoundMethodHandle copyWithExtendJ(MethodType mt, LambdaForm lf, long narg) {
546 * return SPECIES_DATA.extendWith(J_TYPE).constructor().invokeBasic(mt, lf, argL0, argL1, argI2, narg);
547 * }
548 * final BoundMethodHandle copyWithExtendF(MethodType mt, LambdaForm lf, float narg) {
549 * return SPECIES_DATA.extendWith(F_TYPE).constructor().invokeBasic(mt, lf, argL0, argL1, argI2, narg);
550 * }
551 * public final BoundMethodHandle copyWithExtendD(MethodType mt, LambdaForm lf, double narg) {
552 * return SPECIES_DATA.extendWith(D_TYPE).constructor().invokeBasic(mt, lf, argL0, argL1, argI2, narg);
553 * }
554 * }
555 * </pre>
556 *
557 * @param types the type signature, wherein reference types are erased to 'L'
558 * @return the generated concrete BMH class
559 */
560 static Class<? extends BoundMethodHandle> generateConcreteBMHClass(String types) {
561 final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
562
563 String shortTypes = LambdaForm.shortenSignature(types);
564 final String className = SPECIES_PREFIX_PATH + shortTypes;
565 final String sourceFile = SPECIES_PREFIX_NAME + shortTypes;
566 final int NOT_ACC_PUBLIC = 0; // not ACC_PUBLIC
567 cw.visit(V1_6, NOT_ACC_PUBLIC + ACC_FINAL + ACC_SUPER, className, null, BMH, null);
568 cw.visitSource(sourceFile, null);
569
570 // emit static types and SPECIES_DATA fields
571 cw.visitField(NOT_ACC_PUBLIC + ACC_STATIC, "SPECIES_DATA", SPECIES_DATA_SIG, null, null).visitEnd();
572
573 // emit bound argument fields
574 for (int i = 0; i < types.length(); ++i) {
575 final char t = types.charAt(i);
576 final String fieldName = makeFieldName(types, i);
577 final String fieldDesc = t == 'L' ? JLO_SIG : String.valueOf(t);
578 cw.visitField(ACC_FINAL, fieldName, fieldDesc, null, null).visitEnd();
579 }
580
581 MethodVisitor mv;
582
583 // emit constructor
584 mv = cw.visitMethod(ACC_PRIVATE, "<init>", makeSignature(types, true), null, null);
585 mv.visitCode();
586 mv.visitVarInsn(ALOAD, 0); // this
587 mv.visitVarInsn(ALOAD, 1); // type
588 mv.visitVarInsn(ALOAD, 2); // form
589
590 mv.visitMethodInsn(INVOKESPECIAL, BMH, "<init>", makeSignature("", true), false);
591
677 mv.visitFieldInsn(GETSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG);
678 int iconstInsn = ICONST_0 + ord;
679 assert(iconstInsn <= ICONST_5);
680 mv.visitInsn(iconstInsn);
681 mv.visitMethodInsn(INVOKEVIRTUAL, SPECIES_DATA, "extendWith", BMHSPECIES_DATA_EWI_SIG, false);
682 mv.visitMethodInsn(INVOKEVIRTUAL, SPECIES_DATA, "constructor", "()" + MH_SIG, false);
683 // load mt, lf
684 mv.visitVarInsn(ALOAD, 1);
685 mv.visitVarInsn(ALOAD, 2);
686 // put fields on the stack
687 emitPushFields(types, className, mv);
688 // put narg on stack
689 mv.visitVarInsn(typeLoadOp(btChar), 3);
690 // finally, invoke the constructor and return
691 mv.visitMethodInsn(INVOKEVIRTUAL, MH, "invokeBasic", makeSignature(types + btChar, false), false);
692 mv.visitInsn(ARETURN);
693 mv.visitMaxs(0, 0);
694 mv.visitEnd();
695 }
696
697 // emit class initializer
698 mv = cw.visitMethod(NOT_ACC_PUBLIC | ACC_STATIC, "<clinit>", VOID_SIG, null, null);
699 mv.visitCode();
700 mv.visitLdcInsn(types);
701 mv.visitLdcInsn(Type.getObjectType(className));
702 mv.visitMethodInsn(INVOKESTATIC, SPECIES_DATA, "getForClass", BMHSPECIES_DATA_GFC_SIG, false);
703 mv.visitFieldInsn(PUTSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG);
704 mv.visitInsn(RETURN);
705 mv.visitMaxs(0, 0);
706 mv.visitEnd();
707
708 cw.visitEnd();
709
710 // load class
711 final byte[] classFile = cw.toByteArray();
712 InvokerBytecodeGenerator.maybeDump(className, classFile);
713 Class<? extends BoundMethodHandle> bmhClass =
714 //UNSAFE.defineAnonymousClass(BoundMethodHandle.class, classFile, null).asSubclass(BoundMethodHandle.class);
715 UNSAFE.defineClass(className, classFile, 0, classFile.length,
716 BoundMethodHandle.class.getClassLoader(), null)
717 .asSubclass(BoundMethodHandle.class);
718 UNSAFE.ensureClassInitialized(bmhClass);
719
720 return bmhClass;
721 }
722
723 private static int typeLoadOp(char t) {
724 switch (t) {
725 case 'L': return ALOAD;
726 case 'I': return ILOAD;
727 case 'J': return LLOAD;
728 case 'F': return FLOAD;
729 case 'D': return DLOAD;
730 default : throw newInternalError("unrecognized type " + t);
731 }
732 }
733
734 private static void emitPushFields(String types, String className, MethodVisitor mv) {
735 for (int i = 0; i < types.length(); ++i) {
736 char tc = types.charAt(i);
737 mv.visitVarInsn(ALOAD, 0);
738 mv.visitFieldInsn(GETFIELD, className, makeFieldName(types, i), typeSig(tc));
768
769 static MethodHandle[] makeCtors(Class<? extends BoundMethodHandle> cbmh, String types, MethodHandle mhs[]) {
770 if (mhs == null) mhs = new MethodHandle[1];
771 if (types.equals("")) return mhs; // hack for empty BMH species
772 mhs[0] = makeCbmhCtor(cbmh, types);
773 return mhs;
774 }
775
776 static NamedFunction[] makeNominalGetters(String types, NamedFunction[] nfs, MethodHandle[] getters) {
777 if (nfs == null) nfs = new NamedFunction[types.length()];
778 for (int i = 0; i < nfs.length; ++i) {
779 nfs[i] = new NamedFunction(getters[i]);
780 }
781 return nfs;
782 }
783
784 //
785 // Auxiliary methods.
786 //
787
788 static SpeciesData speciesDataFromConcreteBMHClass(Class<? extends BoundMethodHandle> cbmh) {
789 try {
790 Field F_SPECIES_DATA = cbmh.getDeclaredField("SPECIES_DATA");
791 return (SpeciesData) F_SPECIES_DATA.get(null);
792 } catch (ReflectiveOperationException ex) {
793 throw newInternalError(ex);
794 }
795 }
796
797 /**
798 * Field names in concrete BMHs adhere to this pattern:
799 * arg + type + index
800 * where type is a single character (L, I, J, F, D).
801 */
802 private static String makeFieldName(String types, int index) {
803 assert index >= 0 && index < types.length();
804 return "arg" + types.charAt(index) + index;
805 }
806
807 private static String makeSignature(String types, boolean ctor) {
808 StringBuilder buf = new StringBuilder(SIG_INCIPIT);
809 for (char c : types.toCharArray()) {
810 buf.append(typeSig(c));
811 }
|
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.function.Function;
38 import java.util.concurrent.ConcurrentMap;
39 import java.util.concurrent.ConcurrentHashMap;
40
41 import jdk.internal.org.objectweb.asm.FieldVisitor;
42 import sun.invoke.util.ValueConversions;
43 import sun.invoke.util.Wrapper;
44
45 import jdk.internal.org.objectweb.asm.ClassWriter;
46 import jdk.internal.org.objectweb.asm.MethodVisitor;
47
48 /**
49 * The flavor of method handle which emulates an invoke instruction
50 * on a predetermined argument. The JVM dispatches to the correct method
51 * when the handle is created, not when it is invoked.
52 *
53 * All bound arguments are encapsulated in dedicated species.
54 */
55 /*non-public*/ abstract class BoundMethodHandle extends MethodHandle {
56
57 /*non-public*/ BoundMethodHandle(MethodType type, LambdaForm form) {
58 super(type, form);
59 assert(speciesData() == speciesData(form));
60 }
61
62 //
63 // BMH API and internals
64 //
65
66 static BoundMethodHandle bindSingle(MethodType type, LambdaForm form, BasicType xtype, Object x) {
202
203 //
204 // concrete BMH classes required to close bootstrap loops
205 //
206
207 private // make it private to force users to access the enclosing class first
208 static final class Species_L extends BoundMethodHandle {
209 final Object argL0;
210 private Species_L(MethodType mt, LambdaForm lf, Object argL0) {
211 super(mt, lf);
212 this.argL0 = argL0;
213 }
214 @Override
215 /*non-public*/ SpeciesData speciesData() {
216 return SPECIES_DATA;
217 }
218 @Override
219 /*non-public*/ int fieldCount() {
220 return 1;
221 }
222 /*non-public*/ static final SpeciesData SPECIES_DATA = new SpeciesData("L", Species_L.class);
223 /*non-public*/ static BoundMethodHandle make(MethodType mt, LambdaForm lf, Object argL0) {
224 return new Species_L(mt, lf, argL0);
225 }
226 @Override
227 /*non-public*/ final BoundMethodHandle copyWith(MethodType mt, LambdaForm lf) {
228 return new Species_L(mt, lf, argL0);
229 }
230 @Override
231 /*non-public*/ final BoundMethodHandle copyWithExtendL(MethodType mt, LambdaForm lf, Object narg) {
232 try {
233 return (BoundMethodHandle) SPECIES_DATA.extendWith(L_TYPE).constructor().invokeBasic(mt, lf, argL0, narg);
234 } catch (Throwable ex) {
235 throw uncaughtException(ex);
236 }
237 }
238 @Override
239 /*non-public*/ final BoundMethodHandle copyWithExtendI(MethodType mt, LambdaForm lf, int narg) {
240 try {
241 return (BoundMethodHandle) SPECIES_DATA.extendWith(I_TYPE).constructor().invokeBasic(mt, lf, argL0, narg);
242 } catch (Throwable ex) {
320 */
321 NamedFunction getterFunction(int i) {
322 NamedFunction nf = nominalGetters[i];
323 assert(nf.memberDeclaringClassOrNull() == fieldHolder());
324 assert(nf.returnType() == fieldType(i));
325 return nf;
326 }
327
328 NamedFunction[] getterFunctions() {
329 return nominalGetters;
330 }
331
332 MethodHandle[] getterHandles() { return getters; }
333
334 MethodHandle constructor() {
335 return constructor[0];
336 }
337
338 static final SpeciesData EMPTY = new SpeciesData("", BoundMethodHandle.class);
339
340 SpeciesData(String types, Class<? extends BoundMethodHandle> clazz) {
341 this.typeChars = types;
342 this.typeCodes = basicTypes(types);
343 this.clazz = clazz;
344 if (!INIT_DONE) {
345 this.constructor = new MethodHandle[1]; // only one ctor
346 this.getters = new MethodHandle[types.length()];
347 this.nominalGetters = new NamedFunction[types.length()];
348 } else {
349 this.constructor = Factory.makeCtors(clazz, types, null);
350 this.getters = Factory.makeGetters(clazz, types, null);
351 this.nominalGetters = Factory.makeNominalGetters(types, null, this.getters);
352 }
353 this.extensions = new SpeciesData[ARG_TYPE_LIMIT];
354 }
355
356 private void initForBootstrap() {
357 assert(!INIT_DONE);
358 if (constructor() == null) {
359 String types = typeChars;
360 CACHE.put(types, this);
361 Factory.makeCtors(clazz, types, this.constructor);
362 Factory.makeGetters(clazz, types, this.getters);
363 Factory.makeNominalGetters(types, this.nominalGetters, this.getters);
364 }
365 }
366
367 private static final ConcurrentMap<String, SpeciesData> CACHE = new ConcurrentHashMap<>();
368 private static final boolean INIT_DONE; // set after <clinit> finishes...
369
370 SpeciesData extendWith(byte type) {
371 return extendWith(BasicType.basicType(type));
372 }
373
374 SpeciesData extendWith(BasicType type) {
375 int ord = type.ordinal();
376 SpeciesData d = extensions[ord];
377 if (d != null) return d;
378 extensions[ord] = d = get(typeChars+type.basicTypeChar());
379 return d;
380 }
381
382 private static SpeciesData get(String types) {
383 return CACHE.computeIfAbsent(types, new Function<String, SpeciesData>() {
384 @Override
385 public SpeciesData apply(String types) {
386 Class<? extends BoundMethodHandle> bmhcl = Factory.getConcreteBMHClass(types);
387 // SpeciesData instantiation may throw VirtualMachineError because of
388 // code cache overflow...
389 SpeciesData speciesData = new SpeciesData(types, bmhcl);
390 // CHM.computeIfAbsent ensures only one SpeciesData will be set
391 // successfully on the concrete BMH class if ever
392 Factory.setSpeciesDataToConcreteBMHClass(bmhcl, speciesData);
393 // the concrete BMH class is published via SpeciesData instance
394 // returned here only after it's SPECIES_DATA field is set
395 return speciesData;
396 }
397 });
398 }
399
400 /**
401 * This is to be called when assertions are enabled. It checks whether SpeciesData for all of the statically
402 * defined species subclasses of BoundMethodHandle has been added to the SpeciesData cache. See below in the
403 * static initializer for
404 */
405 static boolean speciesDataCachePopulated() {
406 Class<BoundMethodHandle> rootCls = BoundMethodHandle.class;
407 try {
408 for (Class<?> c : rootCls.getDeclaredClasses()) {
409 if (rootCls.isAssignableFrom(c)) {
410 final Class<? extends BoundMethodHandle> cbmh = c.asSubclass(BoundMethodHandle.class);
411 SpeciesData d = Factory.getSpeciesDataFromConcreteBMHClass(cbmh);
412 assert(d != null) : cbmh.getName();
413 assert(d.clazz == cbmh);
414 assert(CACHE.get(d.typeChars) == d);
415 }
416 }
417 } catch (Throwable e) {
418 throw newInternalError(e);
419 }
420 return true;
421 }
422
423 static {
424 // Pre-fill the BMH species-data cache with EMPTY and all BMH's inner subclasses.
425 EMPTY.initForBootstrap();
426 Species_L.SPECIES_DATA.initForBootstrap();
427 // check that all static SpeciesData instances have been initialized
428 assert speciesDataCachePopulated();
429 // Note: Do not simplify this, because INIT_DONE must not be
430 // a compile-time constant during bootstrapping.
431 INIT_DONE = Boolean.TRUE;
432 }
433 }
434
435 static SpeciesData getSpeciesData(String types) {
436 return SpeciesData.get(types);
437 }
438
439 /**
440 * Generation of concrete BMH classes.
441 *
442 * A concrete BMH species is fit for binding a number of values adhering to a
443 * given type pattern. Reference types are erased.
444 *
445 * BMH species are cached by type pattern.
446 *
447 * A BMH species has a number of fields with the concrete (possibly erased) types of
448 * bound values. Setters are provided as an API in BMH. Getters are exposed as MHs,
449 * which can be included as names in lambda forms.
450 */
451 static class Factory {
452
453 static final String JLO_SIG = "Ljava/lang/Object;";
454 static final String JLS_SIG = "Ljava/lang/String;";
455 static final String JLC_SIG = "Ljava/lang/Class;";
456 static final String MH = "java/lang/invoke/MethodHandle";
457 static final String MH_SIG = "L"+MH+";";
458 static final String BMH = "java/lang/invoke/BoundMethodHandle";
459 static final String BMH_SIG = "L"+BMH+";";
460 static final String SPECIES_DATA = "java/lang/invoke/BoundMethodHandle$SpeciesData";
461 static final String SPECIES_DATA_SIG = "L"+SPECIES_DATA+";";
462 static final String STABLE_SIG = "Ljava/lang/invoke/Stable;";
463
464 static final String SPECIES_PREFIX_NAME = "Species_";
465 static final String SPECIES_PREFIX_PATH = BMH + "$" + SPECIES_PREFIX_NAME;
466
467 static final String BMHSPECIES_DATA_EWI_SIG = "(B)" + SPECIES_DATA_SIG;
468 static final String BMHSPECIES_DATA_GFC_SIG = "(" + JLS_SIG + JLC_SIG + ")" + SPECIES_DATA_SIG;
469 static final String MYSPECIES_DATA_SIG = "()" + SPECIES_DATA_SIG;
470 static final String VOID_SIG = "()V";
471 static final String INT_SIG = "()I";
472
473 static final String SIG_INCIPIT = "(Ljava/lang/invoke/MethodType;Ljava/lang/invoke/LambdaForm;";
474
475 static final String[] E_THROWABLE = new String[] { "java/lang/Throwable" };
476
477 static final ConcurrentMap<String, Class<? extends BoundMethodHandle>> CLASS_CACHE = new ConcurrentHashMap<>();
478
479 /**
480 * Get a concrete subclass of BMH for a given combination of bound types.
481 *
482 * @param types the type signature, wherein reference types are erased to 'L'
483 * @return the concrete BMH class
484 */
485 static Class<? extends BoundMethodHandle> getConcreteBMHClass(String types) {
486 // CHM.computeIfAbsent ensures generateConcreteBMHClass is called
487 // only once per key.
488 return CLASS_CACHE.computeIfAbsent(
489 types, new Function<String, Class<? extends BoundMethodHandle>>() {
490 @Override
491 public Class<? extends BoundMethodHandle> apply(String types) {
492 return generateConcreteBMHClass(types);
493 }
494 });
495 }
496
497 /**
498 * Generate a concrete subclass of BMH for a given combination of bound types.
499 *
500 * A concrete BMH species adheres to the following schema:
501 *
502 * <pre>
503 * class Species_[[types]] extends BoundMethodHandle {
504 * [[fields]]
505 * final SpeciesData speciesData() { return SpeciesData.get("[[types]]"); }
506 * }
507 * </pre>
508 *
509 * The {@code [[types]]} signature is precisely the string that is passed to this
510 * method.
511 *
512 * The {@code [[fields]]} section consists of one field definition per character in
513 * the type signature, adhering to the naming schema described in the definition of
514 * {@link #makeFieldName}.
515 *
516 * For example, a concrete BMH species for two reference and one integral bound values
517 * would have the following shape:
518 *
519 * <pre>
520 * class BoundMethodHandle { ... private static
521 * final class Species_LLI extends BoundMethodHandle {
522 * final Object argL0;
523 * final Object argL1;
524 * final int argI2;
525 * private Species_LLI(MethodType mt, LambdaForm lf, Object argL0, Object argL1, int argI2) {
526 * super(mt, lf);
527 * this.argL0 = argL0;
528 * this.argL1 = argL1;
529 * this.argI2 = argI2;
530 * }
531 * final SpeciesData speciesData() { return SPECIES_DATA; }
532 * final int fieldCount() { return 3; }
533 * @Stable static SpeciesData SPECIES_DATA; // injected afterwards
534 * static BoundMethodHandle make(MethodType mt, LambdaForm lf, Object argL0, Object argL1, int argI2) {
535 * return new Species_LLI(mt, lf, argL0, argL1, argI2);
536 * }
537 * final BoundMethodHandle copyWith(MethodType mt, LambdaForm lf) {
538 * return new Species_LLI(mt, lf, argL0, argL1, argI2);
539 * }
540 * final BoundMethodHandle copyWithExtendL(MethodType mt, LambdaForm lf, Object narg) {
541 * return SPECIES_DATA.extendWith(L_TYPE).constructor().invokeBasic(mt, lf, argL0, argL1, argI2, narg);
542 * }
543 * final BoundMethodHandle copyWithExtendI(MethodType mt, LambdaForm lf, int narg) {
544 * return SPECIES_DATA.extendWith(I_TYPE).constructor().invokeBasic(mt, lf, argL0, argL1, argI2, narg);
545 * }
546 * final BoundMethodHandle copyWithExtendJ(MethodType mt, LambdaForm lf, long narg) {
547 * return SPECIES_DATA.extendWith(J_TYPE).constructor().invokeBasic(mt, lf, argL0, argL1, argI2, narg);
548 * }
549 * final BoundMethodHandle copyWithExtendF(MethodType mt, LambdaForm lf, float narg) {
550 * return SPECIES_DATA.extendWith(F_TYPE).constructor().invokeBasic(mt, lf, argL0, argL1, argI2, narg);
551 * }
552 * public final BoundMethodHandle copyWithExtendD(MethodType mt, LambdaForm lf, double narg) {
553 * return SPECIES_DATA.extendWith(D_TYPE).constructor().invokeBasic(mt, lf, argL0, argL1, argI2, narg);
554 * }
555 * }
556 * </pre>
557 *
558 * @param types the type signature, wherein reference types are erased to 'L'
559 * @return the generated concrete BMH class
560 */
561 static Class<? extends BoundMethodHandle> generateConcreteBMHClass(String types) {
562 final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
563
564 String shortTypes = LambdaForm.shortenSignature(types);
565 final String className = SPECIES_PREFIX_PATH + shortTypes;
566 final String sourceFile = SPECIES_PREFIX_NAME + shortTypes;
567 final int NOT_ACC_PUBLIC = 0; // not ACC_PUBLIC
568 cw.visit(V1_6, NOT_ACC_PUBLIC + ACC_FINAL + ACC_SUPER, className, null, BMH, null);
569 cw.visitSource(sourceFile, null);
570
571 // emit static types and SPECIES_DATA fields
572 FieldVisitor fw = cw.visitField(NOT_ACC_PUBLIC + ACC_STATIC, "SPECIES_DATA", SPECIES_DATA_SIG, null, null);
573 fw.visitAnnotation(STABLE_SIG, true);
574 fw.visitEnd();
575
576 // emit bound argument fields
577 for (int i = 0; i < types.length(); ++i) {
578 final char t = types.charAt(i);
579 final String fieldName = makeFieldName(types, i);
580 final String fieldDesc = t == 'L' ? JLO_SIG : String.valueOf(t);
581 cw.visitField(ACC_FINAL, fieldName, fieldDesc, null, null).visitEnd();
582 }
583
584 MethodVisitor mv;
585
586 // emit constructor
587 mv = cw.visitMethod(ACC_PRIVATE, "<init>", makeSignature(types, true), null, null);
588 mv.visitCode();
589 mv.visitVarInsn(ALOAD, 0); // this
590 mv.visitVarInsn(ALOAD, 1); // type
591 mv.visitVarInsn(ALOAD, 2); // form
592
593 mv.visitMethodInsn(INVOKESPECIAL, BMH, "<init>", makeSignature("", true), false);
594
680 mv.visitFieldInsn(GETSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG);
681 int iconstInsn = ICONST_0 + ord;
682 assert(iconstInsn <= ICONST_5);
683 mv.visitInsn(iconstInsn);
684 mv.visitMethodInsn(INVOKEVIRTUAL, SPECIES_DATA, "extendWith", BMHSPECIES_DATA_EWI_SIG, false);
685 mv.visitMethodInsn(INVOKEVIRTUAL, SPECIES_DATA, "constructor", "()" + MH_SIG, false);
686 // load mt, lf
687 mv.visitVarInsn(ALOAD, 1);
688 mv.visitVarInsn(ALOAD, 2);
689 // put fields on the stack
690 emitPushFields(types, className, mv);
691 // put narg on stack
692 mv.visitVarInsn(typeLoadOp(btChar), 3);
693 // finally, invoke the constructor and return
694 mv.visitMethodInsn(INVOKEVIRTUAL, MH, "invokeBasic", makeSignature(types + btChar, false), false);
695 mv.visitInsn(ARETURN);
696 mv.visitMaxs(0, 0);
697 mv.visitEnd();
698 }
699
700 cw.visitEnd();
701
702 // load class
703 final byte[] classFile = cw.toByteArray();
704 InvokerBytecodeGenerator.maybeDump(className, classFile);
705 Class<? extends BoundMethodHandle> bmhClass =
706 //UNSAFE.defineAnonymousClass(BoundMethodHandle.class, classFile, null).asSubclass(BoundMethodHandle.class);
707 UNSAFE.defineClass(className, classFile, 0, classFile.length,
708 BoundMethodHandle.class.getClassLoader(), null)
709 .asSubclass(BoundMethodHandle.class);
710
711 return bmhClass;
712 }
713
714 private static int typeLoadOp(char t) {
715 switch (t) {
716 case 'L': return ALOAD;
717 case 'I': return ILOAD;
718 case 'J': return LLOAD;
719 case 'F': return FLOAD;
720 case 'D': return DLOAD;
721 default : throw newInternalError("unrecognized type " + t);
722 }
723 }
724
725 private static void emitPushFields(String types, String className, MethodVisitor mv) {
726 for (int i = 0; i < types.length(); ++i) {
727 char tc = types.charAt(i);
728 mv.visitVarInsn(ALOAD, 0);
729 mv.visitFieldInsn(GETFIELD, className, makeFieldName(types, i), typeSig(tc));
759
760 static MethodHandle[] makeCtors(Class<? extends BoundMethodHandle> cbmh, String types, MethodHandle mhs[]) {
761 if (mhs == null) mhs = new MethodHandle[1];
762 if (types.equals("")) return mhs; // hack for empty BMH species
763 mhs[0] = makeCbmhCtor(cbmh, types);
764 return mhs;
765 }
766
767 static NamedFunction[] makeNominalGetters(String types, NamedFunction[] nfs, MethodHandle[] getters) {
768 if (nfs == null) nfs = new NamedFunction[types.length()];
769 for (int i = 0; i < nfs.length; ++i) {
770 nfs[i] = new NamedFunction(getters[i]);
771 }
772 return nfs;
773 }
774
775 //
776 // Auxiliary methods.
777 //
778
779 static SpeciesData getSpeciesDataFromConcreteBMHClass(Class<? extends BoundMethodHandle> cbmh) {
780 try {
781 Field F_SPECIES_DATA = cbmh.getDeclaredField("SPECIES_DATA");
782 return (SpeciesData) F_SPECIES_DATA.get(null);
783 } catch (ReflectiveOperationException ex) {
784 throw newInternalError(ex);
785 }
786 }
787
788 static void setSpeciesDataToConcreteBMHClass(Class<? extends BoundMethodHandle> cbmh, SpeciesData speciesData) {
789 try {
790 Field F_SPECIES_DATA = cbmh.getDeclaredField("SPECIES_DATA");
791 assert F_SPECIES_DATA.getDeclaredAnnotation(Stable.class) != null;
792 F_SPECIES_DATA.set(null, speciesData);
793 } catch (ReflectiveOperationException ex) {
794 throw newInternalError(ex);
795 }
796 }
797
798 /**
799 * Field names in concrete BMHs adhere to this pattern:
800 * arg + type + index
801 * where type is a single character (L, I, J, F, D).
802 */
803 private static String makeFieldName(String types, int index) {
804 assert index >= 0 && index < types.length();
805 return "arg" + types.charAt(index) + index;
806 }
807
808 private static String makeSignature(String types, boolean ctor) {
809 StringBuilder buf = new StringBuilder(SIG_INCIPIT);
810 for (char c : types.toCharArray()) {
811 buf.append(typeSig(c));
812 }
|