< prev index next >

src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java

Print this page
rev 15353 : 8164044: Generate the corresponding BoundMethodHandle to all generated DirectMethodHandles
Reviewed-by: vlivanov, mhaupt


  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 jdk.internal.misc.Unsafe;
  29 import jdk.internal.vm.annotation.ForceInline;
  30 import jdk.internal.vm.annotation.Stable;
  31 import sun.invoke.util.ValueConversions;
  32 import sun.invoke.util.VerifyAccess;
  33 import sun.invoke.util.VerifyType;
  34 import sun.invoke.util.Wrapper;
  35 
  36 import java.lang.ref.WeakReference;
  37 import java.util.Arrays;
  38 import java.util.Objects;
  39 
  40 import static java.lang.invoke.LambdaForm.*;

  41 import static java.lang.invoke.MethodHandleNatives.Constants.*;
  42 import static java.lang.invoke.MethodHandleStatics.UNSAFE;
  43 import static java.lang.invoke.MethodHandleStatics.newInternalError;
  44 import static java.lang.invoke.MethodTypeForm.*;
  45 
  46 /**
  47  * The flavor of method handle which implements a constant reference
  48  * to a class member.
  49  * @author jrose
  50  */
  51 class DirectMethodHandle extends MethodHandle {
  52     final MemberName member;
  53 
  54     // Constructors and factory methods in this class *must* be package scoped or private.
  55     private DirectMethodHandle(MethodType mtype, LambdaForm form, MemberName member) {
  56         super(mtype, form);
  57         if (!member.isResolved())  throw new InternalError();
  58 
  59         if (member.getDeclaringClass().isInterface() &&
  60                 member.isMethod() && !member.isAbstract()) {


 172             which = LF_INVSTATIC_INIT;
 173         }
 174         LambdaForm lform = preparedLambdaForm(mtype, which);
 175         maybeCompile(lform, m);
 176         assert(lform.methodType().dropParameterTypes(0, 1)
 177                 .equals(m.getInvocationType().basicType()))
 178                 : Arrays.asList(m, m.getInvocationType().basicType(), lform, lform.methodType());
 179         return lform;
 180     }
 181 
 182     private static LambdaForm preparedLambdaForm(MethodType mtype, int which) {
 183         LambdaForm lform = mtype.form().cachedLambdaForm(which);
 184         if (lform != null)  return lform;
 185         lform = makePreparedLambdaForm(mtype, which);
 186         return mtype.form().setCachedLambdaForm(which, lform);
 187     }
 188 
 189     static LambdaForm makePreparedLambdaForm(MethodType mtype, int which) {
 190         boolean needsInit = (which == LF_INVSTATIC_INIT);
 191         boolean doesAlloc = (which == LF_NEWINVSPECIAL);
 192         String linkerName, lambdaName;

 193         switch (which) {
 194         case LF_INVVIRTUAL:    linkerName = "linkToVirtual";    lambdaName = "DMH.invokeVirtual";    break;
 195         case LF_INVSTATIC:     linkerName = "linkToStatic";     lambdaName = "DMH.invokeStatic";     break;
 196         case LF_INVSTATIC_INIT:linkerName = "linkToStatic";     lambdaName = "DMH.invokeStaticInit"; break;
 197         case LF_INVSPECIAL:    linkerName = "linkToSpecial";    lambdaName = "DMH.invokeSpecial";    break;
 198         case LF_INVINTERFACE:  linkerName = "linkToInterface";  lambdaName = "DMH.invokeInterface";  break;
 199         case LF_NEWINVSPECIAL: linkerName = "linkToSpecial";    lambdaName = "DMH.newInvokeSpecial"; break;
 200         default:  throw new InternalError("which="+which);
 201         }
 202 
 203         MethodType mtypeWithArg = mtype.appendParameterTypes(MemberName.class);
 204         if (doesAlloc)
 205             mtypeWithArg = mtypeWithArg
 206                     .insertParameterTypes(0, Object.class)  // insert newly allocated obj
 207                     .changeReturnType(void.class);          // <init> returns void
 208         MemberName linker = new MemberName(MethodHandle.class, linkerName, mtypeWithArg, REF_invokeStatic);
 209         try {
 210             linker = IMPL_NAMES.resolveOrFail(REF_invokeStatic, linker, null, NoSuchMethodException.class);
 211         } catch (ReflectiveOperationException ex) {
 212             throw newInternalError(ex);
 213         }
 214         final int DMH_THIS    = 0;
 215         final int ARG_BASE    = 1;
 216         final int ARG_LIMIT   = ARG_BASE + mtype.parameterCount();
 217         int nameCursor = ARG_LIMIT;
 218         final int NEW_OBJ     = (doesAlloc ? nameCursor++ : -1);
 219         final int GET_MEMBER  = nameCursor++;


 223         if (doesAlloc) {
 224             // names = { argx,y,z,... new C, init method }
 225             names[NEW_OBJ] = new Name(NF_allocateInstance, names[DMH_THIS]);
 226             names[GET_MEMBER] = new Name(NF_constructorMethod, names[DMH_THIS]);
 227         } else if (needsInit) {
 228             names[GET_MEMBER] = new Name(NF_internalMemberNameEnsureInit, names[DMH_THIS]);
 229         } else {
 230             names[GET_MEMBER] = new Name(NF_internalMemberName, names[DMH_THIS]);
 231         }
 232         assert(findDirectMethodHandle(names[GET_MEMBER]) == names[DMH_THIS]);
 233         Object[] outArgs = Arrays.copyOfRange(names, ARG_BASE, GET_MEMBER+1, Object[].class);
 234         assert(outArgs[outArgs.length-1] == names[GET_MEMBER]);  // look, shifted args!
 235         int result = LAST_RESULT;
 236         if (doesAlloc) {
 237             assert(outArgs[outArgs.length-2] == names[NEW_OBJ]);  // got to move this one
 238             System.arraycopy(outArgs, 0, outArgs, 1, outArgs.length-2);
 239             outArgs[0] = names[NEW_OBJ];
 240             result = NEW_OBJ;
 241         }
 242         names[LINKER_CALL] = new Name(linker, outArgs);
 243         lambdaName += "_" + shortenSignature(basicTypeSignature(mtype));
 244         LambdaForm lform = new LambdaForm(lambdaName, ARG_LIMIT, names, result);
 245 
 246         // This is a tricky bit of code.  Don't send it through the LF interpreter.
 247         lform.compileToBytecode(Holder.class);
 248         return lform;
 249     }
 250 
 251     static Object findDirectMethodHandle(Name name) {
 252         if (name.function == NF_internalMemberName ||
 253             name.function == NF_internalMemberNameEnsureInit ||
 254             name.function == NF_constructorMethod) {
 255             assert(name.arguments.length == 1);
 256             return name.arguments[0];
 257         }
 258         return null;
 259     }
 260 
 261     private static void maybeCompile(LambdaForm lform, MemberName m) {
 262         if (lform.vmentry == null && VerifyAccess.isSamePackage(m.getDeclaringClass(), MethodHandle.class))
 263             // Help along bootstrapping...
 264             lform.compileToBytecode();
 265     }
 266 
 267     /** Static wrapper for DirectMethodHandle.internalMemberName. */


 688                             .getDeclaredMethod("checkBase", Object.class)),
 689                     NF_staticBase = new NamedFunction(DirectMethodHandle.class
 690                             .getDeclaredMethod("staticBase", Object.class)),
 691                     NF_staticOffset = new NamedFunction(DirectMethodHandle.class
 692                             .getDeclaredMethod("staticOffset", Object.class)),
 693                     NF_checkCast = new NamedFunction(DirectMethodHandle.class
 694                             .getDeclaredMethod("checkCast", Object.class, Object.class)),
 695                     NF_allocateInstance = new NamedFunction(DirectMethodHandle.class
 696                             .getDeclaredMethod("allocateInstance", Object.class)),
 697                     NF_constructorMethod = new NamedFunction(DirectMethodHandle.class
 698                             .getDeclaredMethod("constructorMethod", Object.class))
 699             };
 700             // Each nf must be statically invocable or we get tied up in our bootstraps.
 701             assert(InvokerBytecodeGenerator.isStaticallyInvocable(nfs));
 702         } catch (ReflectiveOperationException ex) {
 703             throw newInternalError(ex);
 704         }
 705     }
 706 
 707     static {
 708         // The DMH class will contain pre-generated DirectMethodHandles resolved
 709         // speculatively using MemberName.getFactory().resolveOrNull. However, that
 710         // doesn't initialize the class, which subtly breaks inlining etc. By forcing
 711         // initialization of the Holder class we avoid these issues.
 712         UNSAFE.ensureClassInitialized(Holder.class);
 713     }
 714 
 715     /* Placeholder class for DirectMethodHandles generated ahead of time */
 716     private final class Holder {}
 717 }


  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 jdk.internal.misc.Unsafe;
  29 import jdk.internal.vm.annotation.ForceInline;
  30 import jdk.internal.vm.annotation.Stable;
  31 import sun.invoke.util.ValueConversions;
  32 import sun.invoke.util.VerifyAccess;
  33 import sun.invoke.util.VerifyType;
  34 import sun.invoke.util.Wrapper;
  35 
  36 import java.lang.ref.WeakReference;
  37 import java.util.Arrays;
  38 import java.util.Objects;
  39 
  40 import static java.lang.invoke.LambdaForm.*;
  41 import static java.lang.invoke.LambdaForm.Kind.*;
  42 import static java.lang.invoke.MethodHandleNatives.Constants.*;
  43 import static java.lang.invoke.MethodHandleStatics.UNSAFE;
  44 import static java.lang.invoke.MethodHandleStatics.newInternalError;
  45 import static java.lang.invoke.MethodTypeForm.*;
  46 
  47 /**
  48  * The flavor of method handle which implements a constant reference
  49  * to a class member.
  50  * @author jrose
  51  */
  52 class DirectMethodHandle extends MethodHandle {
  53     final MemberName member;
  54 
  55     // Constructors and factory methods in this class *must* be package scoped or private.
  56     private DirectMethodHandle(MethodType mtype, LambdaForm form, MemberName member) {
  57         super(mtype, form);
  58         if (!member.isResolved())  throw new InternalError();
  59 
  60         if (member.getDeclaringClass().isInterface() &&
  61                 member.isMethod() && !member.isAbstract()) {


 173             which = LF_INVSTATIC_INIT;
 174         }
 175         LambdaForm lform = preparedLambdaForm(mtype, which);
 176         maybeCompile(lform, m);
 177         assert(lform.methodType().dropParameterTypes(0, 1)
 178                 .equals(m.getInvocationType().basicType()))
 179                 : Arrays.asList(m, m.getInvocationType().basicType(), lform, lform.methodType());
 180         return lform;
 181     }
 182 
 183     private static LambdaForm preparedLambdaForm(MethodType mtype, int which) {
 184         LambdaForm lform = mtype.form().cachedLambdaForm(which);
 185         if (lform != null)  return lform;
 186         lform = makePreparedLambdaForm(mtype, which);
 187         return mtype.form().setCachedLambdaForm(which, lform);
 188     }
 189 
 190     static LambdaForm makePreparedLambdaForm(MethodType mtype, int which) {
 191         boolean needsInit = (which == LF_INVSTATIC_INIT);
 192         boolean doesAlloc = (which == LF_NEWINVSPECIAL);
 193         String linkerName;
 194         LambdaForm.Kind kind;
 195         switch (which) {
 196         case LF_INVVIRTUAL:    linkerName = "linkToVirtual";   kind = DIRECT_INVOKE_VIRTUAL;     break;
 197         case LF_INVSTATIC:     linkerName = "linkToStatic";    kind = DIRECT_INVOKE_STATIC;      break;
 198         case LF_INVSTATIC_INIT:linkerName = "linkToStatic";    kind = DIRECT_INVOKE_STATIC_INIT; break;
 199         case LF_INVSPECIAL:    linkerName = "linkToSpecial";   kind = DIRECT_INVOKE_SPECIAL;     break;
 200         case LF_INVINTERFACE:  linkerName = "linkToInterface"; kind = DIRECT_INVOKE_INTERFACE;   break;
 201         case LF_NEWINVSPECIAL: linkerName = "linkToSpecial";   kind = DIRECT_NEW_INVOKE_SPECIAL; break;
 202         default:  throw new InternalError("which="+which);
 203         }
 204 
 205         MethodType mtypeWithArg = mtype.appendParameterTypes(MemberName.class);
 206         if (doesAlloc)
 207             mtypeWithArg = mtypeWithArg
 208                     .insertParameterTypes(0, Object.class)  // insert newly allocated obj
 209                     .changeReturnType(void.class);          // <init> returns void
 210         MemberName linker = new MemberName(MethodHandle.class, linkerName, mtypeWithArg, REF_invokeStatic);
 211         try {
 212             linker = IMPL_NAMES.resolveOrFail(REF_invokeStatic, linker, null, NoSuchMethodException.class);
 213         } catch (ReflectiveOperationException ex) {
 214             throw newInternalError(ex);
 215         }
 216         final int DMH_THIS    = 0;
 217         final int ARG_BASE    = 1;
 218         final int ARG_LIMIT   = ARG_BASE + mtype.parameterCount();
 219         int nameCursor = ARG_LIMIT;
 220         final int NEW_OBJ     = (doesAlloc ? nameCursor++ : -1);
 221         final int GET_MEMBER  = nameCursor++;


 225         if (doesAlloc) {
 226             // names = { argx,y,z,... new C, init method }
 227             names[NEW_OBJ] = new Name(NF_allocateInstance, names[DMH_THIS]);
 228             names[GET_MEMBER] = new Name(NF_constructorMethod, names[DMH_THIS]);
 229         } else if (needsInit) {
 230             names[GET_MEMBER] = new Name(NF_internalMemberNameEnsureInit, names[DMH_THIS]);
 231         } else {
 232             names[GET_MEMBER] = new Name(NF_internalMemberName, names[DMH_THIS]);
 233         }
 234         assert(findDirectMethodHandle(names[GET_MEMBER]) == names[DMH_THIS]);
 235         Object[] outArgs = Arrays.copyOfRange(names, ARG_BASE, GET_MEMBER+1, Object[].class);
 236         assert(outArgs[outArgs.length-1] == names[GET_MEMBER]);  // look, shifted args!
 237         int result = LAST_RESULT;
 238         if (doesAlloc) {
 239             assert(outArgs[outArgs.length-2] == names[NEW_OBJ]);  // got to move this one
 240             System.arraycopy(outArgs, 0, outArgs, 1, outArgs.length-2);
 241             outArgs[0] = names[NEW_OBJ];
 242             result = NEW_OBJ;
 243         }
 244         names[LINKER_CALL] = new Name(linker, outArgs);
 245         String lambdaName = kind.defaultLambdaName + "_" + shortenSignature(basicTypeSignature(mtype));
 246         LambdaForm lform = new LambdaForm(lambdaName, ARG_LIMIT, names, result, kind);
 247 
 248         // This is a tricky bit of code.  Don't send it through the LF interpreter.
 249         lform.compileToBytecode();
 250         return lform;
 251     }
 252 
 253     static Object findDirectMethodHandle(Name name) {
 254         if (name.function == NF_internalMemberName ||
 255             name.function == NF_internalMemberNameEnsureInit ||
 256             name.function == NF_constructorMethod) {
 257             assert(name.arguments.length == 1);
 258             return name.arguments[0];
 259         }
 260         return null;
 261     }
 262 
 263     private static void maybeCompile(LambdaForm lform, MemberName m) {
 264         if (lform.vmentry == null && VerifyAccess.isSamePackage(m.getDeclaringClass(), MethodHandle.class))
 265             // Help along bootstrapping...
 266             lform.compileToBytecode();
 267     }
 268 
 269     /** Static wrapper for DirectMethodHandle.internalMemberName. */


 690                             .getDeclaredMethod("checkBase", Object.class)),
 691                     NF_staticBase = new NamedFunction(DirectMethodHandle.class
 692                             .getDeclaredMethod("staticBase", Object.class)),
 693                     NF_staticOffset = new NamedFunction(DirectMethodHandle.class
 694                             .getDeclaredMethod("staticOffset", Object.class)),
 695                     NF_checkCast = new NamedFunction(DirectMethodHandle.class
 696                             .getDeclaredMethod("checkCast", Object.class, Object.class)),
 697                     NF_allocateInstance = new NamedFunction(DirectMethodHandle.class
 698                             .getDeclaredMethod("allocateInstance", Object.class)),
 699                     NF_constructorMethod = new NamedFunction(DirectMethodHandle.class
 700                             .getDeclaredMethod("constructorMethod", Object.class))
 701             };
 702             // Each nf must be statically invocable or we get tied up in our bootstraps.
 703             assert(InvokerBytecodeGenerator.isStaticallyInvocable(nfs));
 704         } catch (ReflectiveOperationException ex) {
 705             throw newInternalError(ex);
 706         }
 707     }
 708 
 709     static {
 710         // The Holder class will contain pre-generated DirectMethodHandles resolved
 711         // speculatively using MemberName.getFactory().resolveOrNull. However, that
 712         // doesn't initialize the class, which subtly breaks inlining etc. By forcing
 713         // initialization of the Holder class we avoid these issues.
 714         UNSAFE.ensureClassInitialized(Holder.class);
 715     }
 716 
 717     /* Placeholder class for DirectMethodHandles generated ahead of time */
 718     final class Holder {}
 719 }
< prev index next >