< prev index next >

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

Print this page
rev 13050 : 8142334: Improve lazy initialization of java.lang.invoke
Reviewed-by: psandoz, vlivanov, mhaupt


 256         } else {
 257             invokerFormType = invokerFormType.invokerType();
 258         }
 259         Name[] names = arguments(nameCursor - INARG_LIMIT, invokerFormType);
 260         assert(names.length == nameCursor)
 261                 : Arrays.asList(mtype, customized, which, nameCursor, names.length);
 262         if (MTYPE_ARG >= INARG_LIMIT) {
 263             assert(names[MTYPE_ARG] == null);
 264             BoundMethodHandle.SpeciesData speciesData = BoundMethodHandle.speciesData_L();
 265             names[THIS_MH] = names[THIS_MH].withConstraint(speciesData);
 266             NamedFunction getter = speciesData.getterFunction(0);
 267             names[MTYPE_ARG] = new Name(getter, names[THIS_MH]);
 268             // else if isLinker, then MTYPE is passed in from the caller (e.g., the JVM)
 269         }
 270 
 271         // Make the final call.  If isGeneric, then prepend the result of type checking.
 272         MethodType outCallType = mtype.basicType();
 273         Object[] outArgs = Arrays.copyOfRange(names, CALL_MH, OUTARG_LIMIT, Object[].class);
 274         Object mtypeArg = (customized ? mtype : names[MTYPE_ARG]);
 275         if (!isGeneric) {
 276             names[CHECK_TYPE] = new Name(NF_checkExactType, names[CALL_MH], mtypeArg);
 277             // mh.invokeExact(a*):R => checkExactType(mh, TYPEOF(a*:R)); mh.invokeBasic(a*)
 278         } else {
 279             names[CHECK_TYPE] = new Name(NF_checkGenericType, names[CALL_MH], mtypeArg);
 280             // mh.invokeGeneric(a*):R => checkGenericType(mh, TYPEOF(a*:R)).invokeBasic(a*)
 281             outArgs[0] = names[CHECK_TYPE];
 282         }
 283         if (CHECK_CUSTOM != -1) {
 284             names[CHECK_CUSTOM] = new Name(NF_checkCustomized, outArgs[0]);
 285         }
 286         names[LINKER_CALL] = new Name(outCallType, outArgs);
 287         lform = new LambdaForm(debugName, INARG_LIMIT, names);
 288         if (isLinker)
 289             lform.compileToBytecode();  // JVM needs a real methodOop
 290         if (isCached)
 291             lform = mtype.form().setCachedLambdaForm(which, lform);
 292         return lform;
 293     }
 294 
 295     /*non-public*/ static
 296     WrongMethodTypeException newWrongMethodTypeException(MethodType actual, MethodType expected) {
 297         // FIXME: merge with JVM logic for throwing WMTE
 298         return new WrongMethodTypeException("expected "+expected+" but found "+actual);
 299     }
 300 
 301     /** Static definition of MethodHandle.invokeExact checking code. */
 302     /*non-public*/ static
 303     @ForceInline
 304     void checkExactType(Object mhObj, Object expectedObj) {


 352     private static LambdaForm callSiteForm(MethodType mtype, boolean skipCallSite) {
 353         mtype = mtype.basicType();  // normalize Z to I, String to Object, etc.
 354         final int which = (skipCallSite ? MethodTypeForm.LF_MH_LINKER : MethodTypeForm.LF_CS_LINKER);
 355         LambdaForm lform = mtype.form().cachedLambdaForm(which);
 356         if (lform != null)  return lform;
 357         // exactInvokerForm (Object,Object)Object
 358         //   link with java.lang.invoke.MethodHandle.invokeBasic(MethodHandle,Object,Object)Object/invokeSpecial
 359         final int ARG_BASE     = 0;
 360         final int OUTARG_LIMIT = ARG_BASE + mtype.parameterCount();
 361         final int INARG_LIMIT  = OUTARG_LIMIT + 1;
 362         int nameCursor = OUTARG_LIMIT;
 363         final int APPENDIX_ARG = nameCursor++;  // the last in-argument
 364         final int CSITE_ARG    = skipCallSite ? -1 : APPENDIX_ARG;
 365         final int CALL_MH      = skipCallSite ? APPENDIX_ARG : nameCursor++;  // result of getTarget
 366         final int LINKER_CALL  = nameCursor++;
 367         MethodType invokerFormType = mtype.appendParameterTypes(skipCallSite ? MethodHandle.class : CallSite.class);
 368         Name[] names = arguments(nameCursor - INARG_LIMIT, invokerFormType);
 369         assert(names.length == nameCursor);
 370         assert(names[APPENDIX_ARG] != null);
 371         if (!skipCallSite)
 372             names[CALL_MH] = new Name(NF_getCallSiteTarget, names[CSITE_ARG]);
 373         // (site.)invokedynamic(a*):R => mh = site.getTarget(); mh.invokeBasic(a*)
 374         final int PREPEND_MH = 0, PREPEND_COUNT = 1;
 375         Object[] outArgs = Arrays.copyOfRange(names, ARG_BASE, OUTARG_LIMIT + PREPEND_COUNT, Object[].class);
 376         // prepend MH argument:
 377         System.arraycopy(outArgs, 0, outArgs, PREPEND_COUNT, outArgs.length - PREPEND_COUNT);
 378         outArgs[PREPEND_MH] = names[CALL_MH];
 379         names[LINKER_CALL] = new Name(mtype, outArgs);
 380         lform = new LambdaForm((skipCallSite ? "linkToTargetMethod" : "linkToCallSite"), INARG_LIMIT, names);
 381         lform.compileToBytecode();  // JVM needs a real methodOop
 382         lform = mtype.form().setCachedLambdaForm(which, lform);
 383         return lform;
 384     }
 385 
 386     /** Static definition of MethodHandle.invokeGeneric checking code. */
 387     /*non-public*/ static
 388     @ForceInline
 389     Object getCallSiteTarget(Object site) {
 390         return ((CallSite)site).getTarget();
 391     }
 392 


 394     @ForceInline
 395     void checkCustomized(Object o) {
 396         MethodHandle mh = (MethodHandle)o;
 397         if (MethodHandleImpl.isCompileConstant(mh)) return;
 398         if (mh.form.customized == null) {
 399             maybeCustomize(mh);
 400         }
 401     }
 402 
 403     /*non-public*/ static
 404     @DontInline
 405     void maybeCustomize(MethodHandle mh) {
 406         byte count = mh.customizationCount;
 407         if (count >= CUSTOMIZE_THRESHOLD) {
 408             mh.customize();
 409         } else {
 410             mh.customizationCount = (byte)(count+1);
 411         }
 412     }
 413 



























 414     // Local constant functions:
 415     private static final NamedFunction
 416         NF_checkExactType,
 417         NF_checkGenericType,
 418         NF_getCallSiteTarget,
 419         NF_checkCustomized;
 420     static {
 421         try {
 422             NamedFunction nfs[] = {
 423                 NF_checkExactType = new NamedFunction(Invokers.class
 424                         .getDeclaredMethod("checkExactType", Object.class, Object.class)),
 425                 NF_checkGenericType = new NamedFunction(Invokers.class
 426                         .getDeclaredMethod("checkGenericType", Object.class, Object.class)),
 427                 NF_getCallSiteTarget = new NamedFunction(Invokers.class
 428                         .getDeclaredMethod("getCallSiteTarget", Object.class)),
 429                 NF_checkCustomized = new NamedFunction(Invokers.class
 430                         .getDeclaredMethod("checkCustomized", Object.class))
 431             };
 432             for (NamedFunction nf : nfs) {
 433                 // Each nf must be statically invocable or we get tied up in our bootstraps.
 434                 assert(InvokerBytecodeGenerator.isStaticallyInvocable(nf.member)) : nf;
 435                 nf.resolve();
 436             }
 437         } catch (ReflectiveOperationException ex) {
 438             throw newInternalError(ex);
 439         }

 440     }
 441 
 442     private static class Lazy {
 443         private static final MethodHandle MH_asSpreader;
 444 
 445         static {
 446             try {
 447                 MH_asSpreader = IMPL_LOOKUP.findVirtual(MethodHandle.class, "asSpreader",
 448                         MethodType.methodType(MethodHandle.class, Class.class, int.class));
 449             } catch (ReflectiveOperationException ex) {
 450                 throw newInternalError(ex);
 451             }
 452         }
 453     }
 454 }


 256         } else {
 257             invokerFormType = invokerFormType.invokerType();
 258         }
 259         Name[] names = arguments(nameCursor - INARG_LIMIT, invokerFormType);
 260         assert(names.length == nameCursor)
 261                 : Arrays.asList(mtype, customized, which, nameCursor, names.length);
 262         if (MTYPE_ARG >= INARG_LIMIT) {
 263             assert(names[MTYPE_ARG] == null);
 264             BoundMethodHandle.SpeciesData speciesData = BoundMethodHandle.speciesData_L();
 265             names[THIS_MH] = names[THIS_MH].withConstraint(speciesData);
 266             NamedFunction getter = speciesData.getterFunction(0);
 267             names[MTYPE_ARG] = new Name(getter, names[THIS_MH]);
 268             // else if isLinker, then MTYPE is passed in from the caller (e.g., the JVM)
 269         }
 270 
 271         // Make the final call.  If isGeneric, then prepend the result of type checking.
 272         MethodType outCallType = mtype.basicType();
 273         Object[] outArgs = Arrays.copyOfRange(names, CALL_MH, OUTARG_LIMIT, Object[].class);
 274         Object mtypeArg = (customized ? mtype : names[MTYPE_ARG]);
 275         if (!isGeneric) {
 276             names[CHECK_TYPE] = new Name(getConstantFunction(NF_checkExactType), names[CALL_MH], mtypeArg);
 277             // mh.invokeExact(a*):R => checkExactType(mh, TYPEOF(a*:R)); mh.invokeBasic(a*)
 278         } else {
 279             names[CHECK_TYPE] = new Name(getConstantFunction(NF_checkGenericType), names[CALL_MH], mtypeArg);
 280             // mh.invokeGeneric(a*):R => checkGenericType(mh, TYPEOF(a*:R)).invokeBasic(a*)
 281             outArgs[0] = names[CHECK_TYPE];
 282         }
 283         if (CHECK_CUSTOM != -1) {
 284             names[CHECK_CUSTOM] = new Name(getConstantFunction(NF_checkCustomized), outArgs[0]);
 285         }
 286         names[LINKER_CALL] = new Name(outCallType, outArgs);
 287         lform = new LambdaForm(debugName, INARG_LIMIT, names);
 288         if (isLinker)
 289             lform.compileToBytecode();  // JVM needs a real methodOop
 290         if (isCached)
 291             lform = mtype.form().setCachedLambdaForm(which, lform);
 292         return lform;
 293     }
 294 
 295     /*non-public*/ static
 296     WrongMethodTypeException newWrongMethodTypeException(MethodType actual, MethodType expected) {
 297         // FIXME: merge with JVM logic for throwing WMTE
 298         return new WrongMethodTypeException("expected "+expected+" but found "+actual);
 299     }
 300 
 301     /** Static definition of MethodHandle.invokeExact checking code. */
 302     /*non-public*/ static
 303     @ForceInline
 304     void checkExactType(Object mhObj, Object expectedObj) {


 352     private static LambdaForm callSiteForm(MethodType mtype, boolean skipCallSite) {
 353         mtype = mtype.basicType();  // normalize Z to I, String to Object, etc.
 354         final int which = (skipCallSite ? MethodTypeForm.LF_MH_LINKER : MethodTypeForm.LF_CS_LINKER);
 355         LambdaForm lform = mtype.form().cachedLambdaForm(which);
 356         if (lform != null)  return lform;
 357         // exactInvokerForm (Object,Object)Object
 358         //   link with java.lang.invoke.MethodHandle.invokeBasic(MethodHandle,Object,Object)Object/invokeSpecial
 359         final int ARG_BASE     = 0;
 360         final int OUTARG_LIMIT = ARG_BASE + mtype.parameterCount();
 361         final int INARG_LIMIT  = OUTARG_LIMIT + 1;
 362         int nameCursor = OUTARG_LIMIT;
 363         final int APPENDIX_ARG = nameCursor++;  // the last in-argument
 364         final int CSITE_ARG    = skipCallSite ? -1 : APPENDIX_ARG;
 365         final int CALL_MH      = skipCallSite ? APPENDIX_ARG : nameCursor++;  // result of getTarget
 366         final int LINKER_CALL  = nameCursor++;
 367         MethodType invokerFormType = mtype.appendParameterTypes(skipCallSite ? MethodHandle.class : CallSite.class);
 368         Name[] names = arguments(nameCursor - INARG_LIMIT, invokerFormType);
 369         assert(names.length == nameCursor);
 370         assert(names[APPENDIX_ARG] != null);
 371         if (!skipCallSite)
 372             names[CALL_MH] = new Name(getConstantFunction(NF_getCallSiteTarget), names[CSITE_ARG]);
 373         // (site.)invokedynamic(a*):R => mh = site.getTarget(); mh.invokeBasic(a*)
 374         final int PREPEND_MH = 0, PREPEND_COUNT = 1;
 375         Object[] outArgs = Arrays.copyOfRange(names, ARG_BASE, OUTARG_LIMIT + PREPEND_COUNT, Object[].class);
 376         // prepend MH argument:
 377         System.arraycopy(outArgs, 0, outArgs, PREPEND_COUNT, outArgs.length - PREPEND_COUNT);
 378         outArgs[PREPEND_MH] = names[CALL_MH];
 379         names[LINKER_CALL] = new Name(mtype, outArgs);
 380         lform = new LambdaForm((skipCallSite ? "linkToTargetMethod" : "linkToCallSite"), INARG_LIMIT, names);
 381         lform.compileToBytecode();  // JVM needs a real methodOop
 382         lform = mtype.form().setCachedLambdaForm(which, lform);
 383         return lform;
 384     }
 385 
 386     /** Static definition of MethodHandle.invokeGeneric checking code. */
 387     /*non-public*/ static
 388     @ForceInline
 389     Object getCallSiteTarget(Object site) {
 390         return ((CallSite)site).getTarget();
 391     }
 392 


 394     @ForceInline
 395     void checkCustomized(Object o) {
 396         MethodHandle mh = (MethodHandle)o;
 397         if (MethodHandleImpl.isCompileConstant(mh)) return;
 398         if (mh.form.customized == null) {
 399             maybeCustomize(mh);
 400         }
 401     }
 402 
 403     /*non-public*/ static
 404     @DontInline
 405     void maybeCustomize(MethodHandle mh) {
 406         byte count = mh.customizationCount;
 407         if (count >= CUSTOMIZE_THRESHOLD) {
 408             mh.customize();
 409         } else {
 410             mh.customizationCount = (byte)(count+1);
 411         }
 412     }
 413 
 414     private static NamedFunction getConstantFunction(int idx) {
 415         NamedFunction function = FUNCTIONS[idx];
 416         if (function != null) {
 417             return function;
 418         }
 419         return setCachedFunction(idx, makeConstantFunction(idx));
 420     }
 421 
 422     private static synchronized NamedFunction setCachedFunction(int idx, final NamedFunction function) {
 423         // Simulate a CAS, to avoid racy duplication of results.
 424         NamedFunction prev = FUNCTIONS[idx];
 425         if (prev != null) {
 426             return prev;
 427         }
 428         FUNCTIONS[idx] = function;
 429         function.resolve();
 430         return function;
 431     }
 432 
 433     // Indexes into constant functions:
 434     private static final int
 435             NF_checkExactType    =  0,
 436             NF_checkGenericType  =  1,
 437             NF_getCallSiteTarget =  2,
 438             NF_checkCustomized   =  3,
 439             NF_LIMIT             =  4;
 440 
 441     // Local constant functions:
 442     private static final @Stable NamedFunction[] FUNCTIONS = new NamedFunction[NF_LIMIT];
 443 
 444     private static NamedFunction makeConstantFunction(int idx) {



 445         try {
 446             switch (idx) {
 447                 case NF_checkExactType:
 448                     return new NamedFunction(Invokers.class
 449                             .getDeclaredMethod("checkExactType", Object.class, Object.class));
 450                 case NF_checkGenericType:
 451                     return new NamedFunction(Invokers.class
 452                             .getDeclaredMethod("checkGenericType", Object.class, Object.class));
 453                 case NF_getCallSiteTarget:
 454                     return new NamedFunction(Invokers.class
 455                             .getDeclaredMethod("getCallSiteTarget", Object.class));
 456                 case NF_checkCustomized:
 457                     return new NamedFunction(Invokers.class
 458                             .getDeclaredMethod("checkCustomized", Object.class));

 459             }
 460         } catch (ReflectiveOperationException ex) {
 461             throw newInternalError(ex);
 462         }
 463         throw newInternalError("Unknown function index: " + idx);
 464     }
 465 
 466     private static class Lazy {
 467         private static final MethodHandle MH_asSpreader;
 468 
 469         static {
 470             try {
 471                 MH_asSpreader = IMPL_LOOKUP.findVirtual(MethodHandle.class, "asSpreader",
 472                         MethodType.methodType(MethodHandle.class, Class.class, int.class));
 473             } catch (ReflectiveOperationException ex) {
 474                 throw newInternalError(ex);
 475             }
 476         }
 477     }
 478 }
< prev index next >