599 mv.visitInsn(opcode);
600 }
601
602 private static String getInternalName(Class<?> c) {
603 if (c == Object.class) return OBJ;
604 else if (c == Object[].class) return OBJARY;
605 else if (c == Class.class) return CLS;
606 else if (c == MethodHandle.class) return MH;
607 assert(VerifyAccess.isTypeVisible(c, Object.class)) : c.getName();
608 return c.getName().replace('.', '/');
609 }
610
611 /**
612 * Generate customized bytecode for a given LambdaForm.
613 */
614 static MemberName generateCustomizedCode(LambdaForm form, MethodType invokerType) {
615 InvokerBytecodeGenerator g = new InvokerBytecodeGenerator("MH", form, invokerType);
616 return g.loadMethod(g.generateCustomizedCodeBytes());
617 }
618
619 /**
620 * Generate an invoker method for the passed {@link LambdaForm}.
621 */
622 private byte[] generateCustomizedCodeBytes() {
623 classFilePrologue();
624
625 // Suppress this method in backtraces displayed to the user.
626 mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Hidden;", true);
627
628 // Mark this method as a compiled LambdaForm
629 mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Compiled;", true);
630
631 if (lambdaForm.forceInline) {
632 // Force inlining of this invoker method.
633 mv.visitAnnotation("Ljava/lang/invoke/ForceInline;", true);
634 } else {
635 mv.visitAnnotation("Ljava/lang/invoke/DontInline;", true);
636 }
637
638
639 // iterate over the form's names, generating bytecode instructions for each
640 // start iterating at the first name following the arguments
641 Name onStack = null;
642 for (int i = lambdaForm.arity; i < lambdaForm.names.length; i++) {
643 Name name = lambdaForm.names[i];
644
645 emitStoreResult(onStack);
646 onStack = name; // unless otherwise modified below
647 MethodHandleImpl.Intrinsic intr = name.function.intrinsicName();
648 switch (intr) {
649 case SELECT_ALTERNATIVE:
650 assert isSelectAlternative(i);
651 onStack = emitSelectAlternative(name, lambdaForm.names[i+1]);
652 i++; // skip MH.invokeBasic of the selectAlternative result
653 continue;
654 case GUARD_WITH_CATCH:
655 assert isGuardWithCatch(i);
656 onStack = emitGuardWithCatch(i);
657 i = i+2; // Jump to the end of GWC idiom
658 continue;
988 *
989 * The pattern looks like (Cf. MethodHandleImpl.makeGuardWithTest):
990 * <blockquote><pre>{@code
991 * Lambda(a0:L,a1:I)=>{
992 * t2:I=foo.test(a1:I);
993 * t3:L=MethodHandleImpl.selectAlternative(t2:I,(MethodHandle(int)int),(MethodHandle(int)int));
994 * t4:I=MethodHandle.invokeBasic(t3:L,a1:I);t4:I}
995 * }</pre></blockquote>
996 */
997 private Name emitSelectAlternative(Name selectAlternativeName, Name invokeBasicName) {
998 assert isStaticallyInvocable(invokeBasicName);
999
1000 Name receiver = (Name) invokeBasicName.arguments[0];
1001
1002 Label L_fallback = new Label();
1003 Label L_done = new Label();
1004
1005 // load test result
1006 emitPushArgument(selectAlternativeName, 0);
1007
1008 // if_icmpne L_fallback
1009 mv.visitJumpInsn(Opcodes.IFEQ, L_fallback);
1010
1011 // invoke selectAlternativeName.arguments[1]
1012 Class<?>[] preForkClasses = localClasses.clone();
1013 emitPushArgument(selectAlternativeName, 1); // get 2nd argument of selectAlternative
1014 emitAstoreInsn(receiver.index()); // store the MH in the receiver slot
1015 emitStaticInvoke(invokeBasicName);
1016
1017 // goto L_done
1018 mv.visitJumpInsn(Opcodes.GOTO, L_done);
1019
1020 // L_fallback:
1021 mv.visitLabel(L_fallback);
1022
1023 // invoke selectAlternativeName.arguments[2]
1024 System.arraycopy(preForkClasses, 0, localClasses, 0, preForkClasses.length);
1025 emitPushArgument(selectAlternativeName, 2); // get 3rd argument of selectAlternative
1026 emitAstoreInsn(receiver.index()); // store the MH in the receiver slot
1027 emitStaticInvoke(invokeBasicName);
|
599 mv.visitInsn(opcode);
600 }
601
602 private static String getInternalName(Class<?> c) {
603 if (c == Object.class) return OBJ;
604 else if (c == Object[].class) return OBJARY;
605 else if (c == Class.class) return CLS;
606 else if (c == MethodHandle.class) return MH;
607 assert(VerifyAccess.isTypeVisible(c, Object.class)) : c.getName();
608 return c.getName().replace('.', '/');
609 }
610
611 /**
612 * Generate customized bytecode for a given LambdaForm.
613 */
614 static MemberName generateCustomizedCode(LambdaForm form, MethodType invokerType) {
615 InvokerBytecodeGenerator g = new InvokerBytecodeGenerator("MH", form, invokerType);
616 return g.loadMethod(g.generateCustomizedCodeBytes());
617 }
618
619 /** Determines whether a LambdaForm being compiled contains an intrinsic of some particular type. */
620 private boolean containsIntrinsic(MethodHandleImpl.Intrinsic intr) {
621 for (int i = lambdaForm.arity; i < lambdaForm.names.length; i++) {
622 Name name = lambdaForm.names[i];
623 if (name.function.intrinsicName() == intr) {
624 return true;
625 }
626 }
627 return false;
628 }
629
630 /**
631 * Generate an invoker method for the passed {@link LambdaForm}.
632 */
633 private byte[] generateCustomizedCodeBytes() {
634 classFilePrologue();
635
636 // Suppress this method in backtraces displayed to the user.
637 mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Hidden;", true);
638
639 // Mark this method as a compiled LambdaForm
640 mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Compiled;", true);
641
642 if (PROFILE_GWT && containsIntrinsic(MethodHandleImpl.Intrinsic.SELECT_ALTERNATIVE)) {
643 // For now, mark only GWT LambdaForms as @Shared.
644 // TODO: consider marking other non-customized LambdaForms as @Shared
645 mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Shared;", true);
646 }
647
648 if (lambdaForm.forceInline) {
649 // Force inlining of this invoker method.
650 mv.visitAnnotation("Ljava/lang/invoke/ForceInline;", true);
651 } else {
652 mv.visitAnnotation("Ljava/lang/invoke/DontInline;", true);
653 }
654
655 // iterate over the form's names, generating bytecode instructions for each
656 // start iterating at the first name following the arguments
657 Name onStack = null;
658 for (int i = lambdaForm.arity; i < lambdaForm.names.length; i++) {
659 Name name = lambdaForm.names[i];
660
661 emitStoreResult(onStack);
662 onStack = name; // unless otherwise modified below
663 MethodHandleImpl.Intrinsic intr = name.function.intrinsicName();
664 switch (intr) {
665 case SELECT_ALTERNATIVE:
666 assert isSelectAlternative(i);
667 onStack = emitSelectAlternative(name, lambdaForm.names[i+1]);
668 i++; // skip MH.invokeBasic of the selectAlternative result
669 continue;
670 case GUARD_WITH_CATCH:
671 assert isGuardWithCatch(i);
672 onStack = emitGuardWithCatch(i);
673 i = i+2; // Jump to the end of GWC idiom
674 continue;
1004 *
1005 * The pattern looks like (Cf. MethodHandleImpl.makeGuardWithTest):
1006 * <blockquote><pre>{@code
1007 * Lambda(a0:L,a1:I)=>{
1008 * t2:I=foo.test(a1:I);
1009 * t3:L=MethodHandleImpl.selectAlternative(t2:I,(MethodHandle(int)int),(MethodHandle(int)int));
1010 * t4:I=MethodHandle.invokeBasic(t3:L,a1:I);t4:I}
1011 * }</pre></blockquote>
1012 */
1013 private Name emitSelectAlternative(Name selectAlternativeName, Name invokeBasicName) {
1014 assert isStaticallyInvocable(invokeBasicName);
1015
1016 Name receiver = (Name) invokeBasicName.arguments[0];
1017
1018 Label L_fallback = new Label();
1019 Label L_done = new Label();
1020
1021 // load test result
1022 emitPushArgument(selectAlternativeName, 0);
1023
1024 if (PROFILE_GWT) {
1025 emitPushArgument(selectAlternativeName, 3);
1026 mv.visitMethodInsn(Opcodes.INVOKESTATIC, MHI, "profileBranch", "(Z[I)Z", false);
1027 }
1028
1029 // if_icmpne L_fallback
1030 mv.visitJumpInsn(Opcodes.IFEQ, L_fallback);
1031
1032 // invoke selectAlternativeName.arguments[1]
1033 Class<?>[] preForkClasses = localClasses.clone();
1034 emitPushArgument(selectAlternativeName, 1); // get 2nd argument of selectAlternative
1035 emitAstoreInsn(receiver.index()); // store the MH in the receiver slot
1036 emitStaticInvoke(invokeBasicName);
1037
1038 // goto L_done
1039 mv.visitJumpInsn(Opcodes.GOTO, L_done);
1040
1041 // L_fallback:
1042 mv.visitLabel(L_fallback);
1043
1044 // invoke selectAlternativeName.arguments[2]
1045 System.arraycopy(preForkClasses, 0, localClasses, 0, preForkClasses.length);
1046 emitPushArgument(selectAlternativeName, 2); // get 3rd argument of selectAlternative
1047 emitAstoreInsn(receiver.index()); // store the MH in the receiver slot
1048 emitStaticInvoke(invokeBasicName);
|