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}.
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
595 for (int i = 0, j = 0; i < types.length(); ++i, ++j) {
596 // i counts the arguments, j counts corresponding argument slots
597 char t = types.charAt(i);
598 mv.visitVarInsn(ALOAD, 0);
599 mv.visitVarInsn(typeLoadOp(t), j + 3); // parameters start at 3
600 mv.visitFieldInsn(PUTFIELD, className, makeFieldName(types, i), typeSig(t));
601 if (t == 'J' || t == 'D') {
602 ++j; // adjust argument register access
603 }
604 }
605
606 mv.visitInsn(RETURN);
607 mv.visitMaxs(0, 0);
608 mv.visitEnd();
609
610 // emit implementation of speciesData()
611 mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_FINAL, "speciesData", MYSPECIES_DATA_SIG, null, null);
612 mv.visitCode();
613 mv.visitFieldInsn(GETSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG);
614 mv.visitInsn(ARETURN);
615 mv.visitMaxs(0, 0);
616 mv.visitEnd();
617
618 // emit implementation of fieldCount()
619 mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_FINAL, "fieldCount", INT_SIG, null, null);
620 mv.visitCode();
621 int fc = types.length();
622 if (fc <= (ICONST_5 - ICONST_0)) {
623 mv.visitInsn(ICONST_0 + fc);
624 } else {
625 mv.visitIntInsn(SIPUSH, fc);
626 }
627 mv.visitInsn(IRETURN);
628 mv.visitMaxs(0, 0);
629 mv.visitEnd();
630 // emit make() ...factory method wrapping constructor
631 mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_STATIC, "make", makeSignature(types, false), null, null);
632 mv.visitCode();
633 // make instance
634 mv.visitTypeInsn(NEW, className);
635 mv.visitInsn(DUP);
636 // load mt, lf
637 mv.visitVarInsn(ALOAD, 0); // type
638 mv.visitVarInsn(ALOAD, 1); // form
639 // load factory method arguments
640 for (int i = 0, j = 0; i < types.length(); ++i, ++j) {
641 // i counts the arguments, j counts corresponding argument slots
642 char t = types.charAt(i);
643 mv.visitVarInsn(typeLoadOp(t), j + 2); // parameters start at 3
644 if (t == 'J' || t == 'D') {
645 ++j; // adjust argument register access
646 }
647 }
648
649 // finally, invoke the constructor and return
650 mv.visitMethodInsn(INVOKESPECIAL, className, "<init>", makeSignature(types, true), false);
651 mv.visitInsn(ARETURN);
652 mv.visitMaxs(0, 0);
653 mv.visitEnd();
654
655 // emit copyWith()
656 mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_FINAL, "copyWith", makeSignature("", false), null, null);
657 mv.visitCode();
658 // make instance
659 mv.visitTypeInsn(NEW, className);
660 mv.visitInsn(DUP);
661 // load mt, lf
662 mv.visitVarInsn(ALOAD, 1);
663 mv.visitVarInsn(ALOAD, 2);
664 // put fields on the stack
665 emitPushFields(types, className, mv);
666 // finally, invoke the constructor and return
667 mv.visitMethodInsn(INVOKESPECIAL, className, "<init>", makeSignature(types, true), false);
668 mv.visitInsn(ARETURN);
669 mv.visitMaxs(0, 0);
670 mv.visitEnd();
671
672 // for each type, emit copyWithExtendT()
673 for (BasicType type : BasicType.ARG_TYPES) {
674 int ord = type.ordinal();
675 char btChar = type.basicTypeChar();
676 mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_FINAL, "copyWithExtend" + btChar, makeSignature(String.valueOf(btChar), false), null, E_THROWABLE);
677 mv.visitCode();
678 // return SPECIES_DATA.extendWith(t).constructor().invokeBasic(mt, lf, argL0, ..., narg)
679 // obtain constructor
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));
730 }
731 }
|
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(types, SPECIES_LOOKUP);
489 }
490
491 static final SpeciesLookup SPECIES_LOOKUP = new SpeciesLookup();
492
493 /**
494 * @implNote this Function class is intentionally made a named inner
495 * class to act as a hook for generating BMHs ahead-of-time.
496 */
497 static class SpeciesLookup implements Function<String, Class<? extends BoundMethodHandle>> {
498 @Override
499 public Class<? extends BoundMethodHandle> apply(String types) {
500 return generateConcreteBMHClass(types);
501 }
502 }
503
504 /**
505 * Generate a concrete subclass of BMH for a given combination of bound types.
506 *
507 * A concrete BMH species adheres to the following schema:
508 *
509 * <pre>
510 * class Species_[[types]] extends BoundMethodHandle {
511 * [[fields]]
512 * final SpeciesData speciesData() { return SpeciesData.get("[[types]]"); }
513 * }
514 * </pre>
515 *
516 * The {@code [[types]]} signature is precisely the string that is passed to this
517 * method.
518 *
519 * The {@code [[fields]]} section consists of one field definition per character in
520 * the type signature, adhering to the naming schema described in the definition of
521 * {@link #makeFieldName}.
549 * }
550 * final BoundMethodHandle copyWithExtendI(MethodType mt, LambdaForm lf, int narg) {
551 * return SPECIES_DATA.extendWith(I_TYPE).constructor().invokeBasic(mt, lf, argL0, argL1, argI2, narg);
552 * }
553 * final BoundMethodHandle copyWithExtendJ(MethodType mt, LambdaForm lf, long narg) {
554 * return SPECIES_DATA.extendWith(J_TYPE).constructor().invokeBasic(mt, lf, argL0, argL1, argI2, narg);
555 * }
556 * final BoundMethodHandle copyWithExtendF(MethodType mt, LambdaForm lf, float narg) {
557 * return SPECIES_DATA.extendWith(F_TYPE).constructor().invokeBasic(mt, lf, argL0, argL1, argI2, narg);
558 * }
559 * public final BoundMethodHandle copyWithExtendD(MethodType mt, LambdaForm lf, double narg) {
560 * return SPECIES_DATA.extendWith(D_TYPE).constructor().invokeBasic(mt, lf, argL0, argL1, argI2, narg);
561 * }
562 * }
563 * </pre>
564 *
565 * @param types the type signature, wherein reference types are erased to 'L'
566 * @return the generated concrete BMH class
567 */
568 static Class<? extends BoundMethodHandle> generateConcreteBMHClass(String types) {
569 String shortTypes = LambdaForm.shortenSignature(types);
570 final String className = SPECIES_PREFIX_PATH + shortTypes;
571 final String sourceFile = SPECIES_PREFIX_NAME + shortTypes;
572
573 byte[] classFile = generateConcreteBMHClassBytes(className, sourceFile, types);
574
575 // load class
576 InvokerBytecodeGenerator.maybeDump(className, classFile);
577 Class<? extends BoundMethodHandle> bmhClass =
578 //UNSAFE.defineAnonymousClass(BoundMethodHandle.class, classFile, null).asSubclass(BoundMethodHandle.class);
579 UNSAFE.defineClass(className, classFile, 0, classFile.length,
580 BoundMethodHandle.class.getClassLoader(), null)
581 .asSubclass(BoundMethodHandle.class);
582
583 return bmhClass;
584 }
585
586 static byte[] generateConcreteBMHClassBytes(final String className, final String sourceFile, final String types) {
587 final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
588 final int NOT_ACC_PUBLIC = 0; // not ACC_PUBLIC
589 cw.visit(V1_6, NOT_ACC_PUBLIC + ACC_FINAL + ACC_SUPER, className, null, BMH, null);
590 cw.visitSource(sourceFile, null);
591 // emit static types and SPECIES_DATA fields
592 FieldVisitor fw = cw.visitField(NOT_ACC_PUBLIC + ACC_STATIC, "SPECIES_DATA", SPECIES_DATA_SIG, null, null);
593 fw.visitAnnotation(STABLE_SIG, true);
594 fw.visitEnd();
595 // emit bound argument fields
596 for (int i = 0; i < types.length(); ++i) {
597 final char t = types.charAt(i);
598 final String fieldName = makeFieldName(types, i);
599 final String fieldDesc = t == 'L' ? JLO_SIG : String.valueOf(t);
600 cw.visitField(ACC_FINAL, fieldName, fieldDesc, null, null).visitEnd();
601 }
602 MethodVisitor mv;
603 // emit constructor
604 mv = cw.visitMethod(ACC_PRIVATE, "<init>", makeSignature(types, true), null, null);
605 mv.visitCode();
606 mv.visitVarInsn(ALOAD, 0); // this
607 mv.visitVarInsn(ALOAD, 1); // type
608 mv.visitVarInsn(ALOAD, 2); // form
609 mv.visitMethodInsn(INVOKESPECIAL, BMH, "<init>", makeSignature("", true), false);
610 for (int i = 0, j = 0; i < types.length(); ++i, ++j) {
611 // i counts the arguments, j counts corresponding argument slots
612 char t = types.charAt(i);
613 mv.visitVarInsn(ALOAD, 0);
614 mv.visitVarInsn(typeLoadOp(t), j + 3); // parameters start at 3
615 mv.visitFieldInsn(PUTFIELD, className, makeFieldName(types, i), typeSig(t));
616 if (t == 'J' || t == 'D') {
617 ++j; // adjust argument register access
618 }
619 }
620 mv.visitInsn(RETURN);
621 mv.visitMaxs(0, 0);
622 mv.visitEnd();
623 // emit implementation of speciesData()
624 mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_FINAL, "speciesData", MYSPECIES_DATA_SIG, null, null);
625 mv.visitCode();
626 mv.visitFieldInsn(GETSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG);
627 mv.visitInsn(ARETURN);
628 mv.visitMaxs(0, 0);
629 mv.visitEnd();
630 // emit implementation of fieldCount()
631 mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_FINAL, "fieldCount", INT_SIG, null, null);
632 mv.visitCode();
633 int fc = types.length();
634 if (fc <= (ICONST_5 - ICONST_0)) {
635 mv.visitInsn(ICONST_0 + fc);
636 } else {
637 mv.visitIntInsn(SIPUSH, fc);
638 }
639 mv.visitInsn(IRETURN);
640 mv.visitMaxs(0, 0);
641 mv.visitEnd();
642 // emit make() ...factory method wrapping constructor
643 mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_STATIC, "make", makeSignature(types, false), null, null);
644 mv.visitCode();
645 // make instance
646 mv.visitTypeInsn(NEW, className);
647 mv.visitInsn(DUP);
648 // load mt, lf
649 mv.visitVarInsn(ALOAD, 0); // type
650 mv.visitVarInsn(ALOAD, 1); // form
651 // load factory method arguments
652 for (int i = 0, j = 0; i < types.length(); ++i, ++j) {
653 // i counts the arguments, j counts corresponding argument slots
654 char t = types.charAt(i);
655 mv.visitVarInsn(typeLoadOp(t), j + 2); // parameters start at 3
656 if (t == 'J' || t == 'D') {
657 ++j; // adjust argument register access
658 }
659 }
660 // finally, invoke the constructor and return
661 mv.visitMethodInsn(INVOKESPECIAL, className, "<init>", makeSignature(types, true), false);
662 mv.visitInsn(ARETURN);
663 mv.visitMaxs(0, 0);
664 mv.visitEnd();
665 // emit copyWith()
666 mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_FINAL, "copyWith", makeSignature("", false), null, null);
667 mv.visitCode();
668 // make instance
669 mv.visitTypeInsn(NEW, className);
670 mv.visitInsn(DUP);
671 // load mt, lf
672 mv.visitVarInsn(ALOAD, 1);
673 mv.visitVarInsn(ALOAD, 2);
674 // put fields on the stack
675 emitPushFields(types, className, mv);
676 // finally, invoke the constructor and return
677 mv.visitMethodInsn(INVOKESPECIAL, className, "<init>", makeSignature(types, true), false);
678 mv.visitInsn(ARETURN);
679 mv.visitMaxs(0, 0);
680 mv.visitEnd();
681 // for each type, emit copyWithExtendT()
682 for (BasicType type : BasicType.ARG_TYPES) {
683 int ord = type.ordinal();
684 char btChar = type.basicTypeChar();
685 mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_FINAL, "copyWithExtend" + btChar, makeSignature(String.valueOf(btChar), false), null, E_THROWABLE);
686 mv.visitCode();
687 // return SPECIES_DATA.extendWith(t).constructor().invokeBasic(mt, lf, argL0, ..., narg)
688 // obtain constructor
689 mv.visitFieldInsn(GETSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG);
690 int iconstInsn = ICONST_0 + ord;
691 assert(iconstInsn <= ICONST_5);
692 mv.visitInsn(iconstInsn);
693 mv.visitMethodInsn(INVOKEVIRTUAL, SPECIES_DATA, "extendWith", BMHSPECIES_DATA_EWI_SIG, false);
694 mv.visitMethodInsn(INVOKEVIRTUAL, SPECIES_DATA, "constructor", "()" + MH_SIG, false);
695 // load mt, lf
696 mv.visitVarInsn(ALOAD, 1);
697 mv.visitVarInsn(ALOAD, 2);
698 // put fields on the stack
699 emitPushFields(types, className, mv);
700 // put narg on stack
701 mv.visitVarInsn(typeLoadOp(btChar), 3);
702 // finally, invoke the constructor and return
703 mv.visitMethodInsn(INVOKEVIRTUAL, MH, "invokeBasic", makeSignature(types + btChar, false), false);
704 mv.visitInsn(ARETURN);
705 mv.visitMaxs(0, 0);
706 mv.visitEnd();
707 }
708 cw.visitEnd();
709 return cw.toByteArray();
710 }
711
712 private static int typeLoadOp(char t) {
713 switch (t) {
714 case 'L': return ALOAD;
715 case 'I': return ILOAD;
716 case 'J': return LLOAD;
717 case 'F': return FLOAD;
718 case 'D': return DLOAD;
719 default : throw newInternalError("unrecognized type " + t);
720 }
721 }
722
723 private static void emitPushFields(String types, String className, MethodVisitor mv) {
724 for (int i = 0; i < types.length(); ++i) {
725 char tc = types.charAt(i);
726 mv.visitVarInsn(ALOAD, 0);
727 mv.visitFieldInsn(GETFIELD, className, makeFieldName(types, i), typeSig(tc));
728 }
729 }
|