src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
Index Unified diffs Context diffs Sdiffs Patch New Old Previous File Next File jdk Cdiff src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java

src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java

Print this page
rev 9088 : 8027827: Improve performance of catchException combinator
Reviewed-by: ?
rev 9089 : [mq]: 8027827.catchException.custom.webrev01
rev 9091 : [mq]: 8027827.catchException.ver03
rev 9092 : [mq]: 8027827.caching

*** 25,35 **** package java.lang.invoke; import sun.invoke.util.VerifyAccess; import java.lang.invoke.LambdaForm.Name; - import java.lang.invoke.MethodHandles.Lookup; import sun.invoke.util.Wrapper; import java.io.*; import java.util.*; --- 25,34 ----
*** 37,59 **** import jdk.internal.org.objectweb.asm.*; import java.lang.reflect.*; import static java.lang.invoke.MethodHandleStatics.*; import static java.lang.invoke.MethodHandleNatives.Constants.*; - import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; - import sun.invoke.util.ValueConversions; import sun.invoke.util.VerifyType; /** * Code generation backend for LambdaForm. * <p> * @author John Rose, JSR 292 EG */ class InvokerBytecodeGenerator { /** Define class names for convenience. */ private static final String MH = "java/lang/invoke/MethodHandle"; - private static final String BMH = "java/lang/invoke/BoundMethodHandle"; private static final String LF = "java/lang/invoke/LambdaForm"; private static final String LFN = "java/lang/invoke/LambdaForm$Name"; private static final String CLS = "java/lang/Class"; private static final String OBJ = "java/lang/Object"; private static final String OBJARY = "[Ljava/lang/Object;"; --- 36,55 ----
*** 514,529 **** --- 510,532 ---- if (isSelectAlternative(member)) { // selectAlternative idiom // FIXME: make sure this idiom is really present! emitSelectAlternative(name, lambdaForm.names[i + 1]); i++; // skip MH.invokeBasic of the selectAlternative result + } else if (isGuardWithCatch(i)) { + emitGuardWithCatch(i); + i = i+2; // Jump to the end of GWC idiom } else if (isStaticallyInvocable(member)) { emitStaticInvoke(member, name); } else { emitInvoke(name); } + // Update cached form name's info in case an intrinsic spanning multiple names was encountered. + name = lambdaForm.names[i]; + member = name.function.member(); + // store the result from evaluating to the target name in a local if required // (if this is the last value, i.e., the one that is going to be returned, // avoid store/load/return and just return) if (i == lambdaForm.names.length - 1 && i == lambdaForm.result) { // return value - do nothing
*** 672,687 **** } throw new InternalError("refKind="+refKind); } /** * Check if MemberName is a call to MethodHandleImpl.selectAlternative. */ private boolean isSelectAlternative(MemberName member) { ! return member != null && ! member.getDeclaringClass() == MethodHandleImpl.class && ! member.getName().equals("selectAlternative"); } /** * Emit bytecode for the selectAlternative idiom. * --- 675,697 ---- } throw new InternalError("refKind="+refKind); } /** + * Check if MemberName is a call to a method named {@code name} in class {@code declaredClass}. + */ + private boolean memberNameRefersTo(MemberName member, Class<?> declaringClass, String name) { + return member != null && + member.getDeclaringClass() == declaringClass && + member.getName().equals(name); + } + + /** * Check if MemberName is a call to MethodHandleImpl.selectAlternative. */ private boolean isSelectAlternative(MemberName member) { ! return memberNameRefersTo(member, MethodHandleImpl.class, "selectAlternative"); } /** * Emit bytecode for the selectAlternative idiom. *
*** 728,737 **** --- 738,839 ---- // L_done: mv.visitLabel(L_done); } + /** + * Check if i-th name is a start of GuardWithCatch idiom. + */ + private boolean isGuardWithCatch(int pos) { + // GuardWithCatch idiom: + // t_{n}:L=MethodHandle.invokeBasic(...) + // t_{n+1}:L=MethodHandleImpl.guardWithCatch(...); + // t_{n+2}:I=MethodHandle.invokeBasic(...) + return lambdaForm.names.length-1 >= pos+2 && + memberNameRefersTo(lambdaForm.names[pos+1].function.member(), + MethodHandleImpl.class, "guardWithCatch"); + } + + /** + * Emit bytecode for the guardWithCatch idiom. + * + * The pattern looks like (Cf. MethodHandleImpl.makeGuardWithCatch): + * <blockquote><pre>{@code + * guardWithCatch=Lambda(a0:L,a1:L,a2:L,a3:L,a4:L,a5:L,a6:L,a7:L)=>{ + * t8:L=MethodHandle.invokeBasic(a4:L,a6:L,a7:L); + * t9:L=MethodHandleImpl.guardWithCatch(a1:L,a2:L,a3:L,t8:L); + * t10:I=MethodHandle.invokeBasic(a5:L,t9:L);t10:I} + * }</pre></blockquote> + * + * It is compiled into bytecode equivalent of the following code: + * <blockquote><pre>{@code + * try { + * return a1.invokeBasic(a6, a7); + * } catch (Throwable e) { + * if (!a2.isInstance(e)) throw e; + * return a3.invokeBasic(ex, a6, a7); + * }} + */ + private void emitGuardWithCatch(int pos) { + Name args = lambdaForm.names[pos]; + Name invoker = lambdaForm.names[pos+1]; + Name result = lambdaForm.names[pos+2]; + + Label L_startBlock = new Label(); + Label L_endBlock = new Label(); + Label L_handler = new Label(); + Label L_done = new Label(); + + Class<?> returnType = result.function.resolvedHandle.type().returnType(); + MethodType type = args.function.resolvedHandle.type() + .dropParameterTypes(0,1) + .changeReturnType(returnType); + + mv.visitTryCatchBlock(L_startBlock, L_endBlock, L_handler, "java/lang/Throwable"); + + // Normal case + mv.visitLabel(L_startBlock); + // load target + emitPushArgument(invoker, 0); + emitPushArguments(args, 1); // skip 1st argument: method handle + mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, MH, "invokeBasic", type.basicType().toMethodDescriptorString()); + mv.visitLabel(L_endBlock); + mv.visitJumpInsn(Opcodes.GOTO, L_done); + + // Exceptional case + mv.visitLabel(L_handler); + + // Check exception's type + mv.visitInsn(Opcodes.DUP); + // load exception class + emitPushArgument(invoker, 1); + mv.visitInsn(Opcodes.SWAP); + mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "isInstance", "(Ljava/lang/Object;)Z"); + Label L_rethrow = new Label(); + mv.visitJumpInsn(Opcodes.IFEQ, L_rethrow); + + // Invoke catcher + // load catcher + emitPushArgument(invoker, 2); + mv.visitInsn(Opcodes.SWAP); + emitPushArguments(args, 1); // skip 1st argument: method handle + MethodType catcherType = type.insertParameterTypes(0, Throwable.class); + mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, MH, "invokeBasic", catcherType.basicType().toMethodDescriptorString()); + mv.visitJumpInsn(Opcodes.GOTO, L_done); + + mv.visitLabel(L_rethrow); + mv.visitInsn(Opcodes.ATHROW); + + mv.visitLabel(L_done); + } + + private void emitPushArguments(Name args, int start) { + for (int i = start; i < args.arguments.length; i++) { + emitPushArgument(args, i); + } + } + private void emitPushArgument(Name name, int paramIndex) { Object arg = name.arguments[paramIndex]; char ptype = name.function.parameterType(paramIndex); MethodType mtype = name.function.methodType(); if (arg instanceof Name) {
src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
Index Unified diffs Context diffs Sdiffs Patch New Old Previous File Next File