MethodHandleImpl.java revision 14176:8606d027b2c2
1184610Salfred/* 2184610Salfred * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. 3184610Salfred * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4184610Salfred * 5184610Salfred * This code is free software; you can redistribute it and/or modify it 6184610Salfred * under the terms of the GNU General Public License version 2 only, as 7184610Salfred * published by the Free Software Foundation. Oracle designates this 8184610Salfred * particular file as subject to the "Classpath" exception as provided 9184610Salfred * by Oracle in the LICENSE file that accompanied this code. 10184610Salfred * 11184610Salfred * This code is distributed in the hope that it will be useful, but WITHOUT 12184610Salfred * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13184610Salfred * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14184610Salfred * version 2 for more details (a copy is included in the LICENSE file that 15184610Salfred * accompanied this code). 16184610Salfred * 17184610Salfred * You should have received a copy of the GNU General Public License version 18184610Salfred * 2 along with this work; if not, write to the Free Software Foundation, 19184610Salfred * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20184610Salfred * 21184610Salfred * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22184610Salfred * or visit www.oracle.com if you need additional information or have any 23184610Salfred * questions. 24184610Salfred */ 25190754Sthompsa 26184610Salfredpackage java.lang.invoke; 27194677Sthompsa 28194677Sthompsaimport java.security.AccessController; 29194677Sthompsaimport java.security.PrivilegedAction; 30194677Sthompsaimport java.util.Arrays; 31194677Sthompsaimport java.util.Collections; 32194677Sthompsaimport java.util.Iterator; 33194677Sthompsaimport java.util.List; 34194677Sthompsaimport java.util.function.Function; 35194677Sthompsa 36194677Sthompsaimport jdk.internal.reflect.CallerSensitive; 37194677Sthompsaimport jdk.internal.reflect.Reflection; 38194677Sthompsaimport jdk.internal.vm.annotation.Stable; 39194677Sthompsaimport sun.invoke.empty.Empty; 40194677Sthompsaimport sun.invoke.util.ValueConversions; 41194677Sthompsaimport sun.invoke.util.VerifyType; 42194677Sthompsaimport sun.invoke.util.Wrapper; 43194677Sthompsaimport static java.lang.invoke.LambdaForm.*; 44194677Sthompsaimport static java.lang.invoke.MethodHandleStatics.*; 45194677Sthompsaimport static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; 46194677Sthompsa 47188942Sthompsa/** 48194677Sthompsa * Trusted implementation code for MethodHandle. 49194677Sthompsa * @author jrose 50184610Salfred */ 51194228Sthompsa/*non-public*/ abstract class MethodHandleImpl { 52184610Salfred // Do not adjust this except for special platforms: 53188942Sthompsa private static final int MAX_ARITY; 54188942Sthompsa static { 55188942Sthompsa final Object[] values = { 255 }; 56188942Sthompsa AccessController.doPrivileged(new PrivilegedAction<>() { 57188942Sthompsa @Override 58188942Sthompsa public Void run() { 59188942Sthompsa values[0] = Integer.getInteger(MethodHandleImpl.class.getName()+".MAX_ARITY", 255); 60184610Salfred return null; 61188942Sthompsa } 62188942Sthompsa }); 63184610Salfred MAX_ARITY = (Integer) values[0]; 64194228Sthompsa } 65184610Salfred 66184610Salfred /// Factory methods to create method handles: 67184610Salfred 68184610Salfred static MethodHandle makeArrayElementAccessor(Class<?> arrayClass, boolean isSetter) { 69184610Salfred if (arrayClass == Object[].class) 70184610Salfred return (isSetter ? ArrayAccessor.OBJECT_ARRAY_SETTER : ArrayAccessor.OBJECT_ARRAY_GETTER); 71184610Salfred if (!arrayClass.isArray()) 72184610Salfred throw newIllegalArgumentException("not an array: "+arrayClass); 73194228Sthompsa MethodHandle[] cache = ArrayAccessor.TYPED_ACCESSORS.get(arrayClass); 74184610Salfred int cacheIndex = (isSetter ? ArrayAccessor.SETTER_INDEX : ArrayAccessor.GETTER_INDEX); 75207080Sthompsa MethodHandle mh = cache[cacheIndex]; 76184610Salfred if (mh != null) return mh; 77184610Salfred mh = ArrayAccessor.getAccessor(arrayClass, isSetter); 78184610Salfred MethodType correctType = ArrayAccessor.correctType(arrayClass, isSetter); 79184610Salfred if (mh.type() != correctType) { 80184610Salfred assert(mh.type().parameterType(0) == Object[].class); 81184610Salfred assert((isSetter ? mh.type().parameterType(2) : mh.type().returnType()) == Object.class); 82184610Salfred assert(isSetter || correctType.parameterType(0).getComponentType() == correctType.returnType()); 83190734Sthompsa // safe to view non-strictly, because element type follows from array type 84190734Sthompsa mh = mh.viewAsType(correctType, false); 85194228Sthompsa } 86192499Sthompsa mh = makeIntrinsic(mh, (isSetter ? Intrinsic.ARRAY_STORE : Intrinsic.ARRAY_LOAD)); 87184610Salfred // Atomically update accessor cache. 88184610Salfred synchronized(cache) { 89184610Salfred if (cache[cacheIndex] == null) { 90184610Salfred cache[cacheIndex] = mh; 91184610Salfred } else { 92184610Salfred // Throw away newly constructed accessor and use cached version. 93184610Salfred mh = cache[cacheIndex]; 94184610Salfred } 95192984Sthompsa } 96194228Sthompsa return mh; 97190734Sthompsa } 98190734Sthompsa 99190734Sthompsa static final class ArrayAccessor { 100184610Salfred /// Support for array element access 101184610Salfred static final int GETTER_INDEX = 0, SETTER_INDEX = 1, INDEX_LIMIT = 2; 102184610Salfred static final ClassValue<MethodHandle[]> TYPED_ACCESSORS 103184610Salfred = new ClassValue<MethodHandle[]>() { 104184610Salfred @Override 105194228Sthompsa protected MethodHandle[] computeValue(Class<?> type) { 106194228Sthompsa return new MethodHandle[INDEX_LIMIT]; 107194228Sthompsa } 108194677Sthompsa }; 109194228Sthompsa static final MethodHandle OBJECT_ARRAY_GETTER, OBJECT_ARRAY_SETTER; 110194228Sthompsa static { 111194228Sthompsa MethodHandle[] cache = TYPED_ACCESSORS.get(Object[].class); 112194228Sthompsa cache[GETTER_INDEX] = OBJECT_ARRAY_GETTER = makeIntrinsic(getAccessor(Object[].class, false), Intrinsic.ARRAY_LOAD); 113194228Sthompsa cache[SETTER_INDEX] = OBJECT_ARRAY_SETTER = makeIntrinsic(getAccessor(Object[].class, true), Intrinsic.ARRAY_STORE); 114194228Sthompsa 115194228Sthompsa assert(InvokerBytecodeGenerator.isStaticallyInvocable(ArrayAccessor.OBJECT_ARRAY_GETTER.internalMemberName())); 116192500Sthompsa assert(InvokerBytecodeGenerator.isStaticallyInvocable(ArrayAccessor.OBJECT_ARRAY_SETTER.internalMemberName())); 117184610Salfred } 118184610Salfred 119194228Sthompsa static int getElementI(int[] a, int i) { return a[i]; } 120190734Sthompsa static long getElementJ(long[] a, int i) { return a[i]; } 121190734Sthompsa static float getElementF(float[] a, int i) { return a[i]; } 122194677Sthompsa static double getElementD(double[] a, int i) { return a[i]; } 123190734Sthompsa static boolean getElementZ(boolean[] a, int i) { return a[i]; } 124192499Sthompsa static byte getElementB(byte[] a, int i) { return a[i]; } 125194677Sthompsa static short getElementS(short[] a, int i) { return a[i]; } 126190734Sthompsa static char getElementC(char[] a, int i) { return a[i]; } 127194677Sthompsa static Object getElementL(Object[] a, int i) { return a[i]; } 128190734Sthompsa 129190734Sthompsa static void setElementI(int[] a, int i, int x) { a[i] = x; } 130190734Sthompsa static void setElementJ(long[] a, int i, long x) { a[i] = x; } 131194228Sthompsa static void setElementF(float[] a, int i, float x) { a[i] = x; } 132184610Salfred static void setElementD(double[] a, int i, double x) { a[i] = x; } 133184610Salfred static void setElementZ(boolean[] a, int i, boolean x) { a[i] = x; } 134184610Salfred static void setElementB(byte[] a, int i, byte x) { a[i] = x; } 135184610Salfred static void setElementS(short[] a, int i, short x) { a[i] = x; } 136184610Salfred static void setElementC(char[] a, int i, char x) { a[i] = x; } 137194228Sthompsa static void setElementL(Object[] a, int i, Object x) { a[i] = x; } 138184610Salfred 139184610Salfred static String name(Class<?> arrayClass, boolean isSetter) { 140184610Salfred Class<?> elemClass = arrayClass.getComponentType(); 141184610Salfred if (elemClass == null) throw newIllegalArgumentException("not an array", arrayClass); 142184610Salfred return (!isSetter ? "getElement" : "setElement") + Wrapper.basicTypeChar(elemClass); 143184610Salfred } 144184610Salfred static MethodType type(Class<?> arrayClass, boolean isSetter) { 145184610Salfred Class<?> elemClass = arrayClass.getComponentType(); 146184610Salfred Class<?> arrayArgClass = arrayClass; 147184610Salfred if (!elemClass.isPrimitive()) { 148184610Salfred arrayArgClass = Object[].class; 149184610Salfred elemClass = Object.class; 150184610Salfred } 151194228Sthompsa return !isSetter ? 152184610Salfred MethodType.methodType(elemClass, arrayArgClass, int.class) : 153184610Salfred MethodType.methodType(void.class, arrayArgClass, int.class, elemClass); 154184610Salfred } 155184610Salfred static MethodType correctType(Class<?> arrayClass, boolean isSetter) { 156184610Salfred Class<?> elemClass = arrayClass.getComponentType(); 157184610Salfred return !isSetter ? 158184610Salfred MethodType.methodType(elemClass, arrayClass, int.class) : 159184610Salfred MethodType.methodType(void.class, arrayClass, int.class, elemClass); 160193045Sthompsa } 161194228Sthompsa static MethodHandle getAccessor(Class<?> arrayClass, boolean isSetter) { 162184610Salfred String name = name(arrayClass, isSetter); 163184610Salfred MethodType type = type(arrayClass, isSetter); 164184610Salfred try { 165184610Salfred return IMPL_LOOKUP.findStatic(ArrayAccessor.class, name, type); 166184610Salfred } catch (ReflectiveOperationException ex) { 167184610Salfred throw uncaughtException(ex); 168184610Salfred } 169184610Salfred } 170184610Salfred } 171184610Salfred 172184610Salfred /** 173184610Salfred * Create a JVM-level adapter method handle to conform the given method 174184610Salfred * handle to the similar newType, using only pairwise argument conversions. 175184610Salfred * For each argument, convert incoming argument to the exact type needed. 176184610Salfred * The argument conversions allowed are casting, boxing and unboxing, 177184610Salfred * integral widening or narrowing, and floating point widening or narrowing. 178194228Sthompsa * @param srcType required call type 179184610Salfred * @param target original method handle 180184610Salfred * @param strict if true, only asType conversions are allowed; if false, explicitCastArguments conversions allowed 181184610Salfred * @param monobox if true, unboxing conversions are assumed to be exactly typed (Integer to int only, not long or double) 182184610Salfred * @return an adapter to the original handle with the desired new type, 183184610Salfred * or the original target if the types are already identical 184184610Salfred * or null if the adaptation cannot be made 185184610Salfred */ 186184610Salfred static MethodHandle makePairwiseConvert(MethodHandle target, MethodType srcType, 187184610Salfred boolean strict, boolean monobox) { 188190180Sthompsa MethodType dstType = target.type(); 189184610Salfred if (srcType == dstType) 190194228Sthompsa return target; 191193074Sthompsa return makePairwiseConvertByEditor(target, srcType, strict, monobox); 192193074Sthompsa } 193184610Salfred 194192984Sthompsa private static int countNonNull(Object[] array) { 195192984Sthompsa int count = 0; 196184610Salfred for (Object x : array) { 197193074Sthompsa if (x != null) ++count; 198193074Sthompsa } 199193074Sthompsa return count; 200193074Sthompsa } 201193074Sthompsa 202193074Sthompsa static MethodHandle makePairwiseConvertByEditor(MethodHandle target, MethodType srcType, 203184610Salfred boolean strict, boolean monobox) { 204199816Sthompsa Object[] convSpecs = computeValueConversions(srcType, target.type(), strict, monobox); 205184610Salfred int convCount = countNonNull(convSpecs); 206199816Sthompsa if (convCount == 0) 207184610Salfred return target.viewAsType(srcType, strict); 208184610Salfred MethodType basicSrcType = srcType.basicType(); 209184610Salfred MethodType midType = target.type().basicType(); 210184610Salfred BoundMethodHandle mh = target.rebind(); 211184610Salfred // FIXME: Reduce number of bindings when there is more than one Class conversion. 212184610Salfred // FIXME: Reduce number of bindings when there are repeated conversions. 213184610Salfred for (int i = 0; i < convSpecs.length-1; i++) { 214184610Salfred Object convSpec = convSpecs[i]; 215184610Salfred if (convSpec == null) continue; 216184610Salfred MethodHandle fn; 217184610Salfred if (convSpec instanceof Class) { 218184610Salfred fn = getConstantHandle(MH_cast).bindTo(convSpec); 219184610Salfred } else { 220184610Salfred fn = (MethodHandle) convSpec; 221184610Salfred } 222184610Salfred Class<?> newType = basicSrcType.parameterType(i); 223184610Salfred if (--convCount == 0) 224184610Salfred midType = srcType; 225184610Salfred else 226184610Salfred midType = midType.changeParameterType(i, newType); 227184610Salfred LambdaForm form2 = mh.editor().filterArgumentForm(1+i, BasicType.basicType(newType)); 228184610Salfred mh = mh.copyWithExtendL(midType, form2, fn); 229184610Salfred mh = mh.rebind(); 230184610Salfred } 231184610Salfred Object convSpec = convSpecs[convSpecs.length-1]; 232184610Salfred if (convSpec != null) { 233184610Salfred MethodHandle fn; 234184610Salfred if (convSpec instanceof Class) { 235184610Salfred if (convSpec == void.class) 236184610Salfred fn = null; 237184610Salfred else 238184610Salfred fn = getConstantHandle(MH_cast).bindTo(convSpec); 239184610Salfred } else { 240184610Salfred fn = (MethodHandle) convSpec; 241184610Salfred } 242184610Salfred Class<?> newType = basicSrcType.returnType(); 243184610Salfred assert(--convCount == 0); 244187173Sthompsa midType = srcType; 245184610Salfred if (fn != null) { 246184610Salfred mh = mh.rebind(); // rebind if too complex 247184610Salfred LambdaForm form2 = mh.editor().filterReturnForm(BasicType.basicType(newType), false); 248184610Salfred mh = mh.copyWithExtendL(midType, form2, fn); 249187173Sthompsa } else { 250184610Salfred LambdaForm form2 = mh.editor().filterReturnForm(BasicType.basicType(newType), true); 251184610Salfred mh = mh.copyWith(midType, form2); 252184610Salfred } 253184610Salfred } 254184610Salfred assert(convCount == 0); 255184610Salfred assert(mh.type().equals(srcType)); 256184610Salfred return mh; 257184610Salfred } 258184610Salfred 259184610Salfred static MethodHandle makePairwiseConvertIndirect(MethodHandle target, MethodType srcType, 260184610Salfred boolean strict, boolean monobox) { 261184610Salfred assert(target.type().parameterCount() == srcType.parameterCount()); 262184610Salfred // Calculate extra arguments (temporaries) required in the names array. 263184610Salfred Object[] convSpecs = computeValueConversions(srcType, target.type(), strict, monobox); 264184610Salfred final int INARG_COUNT = srcType.parameterCount(); 265184610Salfred int convCount = countNonNull(convSpecs); 266184610Salfred boolean retConv = (convSpecs[INARG_COUNT] != null); 267194228Sthompsa boolean retVoid = srcType.returnType() == void.class; 268184610Salfred if (retConv && retVoid) { 269184610Salfred convCount -= 1; 270184610Salfred retConv = false; 271184610Salfred } 272184610Salfred 273184610Salfred final int IN_MH = 0; 274184610Salfred final int INARG_BASE = 1; 275184610Salfred final int INARG_LIMIT = INARG_BASE + INARG_COUNT; 276184610Salfred final int NAME_LIMIT = INARG_LIMIT + convCount + 1; 277184610Salfred final int RETURN_CONV = (!retConv ? -1 : NAME_LIMIT - 1); 278184610Salfred final int OUT_CALL = (!retConv ? NAME_LIMIT : RETURN_CONV) - 1; 279184610Salfred final int RESULT = (retVoid ? -1 : NAME_LIMIT - 1); 280194228Sthompsa 281184610Salfred // Now build a LambdaForm. 282184610Salfred MethodType lambdaType = srcType.basicType().invokerType(); 283184610Salfred Name[] names = arguments(NAME_LIMIT - INARG_LIMIT, lambdaType); 284184610Salfred 285184610Salfred // Collect the arguments to the outgoing call, maybe with conversions: 286184610Salfred final int OUTARG_BASE = 0; // target MH is Name.function, name Name.arguments[0] 287194228Sthompsa Object[] outArgs = new Object[OUTARG_BASE + INARG_COUNT]; 288184610Salfred 289184610Salfred int nameCursor = INARG_LIMIT; 290184610Salfred for (int i = 0; i < INARG_COUNT; i++) { 291184610Salfred Object convSpec = convSpecs[i]; 292184610Salfred if (convSpec == null) { 293184610Salfred // do nothing: difference is trivial 294184610Salfred outArgs[OUTARG_BASE + i] = names[INARG_BASE + i]; 295184610Salfred continue; 296184610Salfred } 297184610Salfred 298184610Salfred Name conv; 299190180Sthompsa if (convSpec instanceof Class) { 300184610Salfred Class<?> convClass = (Class<?>) convSpec; 301184610Salfred conv = new Name(getConstantHandle(MH_cast), convClass, names[INARG_BASE + i]); 302194228Sthompsa } else { 303184610Salfred MethodHandle fn = (MethodHandle) convSpec; 304184610Salfred conv = new Name(fn, names[INARG_BASE + i]); 305184610Salfred } 306184610Salfred assert(names[nameCursor] == null); 307192984Sthompsa names[nameCursor++] = conv; 308184610Salfred assert(outArgs[OUTARG_BASE + i] == null); 309184610Salfred outArgs[OUTARG_BASE + i] = conv; 310184610Salfred } 311194228Sthompsa 312184610Salfred // Build argument array for the call. 313184610Salfred assert(nameCursor == OUT_CALL); 314184610Salfred names[OUT_CALL] = new Name(target, outArgs); 315184610Salfred 316184610Salfred Object convSpec = convSpecs[INARG_COUNT]; 317192984Sthompsa if (!retConv) { 318192984Sthompsa assert(OUT_CALL == names.length-1); 319192984Sthompsa } else { 320194228Sthompsa Name conv; 321193045Sthompsa if (convSpec == void.class) { 322193045Sthompsa conv = new Name(LambdaForm.constantZero(BasicType.basicType(srcType.returnType()))); 323193045Sthompsa } else if (convSpec instanceof Class) { 324184610Salfred Class<?> convClass = (Class<?>) convSpec; 325184610Salfred conv = new Name(getConstantHandle(MH_cast), convClass, names[OUT_CALL]); 326184610Salfred } else { 327184610Salfred MethodHandle fn = (MethodHandle) convSpec; 328184610Salfred if (fn.type().parameterCount() == 0) 329184610Salfred conv = new Name(fn); // don't pass retval to void conversion 330184610Salfred else 331184610Salfred conv = new Name(fn, names[OUT_CALL]); 332184610Salfred } 333184610Salfred assert(names[RETURN_CONV] == null); 334184610Salfred names[RETURN_CONV] = conv; 335184610Salfred assert(RETURN_CONV == names.length-1); 336184610Salfred } 337193644Sthompsa 338184610Salfred LambdaForm form = new LambdaForm("convert", lambdaType.parameterCount(), names, RESULT); 339184610Salfred return SimpleMethodHandle.make(srcType, form); 340184610Salfred } 341190734Sthompsa 342190734Sthompsa static Object[] computeValueConversions(MethodType srcType, MethodType dstType, 343190734Sthompsa boolean strict, boolean monobox) { 344190734Sthompsa final int INARG_COUNT = srcType.parameterCount(); 345190734Sthompsa Object[] convSpecs = new Object[INARG_COUNT+1]; 346193644Sthompsa for (int i = 0; i <= INARG_COUNT; i++) { 347184610Salfred boolean isRet = (i == INARG_COUNT); 348184610Salfred Class<?> src = isRet ? dstType.returnType() : srcType.parameterType(i); 349184610Salfred Class<?> dst = isRet ? srcType.returnType() : dstType.parameterType(i); 350192499Sthompsa if (!VerifyType.isNullConversion(src, dst, /*keepInterfaces=*/ strict)) { 351184610Salfred convSpecs[i] = valueConversion(src, dst, strict, monobox); 352190734Sthompsa } 353184610Salfred } 354184610Salfred return convSpecs; 355184610Salfred } 356184610Salfred static MethodHandle makePairwiseConvert(MethodHandle target, MethodType srcType, 357184610Salfred boolean strict) { 358184610Salfred return makePairwiseConvert(target, srcType, strict, /*monobox=*/ false); 359184610Salfred } 360184610Salfred 361184610Salfred /** 362184610Salfred * Find a conversion function from the given source to the given destination. 363184610Salfred * This conversion function will be used as a LF NamedFunction. 364184610Salfred * Return a Class object if a simple cast is needed. 365184610Salfred * Return void.class if void is involved. 366184610Salfred */ 367184610Salfred static Object valueConversion(Class<?> src, Class<?> dst, boolean strict, boolean monobox) { 368184610Salfred assert(!VerifyType.isNullConversion(src, dst, /*keepInterfaces=*/ strict)); // caller responsibility 369184610Salfred if (dst == void.class) 370184610Salfred return dst; 371194228Sthompsa MethodHandle fn; 372184610Salfred if (src.isPrimitive()) { 373184610Salfred if (src == void.class) { 374184610Salfred return void.class; // caller must recognize this specially 375184610Salfred } else if (dst.isPrimitive()) { 376184610Salfred // Examples: int->byte, byte->int, boolean->int (!strict) 377184610Salfred fn = ValueConversions.convertPrimitive(src, dst); 378184610Salfred } else { 379184610Salfred // Examples: int->Integer, boolean->Object, float->Number 380184610Salfred Wrapper wsrc = Wrapper.forPrimitiveType(src); 381184610Salfred fn = ValueConversions.boxExact(wsrc); 382184610Salfred assert(fn.type().parameterType(0) == wsrc.primitiveType()); 383184610Salfred assert(fn.type().returnType() == wsrc.wrapperType()); 384184610Salfred if (!VerifyType.isNullConversion(wsrc.wrapperType(), dst, strict)) { 385184610Salfred // Corner case, such as int->Long, which will probably fail. 386184610Salfred MethodType mt = MethodType.methodType(dst, src); 387184610Salfred if (strict) 388184610Salfred fn = fn.asType(mt); 389184610Salfred else 390184610Salfred fn = MethodHandleImpl.makePairwiseConvert(fn, mt, /*strict=*/ false); 391184610Salfred } 392184610Salfred } 393184610Salfred } else if (dst.isPrimitive()) { 394184610Salfred Wrapper wdst = Wrapper.forPrimitiveType(dst); 395184610Salfred if (monobox || src == wdst.wrapperType()) { 396184610Salfred // Use a strongly-typed unboxer, if possible. 397194228Sthompsa fn = ValueConversions.unboxExact(wdst, strict); 398184610Salfred } else { 399184610Salfred // Examples: Object->int, Number->int, Comparable->int, Byte->int 400184610Salfred // must include additional conversions 401184610Salfred // src must be examined at runtime, to detect Byte, Character, etc. 402184610Salfred fn = (strict 403190181Sthompsa ? ValueConversions.unboxWiden(wdst) 404184610Salfred : ValueConversions.unboxCast(wdst)); 405184610Salfred } 406184610Salfred } else { 407184610Salfred // Simple reference conversion. 408184610Salfred // Note: Do not check for a class hierarchy relation 409184610Salfred // between src and dst. In all cases a 'null' argument 410184610Salfred // will pass the cast conversion. 411184610Salfred return dst; 412184610Salfred } 413184610Salfred assert(fn.type().parameterCount() <= 1) : "pc"+Arrays.asList(src.getSimpleName(), dst.getSimpleName(), fn); 414184610Salfred return fn; 415187180Sthompsa } 416187180Sthompsa 417187180Sthompsa static MethodHandle makeVarargsCollector(MethodHandle target, Class<?> arrayType) { 418187180Sthompsa MethodType type = target.type(); 419199059Sthompsa int last = type.parameterCount() - 1; 420187180Sthompsa if (type.parameterType(last) != arrayType) 421187180Sthompsa target = target.asType(type.changeParameterType(last, arrayType)); 422184610Salfred target = target.asFixedArity(); // make sure this attribute is turned off 423199059Sthompsa return new AsVarargsCollector(target, arrayType); 424199059Sthompsa } 425199059Sthompsa 426199059Sthompsa private static final class AsVarargsCollector extends DelegatingMethodHandle { 427199059Sthompsa private final MethodHandle target; 428187180Sthompsa private final Class<?> arrayType; 429184610Salfred private @Stable MethodHandle asCollectorCache; 430184610Salfred 431184610Salfred AsVarargsCollector(MethodHandle target, Class<?> arrayType) { 432184610Salfred this(target.type(), target, arrayType); 433184610Salfred } 434184610Salfred AsVarargsCollector(MethodType type, MethodHandle target, Class<?> arrayType) { 435184610Salfred super(type, target); 436184610Salfred this.target = target; 437184610Salfred this.arrayType = arrayType; 438184610Salfred this.asCollectorCache = target.asCollector(arrayType, 0); 439184610Salfred } 440184610Salfred 441184610Salfred @Override 442184610Salfred public boolean isVarargsCollector() { 443184610Salfred return true; 444184610Salfred } 445184610Salfred 446184610Salfred @Override 447184610Salfred protected MethodHandle getTarget() { 448184610Salfred return target; 449184610Salfred } 450184610Salfred 451184610Salfred @Override 452184610Salfred public MethodHandle asFixedArity() { 453184610Salfred return target; 454184610Salfred } 455184610Salfred 456184610Salfred @Override 457184610Salfred MethodHandle setVarargs(MemberName member) { 458187180Sthompsa if (member.isVarargs()) return this; 459187180Sthompsa return asFixedArity(); 460187180Sthompsa } 461187180Sthompsa 462187180Sthompsa @Override 463187180Sthompsa public MethodHandle asTypeUncached(MethodType newType) { 464187180Sthompsa MethodType type = this.type(); 465187180Sthompsa int collectArg = type.parameterCount() - 1; 466187180Sthompsa int newArity = newType.parameterCount(); 467187180Sthompsa if (newArity == collectArg+1 && 468187180Sthompsa type.parameterType(collectArg).isAssignableFrom(newType.parameterType(collectArg))) { 469187180Sthompsa // if arity and trailing parameter are compatible, do normal thing 470187180Sthompsa return asTypeCache = asFixedArity().asType(newType); 471187180Sthompsa } 472187180Sthompsa // check cache 473187180Sthompsa MethodHandle acc = asCollectorCache; 474187180Sthompsa if (acc != null && acc.type().parameterCount() == newArity) 475187180Sthompsa return asTypeCache = acc.asType(newType); 476184610Salfred // build and cache a collector 477184610Salfred int arrayLength = newArity - collectArg; 478184610Salfred MethodHandle collector; 479187180Sthompsa try { 480187180Sthompsa collector = asFixedArity().asCollector(arrayType, arrayLength); 481184610Salfred assert(collector.type().parameterCount() == newArity) : "newArity="+newArity+" but collector="+collector; 482184610Salfred } catch (IllegalArgumentException ex) { 483184610Salfred throw new WrongMethodTypeException("cannot build collector", ex); 484184610Salfred } 485184610Salfred asCollectorCache = collector; 486184610Salfred return asTypeCache = collector.asType(newType); 487184610Salfred } 488184610Salfred 489184610Salfred @Override 490184610Salfred boolean viewAsTypeChecks(MethodType newType, boolean strict) { 491184610Salfred super.viewAsTypeChecks(newType, true); 492184610Salfred if (strict) return true; 493184610Salfred // extra assertion for non-strict checks: 494184610Salfred assert (type().lastParameterType().getComponentType() 495184610Salfred .isAssignableFrom( 496184610Salfred newType.lastParameterType().getComponentType())) 497184610Salfred : Arrays.asList(this, newType); 498184610Salfred return true; 499184610Salfred } 500184610Salfred } 501184610Salfred 502184610Salfred /** Factory method: Spread selected argument. */ 503184610Salfred static MethodHandle makeSpreadArguments(MethodHandle target, 504184610Salfred Class<?> spreadArgType, int spreadArgPos, int spreadArgCount) { 505184610Salfred MethodType targetType = target.type(); 506184610Salfred 507194228Sthompsa for (int i = 0; i < spreadArgCount; i++) { 508184610Salfred Class<?> arg = VerifyType.spreadArgElementType(spreadArgType, i); 509184610Salfred if (arg == null) arg = Object.class; 510184610Salfred targetType = targetType.changeParameterType(spreadArgPos + i, arg); 511184610Salfred } 512184610Salfred target = target.asType(targetType); 513184610Salfred 514184610Salfred MethodType srcType = targetType 515184610Salfred .replaceParameterTypes(spreadArgPos, spreadArgPos + spreadArgCount, spreadArgType); 516184610Salfred // Now build a LambdaForm. 517184610Salfred MethodType lambdaType = srcType.invokerType(); 518184610Salfred Name[] names = arguments(spreadArgCount + 2, lambdaType); 519184610Salfred int nameCursor = lambdaType.parameterCount(); 520184610Salfred int[] indexes = new int[targetType.parameterCount()]; 521184610Salfred 522184610Salfred for (int i = 0, argIndex = 1; i < targetType.parameterCount() + 1; i++, argIndex++) { 523184610Salfred Class<?> src = lambdaType.parameterType(i); 524184610Salfred if (i == spreadArgPos) { 525184610Salfred // Spread the array. 526184610Salfred MethodHandle aload = MethodHandles.arrayElementGetter(spreadArgType); 527184610Salfred Name array = names[argIndex]; 528184610Salfred names[nameCursor++] = new Name(NF_checkSpreadArgument, array, spreadArgCount); 529184610Salfred for (int j = 0; j < spreadArgCount; i++, j++) { 530184610Salfred indexes[i] = nameCursor; 531184610Salfred names[nameCursor++] = new Name(aload, array, j); 532184610Salfred } 533184610Salfred } else if (i < indexes.length) { 534184610Salfred indexes[i] = argIndex; 535184610Salfred } 536184610Salfred } 537184610Salfred assert(nameCursor == names.length-1); // leave room for the final call 538184610Salfred 539184610Salfred // Build argument array for the call. 540184610Salfred Name[] targetArgs = new Name[targetType.parameterCount()]; 541184610Salfred for (int i = 0; i < targetType.parameterCount(); i++) { 542184610Salfred int idx = indexes[i]; 543184610Salfred targetArgs[i] = names[idx]; 544184610Salfred } 545184610Salfred names[names.length - 1] = new Name(target, (Object[]) targetArgs); 546184610Salfred 547184610Salfred LambdaForm form = new LambdaForm("spread", lambdaType.parameterCount(), names); 548184610Salfred return SimpleMethodHandle.make(srcType, form); 549184610Salfred } 550184610Salfred 551184610Salfred static void checkSpreadArgument(Object av, int n) { 552184610Salfred if (av == null) { 553184610Salfred if (n == 0) return; 554184610Salfred } else if (av instanceof Object[]) { 555184610Salfred int len = ((Object[])av).length; 556184610Salfred if (len == n) return; 557184610Salfred } else { 558184610Salfred int len = java.lang.reflect.Array.getLength(av); 559184610Salfred if (len == n) return; 560184610Salfred } 561184610Salfred // fall through to error: 562184610Salfred throw newIllegalArgumentException("array is not of length "+n); 563184610Salfred } 564184610Salfred 565184610Salfred /** Factory method: Collect or filter selected argument(s). */ 566184610Salfred static MethodHandle makeCollectArguments(MethodHandle target, 567184610Salfred MethodHandle collector, int collectArgPos, boolean retainOriginalArgs) { 568184610Salfred MethodType targetType = target.type(); // (a..., c, [b...])=>r 569184610Salfred MethodType collectorType = collector.type(); // (b...)=>c 570184610Salfred int collectArgCount = collectorType.parameterCount(); 571184610Salfred Class<?> collectValType = collectorType.returnType(); 572184610Salfred int collectValCount = (collectValType == void.class ? 0 : 1); 573184610Salfred MethodType srcType = targetType // (a..., [b...])=>r 574184610Salfred .dropParameterTypes(collectArgPos, collectArgPos+collectValCount); 575184610Salfred if (!retainOriginalArgs) { // (a..., b...)=>r 576184610Salfred srcType = srcType.insertParameterTypes(collectArgPos, collectorType.parameterList()); 577184610Salfred } 578184610Salfred // in arglist: [0: ...keep1 | cpos: collect... | cpos+cacount: keep2... ] 579184610Salfred // out arglist: [0: ...keep1 | cpos: collectVal? | cpos+cvcount: keep2... ] 580184610Salfred // out(retain): [0: ...keep1 | cpos: cV? coll... | cpos+cvc+cac: keep2... ] 581184610Salfred 582184610Salfred // Now build a LambdaForm. 583184610Salfred MethodType lambdaType = srcType.invokerType(); 584184610Salfred Name[] names = arguments(2, lambdaType); 585184610Salfred final int collectNamePos = names.length - 2; 586184610Salfred final int targetNamePos = names.length - 1; 587184610Salfred 588184610Salfred Name[] collectorArgs = Arrays.copyOfRange(names, 1 + collectArgPos, 1 + collectArgPos + collectArgCount); 589184610Salfred names[collectNamePos] = new Name(collector, (Object[]) collectorArgs); 590184610Salfred 591184610Salfred // Build argument array for the target. 592184610Salfred // Incoming LF args to copy are: [ (mh) headArgs collectArgs tailArgs ]. 593184610Salfred // Output argument array is [ headArgs (collectVal)? (collectArgs)? tailArgs ]. 594184610Salfred Name[] targetArgs = new Name[targetType.parameterCount()]; 595184610Salfred int inputArgPos = 1; // incoming LF args to copy to target 596184610Salfred int targetArgPos = 0; // fill pointer for targetArgs 597184610Salfred int chunk = collectArgPos; // |headArgs| 598184610Salfred System.arraycopy(names, inputArgPos, targetArgs, targetArgPos, chunk); 599184610Salfred inputArgPos += chunk; 600184610Salfred targetArgPos += chunk; 601184610Salfred if (collectValType != void.class) { 602184610Salfred targetArgs[targetArgPos++] = names[collectNamePos]; 603184610Salfred } 604184610Salfred chunk = collectArgCount; 605184610Salfred if (retainOriginalArgs) { 606184610Salfred System.arraycopy(names, inputArgPos, targetArgs, targetArgPos, chunk); 607184610Salfred targetArgPos += chunk; // optionally pass on the collected chunk 608184610Salfred } 609184610Salfred inputArgPos += chunk; 610184610Salfred chunk = targetArgs.length - targetArgPos; // all the rest 611194677Sthompsa System.arraycopy(names, inputArgPos, targetArgs, targetArgPos, chunk); 612194677Sthompsa assert(inputArgPos + chunk == collectNamePos); // use of rest of input args also 613194677Sthompsa names[targetNamePos] = new Name(target, (Object[]) targetArgs); 614184610Salfred 615184610Salfred LambdaForm form = new LambdaForm("collect", lambdaType.parameterCount(), names); 616184610Salfred return SimpleMethodHandle.make(srcType, form); 617184610Salfred } 618184610Salfred 619184610Salfred @LambdaForm.Hidden 620184610Salfred static 621184610Salfred MethodHandle selectAlternative(boolean testResult, MethodHandle target, MethodHandle fallback) { 622184610Salfred if (testResult) { 623184610Salfred return target; 624184610Salfred } else { 625184610Salfred return fallback; 626184610Salfred } 627184610Salfred } 628184610Salfred 629194677Sthompsa // Intrinsified by C2. Counters are used during parsing to calculate branch frequencies. 630184610Salfred @LambdaForm.Hidden 631184610Salfred @jdk.internal.HotSpotIntrinsicCandidate 632194677Sthompsa static 633184610Salfred boolean profileBoolean(boolean result, int[] counters) { 634184610Salfred // Profile is int[2] where [0] and [1] correspond to false and true occurrences respectively. 635184610Salfred int idx = result ? 1 : 0; 636184610Salfred try { 637184610Salfred counters[idx] = Math.addExact(counters[idx], 1); 638184610Salfred } catch (ArithmeticException e) { 639184610Salfred // Avoid continuous overflow by halving the problematic count. 640184610Salfred counters[idx] = counters[idx] / 2; 641184610Salfred } 642184610Salfred return result; 643184610Salfred } 644184610Salfred 645184610Salfred // Intrinsified by C2. Returns true if obj is a compile-time constant. 646184610Salfred @LambdaForm.Hidden 647190180Sthompsa @jdk.internal.HotSpotIntrinsicCandidate 648184610Salfred static 649184610Salfred boolean isCompileConstant(Object obj) { 650184610Salfred return false; 651184610Salfred } 652184610Salfred 653184610Salfred static 654184610Salfred MethodHandle makeGuardWithTest(MethodHandle test, 655184610Salfred MethodHandle target, 656192984Sthompsa MethodHandle fallback) { 657184610Salfred MethodType type = target.type(); 658184610Salfred assert(test.type().equals(type.changeReturnType(boolean.class)) && fallback.type().equals(type)); 659184610Salfred MethodType basicType = type.basicType(); 660184610Salfred LambdaForm form = makeGuardWithTestForm(basicType); 661184610Salfred BoundMethodHandle mh; 662184610Salfred try { 663184610Salfred if (PROFILE_GWT) { 664184610Salfred int[] counts = new int[2]; 665184610Salfred mh = (BoundMethodHandle) 666184610Salfred BoundMethodHandle.speciesData_LLLL().constructor().invokeBasic(type, form, 667184610Salfred (Object) test, (Object) profile(target), (Object) profile(fallback), counts); 668184610Salfred } else { 669184610Salfred mh = (BoundMethodHandle) 670184610Salfred BoundMethodHandle.speciesData_LLL().constructor().invokeBasic(type, form, 671184610Salfred (Object) test, (Object) profile(target), (Object) profile(fallback)); 672184610Salfred } 673184610Salfred } catch (Throwable ex) { 674184610Salfred throw uncaughtException(ex); 675190180Sthompsa } 676184610Salfred assert(mh.type() == type); 677184610Salfred return mh; 678184610Salfred } 679184610Salfred 680184610Salfred 681184610Salfred static 682190181Sthompsa MethodHandle profile(MethodHandle target) { 683184610Salfred if (DONT_INLINE_THRESHOLD >= 0) { 684184610Salfred return makeBlockInliningWrapper(target); 685184610Salfred } else { 686190181Sthompsa return target; 687184610Salfred } 688184610Salfred } 689184610Salfred 690184610Salfred /** 691184610Salfred * Block inlining during JIT-compilation of a target method handle if it hasn't been invoked enough times. 692184610Salfred * Corresponding LambdaForm has @DontInline when compiled into bytecode. 693184610Salfred */ 694184610Salfred static 695184610Salfred MethodHandle makeBlockInliningWrapper(MethodHandle target) { 696187173Sthompsa LambdaForm lform; 697190180Sthompsa if (DONT_INLINE_THRESHOLD > 0) { 698184610Salfred lform = Makers.PRODUCE_BLOCK_INLINING_FORM.apply(target); 699184610Salfred } else { 700184610Salfred lform = Makers.PRODUCE_REINVOKER_FORM.apply(target); 701194228Sthompsa } 702184610Salfred return new CountingWrapper(target, lform, 703184610Salfred Makers.PRODUCE_BLOCK_INLINING_FORM, Makers.PRODUCE_REINVOKER_FORM, 704184610Salfred DONT_INLINE_THRESHOLD); 705184610Salfred } 706184610Salfred 707184610Salfred private final static class Makers { 708190180Sthompsa /** Constructs reinvoker lambda form which block inlining during JIT-compilation for a particular method handle */ 709184610Salfred static final Function<MethodHandle, LambdaForm> PRODUCE_BLOCK_INLINING_FORM = new Function<MethodHandle, LambdaForm>() { 710184610Salfred @Override 711184610Salfred public LambdaForm apply(MethodHandle target) { 712184610Salfred return DelegatingMethodHandle.makeReinvokerForm(target, 713184610Salfred MethodTypeForm.LF_DELEGATE_BLOCK_INLINING, CountingWrapper.class, "reinvoker.dontInline", false, 714184610Salfred DelegatingMethodHandle.NF_getTarget, CountingWrapper.NF_maybeStopCounting); 715184610Salfred } 716190181Sthompsa }; 717184610Salfred 718184610Salfred /** Constructs simple reinvoker lambda form for a particular method handle */ 719184610Salfred static final Function<MethodHandle, LambdaForm> PRODUCE_REINVOKER_FORM = new Function<MethodHandle, LambdaForm>() { 720184610Salfred @Override 721184610Salfred public LambdaForm apply(MethodHandle target) { 722184610Salfred return DelegatingMethodHandle.makeReinvokerForm(target, 723184610Salfred MethodTypeForm.LF_DELEGATE, DelegatingMethodHandle.class, DelegatingMethodHandle.NF_getTarget); 724184610Salfred } 725184610Salfred }; 726194228Sthompsa 727184610Salfred /** Maker of type-polymorphic varargs */ 728194228Sthompsa static final ClassValue<MethodHandle[]> TYPED_COLLECTORS = new ClassValue<MethodHandle[]>() { 729194228Sthompsa @Override 730184610Salfred protected MethodHandle[] computeValue(Class<?> type) { 731184610Salfred return new MethodHandle[MAX_JVM_ARITY + 1]; 732184610Salfred } 733184610Salfred }; 734184610Salfred } 735184610Salfred 736184610Salfred /** 737184610Salfred * Counting method handle. It has 2 states: counting and non-counting. 738193045Sthompsa * It is in counting state for the first n invocations and then transitions to non-counting state. 739194228Sthompsa * Behavior in counting and non-counting states is determined by lambda forms produced by 740192984Sthompsa * countingFormProducer & nonCountingFormProducer respectively. 741192984Sthompsa */ 742187173Sthompsa static class CountingWrapper extends DelegatingMethodHandle { 743184610Salfred private final MethodHandle target; 744192984Sthompsa private int count; 745192984Sthompsa private Function<MethodHandle, LambdaForm> countingFormProducer; 746192984Sthompsa private Function<MethodHandle, LambdaForm> nonCountingFormProducer; 747192984Sthompsa private volatile boolean isCounting; 748193644Sthompsa 749192984Sthompsa private CountingWrapper(MethodHandle target, LambdaForm lform, 750192984Sthompsa Function<MethodHandle, LambdaForm> countingFromProducer, 751184610Salfred Function<MethodHandle, LambdaForm> nonCountingFormProducer, 752184610Salfred int count) { 753184610Salfred super(target.type(), lform); 754184610Salfred this.target = target; 755184610Salfred this.count = count; 756184610Salfred this.countingFormProducer = countingFromProducer; 757184610Salfred this.nonCountingFormProducer = nonCountingFormProducer; 758184610Salfred this.isCounting = (count > 0); 759184610Salfred } 760194228Sthompsa 761184610Salfred @Hidden 762184610Salfred @Override 763184610Salfred protected MethodHandle getTarget() { 764184610Salfred return target; 765184610Salfred } 766184610Salfred 767184610Salfred @Override 768184610Salfred public MethodHandle asTypeUncached(MethodType newType) { 769184610Salfred MethodHandle newTarget = target.asType(newType); 770184610Salfred MethodHandle wrapper; 771184610Salfred if (isCounting) { 772187173Sthompsa LambdaForm lform; 773184610Salfred lform = countingFormProducer.apply(newTarget); 774187173Sthompsa wrapper = new CountingWrapper(newTarget, lform, countingFormProducer, nonCountingFormProducer, DONT_INLINE_THRESHOLD); 775184610Salfred } else { 776184610Salfred wrapper = newTarget; // no need for a counting wrapper anymore 777184610Salfred } 778184610Salfred return (asTypeCache = wrapper); 779193045Sthompsa } 780184610Salfred 781184610Salfred // Customize target if counting happens for too long. 782184610Salfred private int invocations = CUSTOMIZE_THRESHOLD; 783190734Sthompsa private void maybeCustomizeTarget() { 784184610Salfred int c = invocations; 785184610Salfred if (c >= 0) { 786184610Salfred if (c == 1) { 787184610Salfred target.customize(); 788184610Salfred } 789184610Salfred invocations = c - 1; 790184610Salfred } 791184610Salfred } 792184610Salfred 793184610Salfred boolean countDown() { 794184610Salfred int c = count; 795184610Salfred maybeCustomizeTarget(); 796194228Sthompsa if (c <= 1) { 797184610Salfred // Try to limit number of updates. MethodHandle.updateForm() doesn't guarantee LF update visibility. 798184610Salfred if (isCounting) { 799184610Salfred isCounting = false; 800184610Salfred return true; 801184610Salfred } else { 802184610Salfred return false; 803184610Salfred } 804184610Salfred } else { 805184610Salfred count = c - 1; 806184610Salfred return false; 807184610Salfred } 808184610Salfred } 809192984Sthompsa 810184610Salfred @Hidden 811184610Salfred static void maybeStopCounting(Object o1) { 812184610Salfred CountingWrapper wrapper = (CountingWrapper) o1; 813184610Salfred if (wrapper.countDown()) { 814184610Salfred // Reached invocation threshold. Replace counting behavior with a non-counting one. 815184610Salfred LambdaForm lform = wrapper.nonCountingFormProducer.apply(wrapper.target); 816184610Salfred lform.compileToBytecode(); // speed up warmup by avoiding LF interpretation again after transition 817190180Sthompsa wrapper.updateForm(lform); 818184610Salfred } 819184610Salfred } 820190180Sthompsa 821184610Salfred static final NamedFunction NF_maybeStopCounting; 822184610Salfred static { 823184610Salfred Class<?> THIS_CLASS = CountingWrapper.class; 824194227Sthompsa try { 825184610Salfred NF_maybeStopCounting = new NamedFunction(THIS_CLASS.getDeclaredMethod("maybeStopCounting", Object.class)); 826187173Sthompsa } catch (ReflectiveOperationException ex) { 827190180Sthompsa throw newInternalError(ex); 828194228Sthompsa } 829184610Salfred } 830194228Sthompsa } 831190180Sthompsa 832184610Salfred static 833184610Salfred LambdaForm makeGuardWithTestForm(MethodType basicType) { 834187173Sthompsa LambdaForm lform = basicType.form().cachedLambdaForm(MethodTypeForm.LF_GWT); 835184610Salfred if (lform != null) return lform; 836184610Salfred final int THIS_MH = 0; // the BMH_LLL 837194228Sthompsa final int ARG_BASE = 1; // start of incoming arguments 838190180Sthompsa final int ARG_LIMIT = ARG_BASE + basicType.parameterCount(); 839184610Salfred int nameCursor = ARG_LIMIT; 840194228Sthompsa final int GET_TEST = nameCursor++; 841190180Sthompsa final int GET_TARGET = nameCursor++; 842194228Sthompsa final int GET_FALLBACK = nameCursor++; 843187173Sthompsa final int GET_COUNTERS = PROFILE_GWT ? nameCursor++ : -1; 844194228Sthompsa final int CALL_TEST = nameCursor++; 845187173Sthompsa final int PROFILE = (GET_COUNTERS != -1) ? nameCursor++ : -1; 846184610Salfred final int TEST = nameCursor-1; // previous statement: either PROFILE or CALL_TEST 847191400Sthompsa final int SELECT_ALT = nameCursor++; 848191400Sthompsa final int CALL_TARGET = nameCursor++; 849191400Sthompsa assert(CALL_TARGET == SELECT_ALT+1); // must be true to trigger IBG.emitSelectAlternative 850191400Sthompsa 851191400Sthompsa MethodType lambdaType = basicType.invokerType(); 852191400Sthompsa Name[] names = arguments(nameCursor - ARG_LIMIT, lambdaType); 853194228Sthompsa 854187174Sthompsa BoundMethodHandle.SpeciesData data = 855191400Sthompsa (GET_COUNTERS != -1) ? BoundMethodHandle.speciesData_LLLL() 856191400Sthompsa : BoundMethodHandle.speciesData_LLL(); 857191400Sthompsa names[THIS_MH] = names[THIS_MH].withConstraint(data); 858187174Sthompsa names[GET_TEST] = new Name(data.getterFunction(0), names[THIS_MH]); 859187174Sthompsa names[GET_TARGET] = new Name(data.getterFunction(1), names[THIS_MH]); 860187174Sthompsa names[GET_FALLBACK] = new Name(data.getterFunction(2), names[THIS_MH]); 861187174Sthompsa if (GET_COUNTERS != -1) { 862184610Salfred names[GET_COUNTERS] = new Name(data.getterFunction(3), names[THIS_MH]); 863184610Salfred } 864184610Salfred Object[] invokeArgs = Arrays.copyOfRange(names, 0, ARG_LIMIT, Object[].class); 865184610Salfred 866184610Salfred // call test 867184610Salfred MethodType testType = basicType.changeReturnType(boolean.class).basicType(); 868184610Salfred invokeArgs[0] = names[GET_TEST]; 869184610Salfred names[CALL_TEST] = new Name(testType, invokeArgs); 870184610Salfred 871184610Salfred // profile branch 872184610Salfred if (PROFILE != -1) { 873190734Sthompsa names[PROFILE] = new Name(NF_profileBoolean, names[CALL_TEST], names[GET_COUNTERS]); 874184610Salfred } 875184610Salfred // call selectAlternative 876184610Salfred names[SELECT_ALT] = new Name(getConstantHandle(MH_selectAlternative), names[TEST], names[GET_TARGET], names[GET_FALLBACK]); 877194228Sthompsa 878184610Salfred // call target or fallback 879184610Salfred invokeArgs[0] = names[SELECT_ALT]; 880193644Sthompsa names[CALL_TARGET] = new Name(basicType, invokeArgs); 881190734Sthompsa 882184610Salfred lform = new LambdaForm("guard", lambdaType.parameterCount(), names, /*forceInline=*/true); 883192499Sthompsa 884192499Sthompsa return basicType.form().setCachedLambdaForm(MethodTypeForm.LF_GWT, lform); 885190734Sthompsa } 886184610Salfred 887184610Salfred /** 888184610Salfred * The LambdaForm shape for catchException combinator is the following: 889184610Salfred * <blockquote><pre>{@code 890184610Salfred * guardWithCatch=Lambda(a0:L,a1:L,a2:L)=>{ 891184610Salfred * t3:L=BoundMethodHandle$Species_LLLLL.argL0(a0:L); 892184610Salfred * t4:L=BoundMethodHandle$Species_LLLLL.argL1(a0:L); 893190734Sthompsa * t5:L=BoundMethodHandle$Species_LLLLL.argL2(a0:L); 894190734Sthompsa * t6:L=BoundMethodHandle$Species_LLLLL.argL3(a0:L); 895190734Sthompsa * t7:L=BoundMethodHandle$Species_LLLLL.argL4(a0:L); 896184610Salfred * t8:L=MethodHandle.invokeBasic(t6:L,a1:L,a2:L); 897184610Salfred * t9:L=MethodHandleImpl.guardWithCatch(t3:L,t4:L,t5:L,t8:L); 898184610Salfred * t10:I=MethodHandle.invokeBasic(t7:L,t9:L);t10:I} 899192984Sthompsa * }</pre></blockquote> 900184610Salfred * 901184610Salfred * argL0 and argL2 are target and catcher method handles. argL1 is exception class. 902184610Salfred * argL3 and argL4 are auxiliary method handles: argL3 boxes arguments and wraps them into Object[] 903184610Salfred * (ValueConversions.array()) and argL4 unboxes result if necessary (ValueConversions.unbox()). 904187173Sthompsa * 905184610Salfred * Having t8 and t10 passed outside and not hardcoded into a lambda form allows to share lambda forms 906194228Sthompsa * among catchException combinators with the same basic type. 907186454Sthompsa */ 908184610Salfred private static LambdaForm makeGuardWithCatchForm(MethodType basicType) { 909184610Salfred MethodType lambdaType = basicType.invokerType(); 910184610Salfred 911192984Sthompsa LambdaForm lform = basicType.form().cachedLambdaForm(MethodTypeForm.LF_GWC); 912184610Salfred if (lform != null) { 913184610Salfred return lform; 914184610Salfred } 915184610Salfred final int THIS_MH = 0; // the BMH_LLLLL 916184610Salfred final int ARG_BASE = 1; // start of incoming arguments 917184610Salfred final int ARG_LIMIT = ARG_BASE + basicType.parameterCount(); 918184610Salfred 919184610Salfred int nameCursor = ARG_LIMIT; 920184610Salfred final int GET_TARGET = nameCursor++; 921193644Sthompsa final int GET_CLASS = nameCursor++; 922193644Sthompsa final int GET_CATCHER = nameCursor++; 923188982Sthompsa final int GET_COLLECT_ARGS = nameCursor++; 924184610Salfred final int GET_UNBOX_RESULT = nameCursor++; 925193644Sthompsa final int BOXED_ARGS = nameCursor++; 926188982Sthompsa final int TRY_CATCH = nameCursor++; 927184610Salfred final int UNBOX_RESULT = nameCursor++; 928188982Sthompsa 929188982Sthompsa Name[] names = arguments(nameCursor - ARG_LIMIT, lambdaType); 930188982Sthompsa 931188982Sthompsa BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLLLL(); 932188982Sthompsa names[THIS_MH] = names[THIS_MH].withConstraint(data); 933184610Salfred names[GET_TARGET] = new Name(data.getterFunction(0), names[THIS_MH]); 934188982Sthompsa names[GET_CLASS] = new Name(data.getterFunction(1), names[THIS_MH]); 935188982Sthompsa names[GET_CATCHER] = new Name(data.getterFunction(2), names[THIS_MH]); 936188982Sthompsa names[GET_COLLECT_ARGS] = new Name(data.getterFunction(3), names[THIS_MH]); 937188982Sthompsa names[GET_UNBOX_RESULT] = new Name(data.getterFunction(4), names[THIS_MH]); 938184610Salfred 939184610Salfred // FIXME: rework argument boxing/result unboxing logic for LF interpretation 940193644Sthompsa 941184610Salfred // t_{i}:L=MethodHandle.invokeBasic(collectArgs:L,a1:L,...); 942184610Salfred MethodType collectArgsType = basicType.changeReturnType(Object.class); 943184610Salfred MethodHandle invokeBasic = MethodHandles.basicInvoker(collectArgsType); 944184610Salfred Object[] args = new Object[invokeBasic.type().parameterCount()]; 945199672Sthompsa args[0] = names[GET_COLLECT_ARGS]; 946184610Salfred System.arraycopy(names, ARG_BASE, args, 1, ARG_LIMIT-ARG_BASE); 947184610Salfred names[BOXED_ARGS] = new Name(makeIntrinsic(invokeBasic, Intrinsic.GUARD_WITH_CATCH), args); 948199672Sthompsa 949199672Sthompsa // t_{i+1}:L=MethodHandleImpl.guardWithCatch(target:L,exType:L,catcher:L,t_{i}:L); 950199672Sthompsa Object[] gwcArgs = new Object[] {names[GET_TARGET], names[GET_CLASS], names[GET_CATCHER], names[BOXED_ARGS]}; 951184610Salfred names[TRY_CATCH] = new Name(NF_guardWithCatch, gwcArgs); 952199672Sthompsa 953199672Sthompsa // t_{i+2}:I=MethodHandle.invokeBasic(unbox:L,t_{i+1}:L); 954199672Sthompsa MethodHandle invokeBasicUnbox = MethodHandles.basicInvoker(MethodType.methodType(basicType.rtype(), Object.class)); 955199672Sthompsa Object[] unboxArgs = new Object[] {names[GET_UNBOX_RESULT], names[TRY_CATCH]}; 956199672Sthompsa names[UNBOX_RESULT] = new Name(invokeBasicUnbox, unboxArgs); 957199672Sthompsa 958188982Sthompsa lform = new LambdaForm("guardWithCatch", lambdaType.parameterCount(), names); 959188982Sthompsa 960188982Sthompsa return basicType.form().setCachedLambdaForm(MethodTypeForm.LF_GWC, lform); 961188982Sthompsa } 962188982Sthompsa 963188982Sthompsa static 964184610Salfred MethodHandle makeGuardWithCatch(MethodHandle target, 965188982Sthompsa Class<? extends Throwable> exType, 966188982Sthompsa MethodHandle catcher) { 967188982Sthompsa MethodType type = target.type(); 968188982Sthompsa LambdaForm form = makeGuardWithCatchForm(type.basicType()); 969188982Sthompsa 970184610Salfred // Prepare auxiliary method handles used during LambdaForm interpretation. 971199672Sthompsa // Box arguments and wrap them into Object[]: ValueConversions.array(). 972199672Sthompsa MethodType varargsType = type.changeReturnType(Object[].class); 973199672Sthompsa MethodHandle collectArgs = varargsArray(type.parameterCount()).asType(varargsType); 974199672Sthompsa // Result unboxing: ValueConversions.unbox() OR ValueConversions.identity() OR ValueConversions.ignore(). 975184610Salfred MethodHandle unboxResult; 976184610Salfred Class<?> rtype = type.returnType(); 977184610Salfred if (rtype.isPrimitive()) { 978184610Salfred if (rtype == void.class) { 979184610Salfred unboxResult = ValueConversions.ignore(); 980184610Salfred } else { 981184610Salfred Wrapper w = Wrapper.forPrimitiveType(type.returnType()); 982184610Salfred unboxResult = ValueConversions.unboxExact(w); 983184610Salfred } 984184610Salfred } else { 985184610Salfred unboxResult = MethodHandles.identity(Object.class); 986184610Salfred } 987184610Salfred 988184610Salfred BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLLLL(); 989184610Salfred BoundMethodHandle mh; 990184610Salfred try { 991184610Salfred mh = (BoundMethodHandle) 992184610Salfred data.constructor().invokeBasic(type, form, (Object) target, (Object) exType, (Object) catcher, 993184610Salfred (Object) collectArgs, (Object) unboxResult); 994184610Salfred } catch (Throwable ex) { 995184610Salfred throw uncaughtException(ex); 996184610Salfred } 997184610Salfred assert(mh.type() == type); 998184610Salfred return mh; 999184610Salfred } 1000184610Salfred 1001184610Salfred /** 1002184610Salfred * Intrinsified during LambdaForm compilation 1003184610Salfred * (see {@link InvokerBytecodeGenerator#emitGuardWithCatch emitGuardWithCatch}). 1004184610Salfred */ 1005184610Salfred @LambdaForm.Hidden 1006184610Salfred static Object guardWithCatch(MethodHandle target, Class<? extends Throwable> exType, MethodHandle catcher, 1007184610Salfred Object... av) throws Throwable { 1008184610Salfred // Use asFixedArity() to avoid unnecessary boxing of last argument for VarargsCollector case. 1009184610Salfred try { 1010184610Salfred return target.asFixedArity().invokeWithArguments(av); 1011184610Salfred } catch (Throwable t) { 1012184610Salfred if (!exType.isInstance(t)) throw t; 1013184610Salfred return catcher.asFixedArity().invokeWithArguments(prepend(t, av)); 1014184610Salfred } 1015184610Salfred } 1016184610Salfred 1017184610Salfred /** Prepend an element {@code elem} to an {@code array}. */ 1018184610Salfred @LambdaForm.Hidden 1019184610Salfred private static Object[] prepend(Object elem, Object[] array) { 1020184610Salfred Object[] newArray = new Object[array.length+1]; 1021184610Salfred newArray[0] = elem; 1022184610Salfred System.arraycopy(array, 0, newArray, 1, array.length); 1023184610Salfred return newArray; 1024184610Salfred } 1025184610Salfred 1026184610Salfred static 1027184610Salfred MethodHandle throwException(MethodType type) { 1028184610Salfred assert(Throwable.class.isAssignableFrom(type.parameterType(0))); 1029184610Salfred int arity = type.parameterCount(); 1030184610Salfred if (arity > 1) { 1031184610Salfred MethodHandle mh = throwException(type.dropParameterTypes(1, arity)); 1032184610Salfred mh = MethodHandles.dropArguments(mh, 1, type.parameterList().subList(1, arity)); 1033184610Salfred return mh; 1034184610Salfred } 1035184610Salfred return makePairwiseConvert(NF_throwException.resolvedHandle(), type, false, true); 1036184610Salfred } 1037184610Salfred 1038184610Salfred static <T extends Throwable> Empty throwException(T t) throws T { throw t; } 1039184610Salfred 1040184610Salfred static MethodHandle[] FAKE_METHOD_HANDLE_INVOKE = new MethodHandle[2]; 1041184610Salfred static MethodHandle fakeMethodHandleInvoke(MemberName method) { 1042184610Salfred int idx; 1043184610Salfred assert(method.isMethodHandleInvoke()); 1044184610Salfred switch (method.getName()) { 1045184610Salfred case "invoke": idx = 0; break; 1046184610Salfred case "invokeExact": idx = 1; break; 1047184610Salfred default: throw new InternalError(method.getName()); 1048184610Salfred } 1049184610Salfred MethodHandle mh = FAKE_METHOD_HANDLE_INVOKE[idx]; 1050184610Salfred if (mh != null) return mh; 1051184610Salfred MethodType type = MethodType.methodType(Object.class, UnsupportedOperationException.class, 1052184610Salfred MethodHandle.class, Object[].class); 1053184610Salfred mh = throwException(type); 1054184610Salfred mh = mh.bindTo(new UnsupportedOperationException("cannot reflectively invoke MethodHandle")); 1055184610Salfred if (!method.getInvocationType().equals(mh.type())) 1056184610Salfred throw new InternalError(method.toString()); 1057184610Salfred mh = mh.withInternalMemberName(method, false); 1058184610Salfred mh = mh.withVarargs(true); 1059184610Salfred assert(method.isVarargs()); 1060184610Salfred FAKE_METHOD_HANDLE_INVOKE[idx] = mh; 1061184610Salfred return mh; 1062184610Salfred } 1063184610Salfred static MethodHandle fakeVarHandleInvoke(MemberName method) { 1064184610Salfred // TODO caching, is it necessary? 1065184610Salfred MethodType type = MethodType.methodType(method.getReturnType(), UnsupportedOperationException.class, 1066184610Salfred VarHandle.class, Object[].class); 1067184610Salfred MethodHandle mh = throwException(type); 1068194228Sthompsa mh = mh.bindTo(new UnsupportedOperationException("cannot reflectively invoke VarHandle")); 1069184824Sthompsa if (!method.getInvocationType().equals(mh.type())) 1070184610Salfred throw new InternalError(method.toString()); 1071184824Sthompsa mh = mh.withInternalMemberName(method, false); 1072184610Salfred mh = mh.asVarargsCollector(Object[].class); 1073184610Salfred assert(method.isVarargs()); 1074194228Sthompsa return mh; 1075184610Salfred } 1076184610Salfred 1077184610Salfred /** 1078194228Sthompsa * Create an alias for the method handle which, when called, 1079184610Salfred * appears to be called from the same class loader and protection domain 1080184610Salfred * as hostClass. 1081184610Salfred * This is an expensive no-op unless the method which is called 1082184610Salfred * is sensitive to its caller. A small number of system methods 1083184610Salfred * are in this category, including Class.forName and Method.invoke. 1084194228Sthompsa */ 1085184610Salfred static 1086184610Salfred MethodHandle bindCaller(MethodHandle mh, Class<?> hostClass) { 1087194228Sthompsa return BindCaller.bindCaller(mh, hostClass); 1088184610Salfred } 1089192984Sthompsa 1090184610Salfred // Put the whole mess into its own nested class. 1091184824Sthompsa // That way we can lazily load the code and set up the constants. 1092184610Salfred private static class BindCaller { 1093184610Salfred static 1094184610Salfred MethodHandle bindCaller(MethodHandle mh, Class<?> hostClass) { 1095184610Salfred // Do not use this function to inject calls into system classes. 1096193045Sthompsa if (hostClass == null 1097194228Sthompsa || (hostClass.isArray() || 1098194228Sthompsa hostClass.isPrimitive() || 1099188411Sthompsa hostClass.getName().startsWith("java.") || 1100184610Salfred hostClass.getName().startsWith("sun."))) { 1101187174Sthompsa throw new InternalError(); // does not happen, and should not anyway 1102187174Sthompsa } 1103194228Sthompsa // For simplicity, convert mh to a varargs-like method. 1104187174Sthompsa MethodHandle vamh = prepareForInvoker(mh); 1105184824Sthompsa // Cache the result of makeInjectedInvoker once per argument class. 1106184610Salfred MethodHandle bccInvoker = CV_makeInjectedInvoker.get(hostClass); 1107190180Sthompsa return restoreToType(bccInvoker.bindTo(vamh), mh, hostClass); 1108184610Salfred } 1109184610Salfred 1110184610Salfred private static MethodHandle makeInjectedInvoker(Class<?> hostClass) { 1111194228Sthompsa Class<?> bcc = UNSAFE.defineAnonymousClass(hostClass, T_BYTES, null); 1112184610Salfred if (hostClass.getClassLoader() != bcc.getClassLoader()) 1113184610Salfred throw new InternalError(hostClass.getName()+" (CL)"); 1114184610Salfred try { 1115184610Salfred if (hostClass.getProtectionDomain() != bcc.getProtectionDomain()) 1116184610Salfred throw new InternalError(hostClass.getName()+" (PD)"); 1117184610Salfred } catch (SecurityException ex) { 1118194228Sthompsa // Self-check was blocked by security manager. This is OK. 1119184610Salfred // In fact the whole try body could be turned into an assertion. 1120184610Salfred } 1121184610Salfred try { 1122184610Salfred MethodHandle init = IMPL_LOOKUP.findStatic(bcc, "init", MethodType.methodType(void.class)); 1123194228Sthompsa init.invokeExact(); // force initialization of the class 1124190180Sthompsa } catch (Throwable ex) { 1125184610Salfred throw uncaughtException(ex); 1126194227Sthompsa } 1127184610Salfred MethodHandle bccInvoker; 1128184610Salfred try { 1129184610Salfred MethodType invokerMT = MethodType.methodType(Object.class, MethodHandle.class, Object[].class); 1130184610Salfred bccInvoker = IMPL_LOOKUP.findStatic(bcc, "invoke_V", invokerMT); 1131184610Salfred } catch (ReflectiveOperationException ex) { 1132184610Salfred throw uncaughtException(ex); 1133184610Salfred } 1134184610Salfred // Test the invoker, to ensure that it really injects into the right place. 1135184610Salfred try { 1136194228Sthompsa MethodHandle vamh = prepareForInvoker(MH_checkCallerClass); 1137184610Salfred Object ok = bccInvoker.invokeExact(vamh, new Object[]{hostClass, bcc}); 1138184610Salfred } catch (Throwable ex) { 1139184610Salfred throw new InternalError(ex); 1140184610Salfred } 1141184610Salfred return bccInvoker; 1142184610Salfred } 1143194228Sthompsa private static ClassValue<MethodHandle> CV_makeInjectedInvoker = new ClassValue<MethodHandle>() { 1144184610Salfred @Override protected MethodHandle computeValue(Class<?> hostClass) { 1145192984Sthompsa return makeInjectedInvoker(hostClass); 1146192984Sthompsa } 1147184610Salfred }; 1148184610Salfred 1149184610Salfred // Adapt mh so that it can be called directly from an injected invoker: 1150194228Sthompsa private static MethodHandle prepareForInvoker(MethodHandle mh) { 1151184610Salfred mh = mh.asFixedArity(); 1152184610Salfred MethodType mt = mh.type(); 1153184610Salfred int arity = mt.parameterCount(); 1154184610Salfred MethodHandle vamh = mh.asType(mt.generic()); 1155188982Sthompsa vamh.internalForm().compileToBytecode(); // eliminate LFI stack frames 1156188982Sthompsa vamh = vamh.asSpreader(Object[].class, arity); 1157184610Salfred vamh.internalForm().compileToBytecode(); // eliminate LFI stack frames 1158188982Sthompsa return vamh; 1159184610Salfred } 1160188982Sthompsa 1161188982Sthompsa // Undo the adapter effect of prepareForInvoker: 1162184610Salfred private static MethodHandle restoreToType(MethodHandle vamh, 1163188982Sthompsa MethodHandle original, 1164188982Sthompsa Class<?> hostClass) { 1165188982Sthompsa MethodType type = original.type(); 1166188982Sthompsa MethodHandle mh = vamh.asCollector(Object[].class, type.parameterCount()); 1167194228Sthompsa MemberName member = original.internalMemberName(); 1168194228Sthompsa mh = mh.asType(type); 1169188982Sthompsa mh = new WrappedMember(mh, type, member, original.isInvokeSpecial(), hostClass); 1170188982Sthompsa return mh; 1171188982Sthompsa } 1172194228Sthompsa 1173194228Sthompsa private static final MethodHandle MH_checkCallerClass; 1174188982Sthompsa static { 1175188982Sthompsa final Class<?> THIS_CLASS = BindCaller.class; 1176188982Sthompsa assert(checkCallerClass(THIS_CLASS, THIS_CLASS)); 1177188982Sthompsa try { 1178188982Sthompsa MH_checkCallerClass = IMPL_LOOKUP 1179188982Sthompsa .findStatic(THIS_CLASS, "checkCallerClass", 1180184610Salfred MethodType.methodType(boolean.class, Class.class, Class.class)); 1181188982Sthompsa assert((boolean) MH_checkCallerClass.invokeExact(THIS_CLASS, THIS_CLASS)); 1182188982Sthompsa } catch (Throwable ex) { 1183184610Salfred throw new InternalError(ex); 1184194228Sthompsa } 1185184610Salfred } 1186190180Sthompsa 1187188982Sthompsa @CallerSensitive 1188188982Sthompsa private static boolean checkCallerClass(Class<?> expected, Class<?> expected2) { 1189190180Sthompsa // This method is called via MH_checkCallerClass and so it's 1190188982Sthompsa // correct to ask for the immediate caller here. 1191193644Sthompsa Class<?> actual = Reflection.getCallerClass(); 1192193644Sthompsa if (actual != expected && actual != expected2) 1193188982Sthompsa throw new InternalError("found "+actual.getName()+", expected "+expected.getName() 1194199672Sthompsa +(expected == expected2 ? "" : ", or else "+expected2.getName())); 1195199672Sthompsa return true; 1196199672Sthompsa } 1197184610Salfred 1198194228Sthompsa private static final byte[] T_BYTES; 1199184610Salfred static { 1200188982Sthompsa final Object[] values = {null}; 1201184610Salfred AccessController.doPrivileged(new PrivilegedAction<>() { 1202188982Sthompsa public Void run() { 1203199816Sthompsa try { 1204184610Salfred Class<T> tClass = T.class; 1205188982Sthompsa String tName = tClass.getName(); 1206188982Sthompsa String tResource = tName.substring(tName.lastIndexOf('.')+1)+".class"; 1207188982Sthompsa try (java.io.InputStream in = tClass.getResourceAsStream(tResource)) { 1208194228Sthompsa values[0] = in.readAllBytes(); 1209188982Sthompsa } 1210188982Sthompsa } catch (java.io.IOException ex) { 1211188982Sthompsa throw new InternalError(ex); 1212184610Salfred } 1213184610Salfred return null; 1214184610Salfred } 1215184610Salfred }); 1216184610Salfred T_BYTES = (byte[]) values[0]; 1217194228Sthompsa } 1218184610Salfred 1219184610Salfred // The following class is used as a template for Unsafe.defineAnonymousClass: 1220192984Sthompsa private static class T { 1221184610Salfred static void init() { } // side effect: initializes this class 1222184610Salfred static Object invoke_V(MethodHandle vamh, Object[] args) throws Throwable { 1223184610Salfred return vamh.invokeExact(args); 1224184610Salfred } 1225184610Salfred } 1226184610Salfred } 1227184610Salfred 1228194228Sthompsa 1229184610Salfred /** This subclass allows a wrapped method handle to be re-associated with an arbitrary member name. */ 1230192984Sthompsa private static final class WrappedMember extends DelegatingMethodHandle { 1231184610Salfred private final MethodHandle target; 1232184610Salfred private final MemberName member; 1233184610Salfred private final Class<?> callerClass; 1234194228Sthompsa private final boolean isInvokeSpecial; 1235184610Salfred 1236184610Salfred private WrappedMember(MethodHandle target, MethodType type, 1237184610Salfred MemberName member, boolean isInvokeSpecial, 1238184610Salfred Class<?> callerClass) { 1239184610Salfred super(type, target); 1240184610Salfred this.target = target; 1241184610Salfred this.member = member; 1242193644Sthompsa this.callerClass = callerClass; 1243193644Sthompsa this.isInvokeSpecial = isInvokeSpecial; 1244184610Salfred } 1245184610Salfred 1246184610Salfred @Override 1247184610Salfred MemberName internalMemberName() { 1248194677Sthompsa return member; 1249184610Salfred } 1250184610Salfred @Override 1251184610Salfred Class<?> internalCallerClass() { 1252184610Salfred return callerClass; 1253184610Salfred } 1254184610Salfred @Override 1255184610Salfred boolean isInvokeSpecial() { 1256184610Salfred return isInvokeSpecial; 1257184610Salfred } 1258194677Sthompsa @Override 1259194677Sthompsa protected MethodHandle getTarget() { 1260184610Salfred return target; 1261193045Sthompsa } 1262184610Salfred @Override 1263184610Salfred public MethodHandle asTypeUncached(MethodType newType) { 1264192552Sthompsa // This MH is an alias for target, except for the MemberName 1265192552Sthompsa // Drop the MemberName if there is any conversion. 1266192552Sthompsa return asTypeCache = target.asType(newType); 1267184610Salfred } 1268192552Sthompsa } 1269192552Sthompsa 1270192552Sthompsa static MethodHandle makeWrappedMember(MethodHandle target, MemberName member, boolean isInvokeSpecial) { 1271184610Salfred if (member.equals(target.internalMemberName()) && isInvokeSpecial == target.isInvokeSpecial()) 1272190184Sthompsa return target; 1273190184Sthompsa return new WrappedMember(target, target.type(), member, isInvokeSpecial, null); 1274190184Sthompsa } 1275190184Sthompsa 1276190184Sthompsa /** Intrinsic IDs */ 1277190184Sthompsa /*non-public*/ 1278190184Sthompsa enum Intrinsic { 1279190184Sthompsa SELECT_ALTERNATIVE, 1280190184Sthompsa GUARD_WITH_CATCH, 1281190184Sthompsa NEW_ARRAY, 1282190184Sthompsa ARRAY_LOAD, 1283190184Sthompsa ARRAY_STORE, 1284190184Sthompsa IDENTITY, 1285190184Sthompsa ZERO, 1286184610Salfred NONE // no intrinsic associated 1287184610Salfred } 1288184610Salfred 1289184610Salfred /** Mark arbitrary method handle as intrinsic. 1290184610Salfred * InvokerBytecodeGenerator uses this info to produce more efficient bytecode shape. */ 1291184610Salfred private static final class IntrinsicMethodHandle extends DelegatingMethodHandle { 1292184610Salfred private final MethodHandle target; 1293184610Salfred private final Intrinsic intrinsicName; 1294184610Salfred 1295184610Salfred IntrinsicMethodHandle(MethodHandle target, Intrinsic intrinsicName) { 1296184610Salfred super(target.type(), target); 1297184610Salfred this.target = target; 1298184610Salfred this.intrinsicName = intrinsicName; 1299192499Sthompsa } 1300194228Sthompsa 1301184610Salfred @Override 1302184610Salfred protected MethodHandle getTarget() { 1303184610Salfred return target; 1304184610Salfred } 1305184610Salfred 1306184610Salfred @Override 1307184610Salfred Intrinsic intrinsicName() { 1308184610Salfred return intrinsicName; 1309184610Salfred } 1310184610Salfred 1311192984Sthompsa @Override 1312184610Salfred public MethodHandle asTypeUncached(MethodType newType) { 1313184610Salfred // This MH is an alias for target, except for the intrinsic name 1314192984Sthompsa // Drop the name if there is any conversion. 1315184610Salfred return asTypeCache = target.asType(newType); 1316184610Salfred } 1317184610Salfred 1318192499Sthompsa @Override 1319184610Salfred String internalProperties() { 1320184610Salfred return super.internalProperties() + 1321184610Salfred "\n& Intrinsic="+intrinsicName; 1322184610Salfred } 1323184610Salfred 1324184610Salfred @Override 1325184610Salfred public MethodHandle asCollector(Class<?> arrayType, int arrayLength) { 1326184610Salfred if (intrinsicName == Intrinsic.IDENTITY) { 1327184610Salfred MethodType resultType = type().asCollectorType(arrayType, type().parameterCount() - 1, arrayLength); 1328184610Salfred MethodHandle newArray = MethodHandleImpl.varargsArray(arrayType, arrayLength); 1329184610Salfred return newArray.asType(resultType); 1330184610Salfred } 1331184610Salfred return super.asCollector(arrayType, arrayLength); 1332184610Salfred } 1333194228Sthompsa } 1334184610Salfred 1335184610Salfred static MethodHandle makeIntrinsic(MethodHandle target, Intrinsic intrinsicName) { 1336184610Salfred if (intrinsicName == target.intrinsicName()) 1337184610Salfred return target; 1338184610Salfred return new IntrinsicMethodHandle(target, intrinsicName); 1339184610Salfred } 1340194228Sthompsa 1341184610Salfred static MethodHandle makeIntrinsic(MethodType type, LambdaForm form, Intrinsic intrinsicName) { 1342184610Salfred return new IntrinsicMethodHandle(SimpleMethodHandle.make(type, form), intrinsicName); 1343184610Salfred } 1344184610Salfred 1345184610Salfred /// Collection of multiple arguments. 1346184610Salfred 1347184610Salfred private static MethodHandle findCollector(String name, int nargs, Class<?> rtype, Class<?>... ptypes) { 1348184610Salfred MethodType type = MethodType.genericMethodType(nargs) 1349192984Sthompsa .changeReturnType(rtype) 1350184610Salfred .insertParameterTypes(0, ptypes); 1351184610Salfred try { 1352184610Salfred return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, name, type); 1353184610Salfred } catch (ReflectiveOperationException ex) { 1354184610Salfred return null; 1355197562Sthompsa } 1356199816Sthompsa } 1357197562Sthompsa 1358184610Salfred private static final Object[] NO_ARGS_ARRAY = {}; 1359184610Salfred private static Object[] makeArray(Object... args) { return args; } 1360184610Salfred private static Object[] array() { return NO_ARGS_ARRAY; } 1361184610Salfred private static Object[] array(Object a0) 1362184610Salfred { return makeArray(a0); } 1363184610Salfred private static Object[] array(Object a0, Object a1) 1364184610Salfred { return makeArray(a0, a1); } 1365184610Salfred private static Object[] array(Object a0, Object a1, Object a2) 1366184610Salfred { return makeArray(a0, a1, a2); } 1367184610Salfred private static Object[] array(Object a0, Object a1, Object a2, Object a3) 1368184610Salfred { return makeArray(a0, a1, a2, a3); } 1369199816Sthompsa private static Object[] array(Object a0, Object a1, Object a2, Object a3, 1370184610Salfred Object a4) 1371184610Salfred { return makeArray(a0, a1, a2, a3, a4); } 1372184610Salfred private static Object[] array(Object a0, Object a1, Object a2, Object a3, 1373184610Salfred Object a4, Object a5) 1374184610Salfred { return makeArray(a0, a1, a2, a3, a4, a5); } 1375184610Salfred private static Object[] array(Object a0, Object a1, Object a2, Object a3, 1376184610Salfred Object a4, Object a5, Object a6) 1377184610Salfred { return makeArray(a0, a1, a2, a3, a4, a5, a6); } 1378184610Salfred private static Object[] array(Object a0, Object a1, Object a2, Object a3, 1379184610Salfred Object a4, Object a5, Object a6, Object a7) 1380184610Salfred { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7); } 1381184610Salfred private static Object[] array(Object a0, Object a1, Object a2, Object a3, 1382184610Salfred Object a4, Object a5, Object a6, Object a7, 1383184610Salfred Object a8) 1384184610Salfred { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8); } 1385184610Salfred private static Object[] array(Object a0, Object a1, Object a2, Object a3, 1386184610Salfred Object a4, Object a5, Object a6, Object a7, 1387184610Salfred Object a8, Object a9) 1388184610Salfred { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } 1389184610Salfred 1390184610Salfred private static final int ARRAYS_COUNT = 11; 1391184610Salfred private static final @Stable MethodHandle[] ARRAYS = new MethodHandle[MAX_ARITY + 1]; 1392184610Salfred 1393184610Salfred // filling versions of the above: 1394184610Salfred // using Integer len instead of int len and no varargs to avoid bootstrapping problems 1395184610Salfred private static Object[] fillNewArray(Integer len, Object[] /*not ...*/ args) { 1396184610Salfred Object[] a = new Object[len]; 1397184610Salfred fillWithArguments(a, 0, args); 1398184610Salfred return a; 1399184610Salfred } 1400184610Salfred private static Object[] fillNewTypedArray(Object[] example, Integer len, Object[] /*not ...*/ args) { 1401184610Salfred Object[] a = Arrays.copyOf(example, len); 1402184610Salfred assert(a.getClass() != Object[].class); 1403194228Sthompsa fillWithArguments(a, 0, args); 1404184610Salfred return a; 1405184610Salfred } 1406184610Salfred private static void fillWithArguments(Object[] a, int pos, Object... args) { 1407184610Salfred System.arraycopy(args, 0, a, pos, args.length); 1408194228Sthompsa } 1409184610Salfred // using Integer pos instead of int pos to avoid bootstrapping problems 1410192984Sthompsa private static Object[] fillArray(Integer pos, Object[] a, Object a0) 1411192984Sthompsa { fillWithArguments(a, pos, a0); return a; } 1412193045Sthompsa private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1) 1413184610Salfred { fillWithArguments(a, pos, a0, a1); return a; } 1414191494Sthompsa private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2) 1415191494Sthompsa { fillWithArguments(a, pos, a0, a1, a2); return a; } 1416191494Sthompsa private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3) 1417193644Sthompsa { fillWithArguments(a, pos, a0, a1, a2, a3); return a; } 1418193644Sthompsa private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3, 1419184610Salfred Object a4) 1420184610Salfred { fillWithArguments(a, pos, a0, a1, a2, a3, a4); return a; } 1421207077Sthompsa private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3, 1422184610Salfred Object a4, Object a5) 1423191494Sthompsa { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5); return a; } 1424184610Salfred private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3, 1425194228Sthompsa Object a4, Object a5, Object a6) 1426184610Salfred { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6); return a; } 1427191494Sthompsa private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3, 1428184610Salfred Object a4, Object a5, Object a6, Object a7) 1429184610Salfred { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7); return a; } 1430184610Salfred private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3, 1431184824Sthompsa Object a4, Object a5, Object a6, Object a7, 1432191494Sthompsa Object a8) 1433184610Salfred { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7, a8); return a; } 1434184610Salfred private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3, 1435184610Salfred Object a4, Object a5, Object a6, Object a7, 1436184610Salfred Object a8, Object a9) 1437184610Salfred { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); return a; } 1438184610Salfred 1439184610Salfred private static final int FILL_ARRAYS_COUNT = 11; // current number of fillArray methods 1440191494Sthompsa private static final @Stable MethodHandle[] FILL_ARRAYS = new MethodHandle[FILL_ARRAYS_COUNT]; 1441193644Sthompsa 1442191494Sthompsa private static MethodHandle getFillArray(int count) { 1443184610Salfred assert (count > 0 && count < FILL_ARRAYS_COUNT); 1444184610Salfred MethodHandle mh = FILL_ARRAYS[count]; 1445184610Salfred if (mh != null) { 1446184610Salfred return mh; 1447190734Sthompsa } 1448186730Salfred mh = findCollector("fillArray", count, Object[].class, Integer.class, Object[].class); 1449194228Sthompsa FILL_ARRAYS[count] = mh; 1450190734Sthompsa return mh; 1451184610Salfred } 1452184610Salfred 1453184610Salfred private static Object copyAsPrimitiveArray(Wrapper w, Object... boxes) { 1454184610Salfred Object a = w.makeArray(boxes.length); 1455184610Salfred w.copyArrayUnboxing(boxes, 0, a, 0, boxes.length); 1456191494Sthompsa return a; 1457194228Sthompsa } 1458191494Sthompsa 1459184610Salfred /** Return a method handle that takes the indicated number of Object 1460184610Salfred * arguments and returns an Object array of them, as if for varargs. 1461184610Salfred */ 1462184610Salfred static MethodHandle varargsArray(int nargs) { 1463184610Salfred MethodHandle mh = ARRAYS[nargs]; 1464184610Salfred if (mh != null) { 1465184610Salfred return mh; 1466190180Sthompsa } 1467184610Salfred if (nargs < ARRAYS_COUNT) { 1468184610Salfred mh = findCollector("array", nargs, Object[].class); 1469190180Sthompsa } else { 1470184610Salfred mh = buildVarargsArray(getConstantHandle(MH_fillNewArray), 1471184610Salfred getConstantHandle(MH_arrayIdentity), nargs); 1472184610Salfred } 1473184610Salfred assert(assertCorrectArity(mh, nargs)); 1474184610Salfred mh = makeIntrinsic(mh, Intrinsic.NEW_ARRAY); 1475184610Salfred return ARRAYS[nargs] = mh; 1476184610Salfred } 1477184610Salfred 1478184610Salfred private static boolean assertCorrectArity(MethodHandle mh, int arity) { 1479184610Salfred assert(mh.type().parameterCount() == arity) : "arity != "+arity+": "+mh; 1480184610Salfred return true; 1481191824Sthompsa } 1482191824Sthompsa 1483191824Sthompsa // Array identity function (used as getConstantHandle(MH_arrayIdentity)). 1484192051Sthompsa static <T> T[] identity(T[] x) { 1485192051Sthompsa return x; 1486192051Sthompsa } 1487192051Sthompsa 1488194228Sthompsa private static MethodHandle buildVarargsArray(MethodHandle newArray, MethodHandle finisher, int nargs) { 1489191824Sthompsa // Build up the result mh as a sequence of fills like this: 1490191824Sthompsa // finisher(fill(fill(newArrayWA(23,x1..x10),10,x11..x20),20,x21..x23)) 1491191824Sthompsa // The various fill(_,10*I,___*[J]) are reusable. 1492191824Sthompsa int leftLen = Math.min(nargs, LEFT_ARGS); // absorb some arguments immediately 1493184610Salfred int rightLen = nargs - leftLen; 1494184610Salfred MethodHandle leftCollector = newArray.bindTo(nargs); 1495184610Salfred leftCollector = leftCollector.asCollector(Object[].class, leftLen); 1496184610Salfred MethodHandle mh = finisher; 1497184610Salfred if (rightLen > 0) { 1498184610Salfred MethodHandle rightFiller = fillToRight(LEFT_ARGS + rightLen); 1499184610Salfred if (mh.equals(getConstantHandle(MH_arrayIdentity))) 1500184610Salfred mh = rightFiller; 1501184610Salfred else 1502191494Sthompsa mh = MethodHandles.collectArguments(mh, 0, rightFiller); 1503184610Salfred } 1504184610Salfred if (mh.equals(getConstantHandle(MH_arrayIdentity))) 1505194228Sthompsa mh = leftCollector; 1506191494Sthompsa else 1507184610Salfred mh = MethodHandles.collectArguments(mh, 0, leftCollector); 1508184610Salfred return mh; 1509191494Sthompsa } 1510194228Sthompsa 1511191494Sthompsa private static final int LEFT_ARGS = FILL_ARRAYS_COUNT - 1; 1512184610Salfred private static final @Stable MethodHandle[] FILL_ARRAY_TO_RIGHT = new MethodHandle[MAX_ARITY + 1]; 1513184610Salfred /** fill_array_to_right(N).invoke(a, argL..arg[N-1]) 1514184610Salfred * fills a[L]..a[N-1] with corresponding arguments, 1515184610Salfred * and then returns a. The value L is a global constant (LEFT_ARGS). 1516184610Salfred */ 1517184610Salfred private static MethodHandle fillToRight(int nargs) { 1518184610Salfred MethodHandle filler = FILL_ARRAY_TO_RIGHT[nargs]; 1519184610Salfred if (filler != null) return filler; 1520191494Sthompsa filler = buildFiller(nargs); 1521194228Sthompsa assert(assertCorrectArity(filler, nargs - LEFT_ARGS + 1)); 1522191494Sthompsa return FILL_ARRAY_TO_RIGHT[nargs] = filler; 1523184610Salfred } 1524184610Salfred private static MethodHandle buildFiller(int nargs) { 1525184610Salfred if (nargs <= LEFT_ARGS) 1526184610Salfred return getConstantHandle(MH_arrayIdentity); // no args to fill; return the array unchanged 1527184610Salfred // we need room for both mh and a in mh.invoke(a, arg*[nargs]) 1528184610Salfred final int CHUNK = LEFT_ARGS; 1529184610Salfred int rightLen = nargs % CHUNK; 1530184610Salfred int midLen = nargs - rightLen; 1531184610Salfred if (rightLen == 0) { 1532184610Salfred midLen = nargs - (rightLen = CHUNK); 1533184610Salfred if (FILL_ARRAY_TO_RIGHT[midLen] == null) { 1534184610Salfred // build some precursors from left to right 1535184610Salfred for (int j = LEFT_ARGS % CHUNK; j < midLen; j += CHUNK) 1536194677Sthompsa if (j > LEFT_ARGS) fillToRight(j); 1537191494Sthompsa } 1538194228Sthompsa } 1539191494Sthompsa if (midLen < LEFT_ARGS) rightLen = nargs - (midLen = LEFT_ARGS); 1540184610Salfred assert(rightLen > 0); 1541184610Salfred MethodHandle midFill = fillToRight(midLen); // recursive fill 1542184610Salfred MethodHandle rightFill = getFillArray(rightLen).bindTo(midLen); // [midLen..nargs-1] 1543184610Salfred assert(midFill.type().parameterCount() == 1 + midLen - LEFT_ARGS); 1544184610Salfred assert(rightFill.type().parameterCount() == 1 + rightLen); 1545184610Salfred 1546184610Salfred // Combine the two fills: 1547184610Salfred // right(mid(a, x10..x19), x20..x23) 1548184610Salfred // The final product will look like this: 1549190184Sthompsa // right(mid(newArrayLeft(24, x0..x9), x10..x19), x20..x23) 1550190184Sthompsa if (midLen == LEFT_ARGS) 1551190184Sthompsa return rightFill; 1552190184Sthompsa else 1553190184Sthompsa return MethodHandles.collectArguments(rightFill, 0, midFill); 1554184610Salfred } 1555190184Sthompsa 1556190184Sthompsa static final int MAX_JVM_ARITY = 255; // limit imposed by the JVM 1557190184Sthompsa 1558190184Sthompsa /** Return a method handle that takes the indicated number of 1559190184Sthompsa * typed arguments and returns an array of them. 1560190184Sthompsa * The type argument is the array type. 1561190184Sthompsa */ 1562190184Sthompsa static MethodHandle varargsArray(Class<?> arrayType, int nargs) { 1563190184Sthompsa Class<?> elemType = arrayType.getComponentType(); 1564190184Sthompsa if (elemType == null) throw new IllegalArgumentException("not an array: "+arrayType); 1565190184Sthompsa // FIXME: Need more special casing and caching here. 1566190184Sthompsa if (nargs >= MAX_JVM_ARITY/2 - 1) { 1567190184Sthompsa int slots = nargs; 1568190184Sthompsa final int MAX_ARRAY_SLOTS = MAX_JVM_ARITY - 1; // 1 for receiver MH 1569190184Sthompsa if (slots <= MAX_ARRAY_SLOTS && elemType.isPrimitive()) 1570184610Salfred slots *= Wrapper.forPrimitiveType(elemType).stackSlots(); 1571184610Salfred if (slots > MAX_ARRAY_SLOTS) 1572184610Salfred throw new IllegalArgumentException("too many arguments: "+arrayType.getSimpleName()+", length "+nargs); 1573184610Salfred } 1574184610Salfred if (elemType == Object.class) 1575184610Salfred return varargsArray(nargs); 1576184610Salfred // other cases: primitive arrays, subtypes of Object[] 1577184610Salfred MethodHandle cache[] = Makers.TYPED_COLLECTORS.get(elemType); 1578190180Sthompsa MethodHandle mh = nargs < cache.length ? cache[nargs] : null; 1579184610Salfred if (mh != null) return mh; 1580184610Salfred if (nargs == 0) { 1581194228Sthompsa Object example = java.lang.reflect.Array.newInstance(arrayType.getComponentType(), 0); 1582184610Salfred mh = MethodHandles.constant(arrayType, example); 1583184610Salfred } else if (elemType.isPrimitive()) { 1584190180Sthompsa MethodHandle builder = getConstantHandle(MH_fillNewArray); 1585184610Salfred MethodHandle producer = buildArrayProducer(arrayType); 1586184610Salfred mh = buildVarargsArray(builder, producer, nargs); 1587184610Salfred } else { 1588184610Salfred Class<? extends Object[]> objArrayType = arrayType.asSubclass(Object[].class); 1589194228Sthompsa Object[] example = Arrays.copyOf(NO_ARGS_ARRAY, 0, objArrayType); 1590184610Salfred MethodHandle builder = getConstantHandle(MH_fillNewTypedArray).bindTo(example); 1591184610Salfred MethodHandle producer = getConstantHandle(MH_arrayIdentity); // must be weakly typed 1592184610Salfred mh = buildVarargsArray(builder, producer, nargs); 1593194228Sthompsa } 1594184610Salfred mh = mh.asType(MethodType.methodType(arrayType, Collections.<Class<?>>nCopies(nargs, elemType))); 1595184610Salfred mh = makeIntrinsic(mh, Intrinsic.NEW_ARRAY); 1596194228Sthompsa assert(assertCorrectArity(mh, nargs)); 1597184610Salfred if (nargs < cache.length) 1598193644Sthompsa cache[nargs] = mh; 1599184610Salfred return mh; 1600184824Sthompsa } 1601184610Salfred 1602187173Sthompsa private static MethodHandle buildArrayProducer(Class<?> arrayType) { 1603184610Salfred Class<?> elemType = arrayType.getComponentType(); 1604193644Sthompsa assert(elemType.isPrimitive()); 1605184610Salfred return getConstantHandle(MH_copyAsPrimitiveArray).bindTo(Wrapper.forPrimitiveType(elemType)); 1606184610Salfred } 1607184610Salfred 1608184610Salfred /*non-public*/ static void assertSame(Object mh1, Object mh2) { 1609193644Sthompsa if (mh1 != mh2) { 1610184610Salfred String msg = String.format("mh1 != mh2: mh1 = %s (form: %s); mh2 = %s (form: %s)", 1611190738Sthompsa mh1, ((MethodHandle)mh1).form, 1612190738Sthompsa mh2, ((MethodHandle)mh2).form); 1613190738Sthompsa throw newInternalError(msg); 1614190738Sthompsa } 1615190738Sthompsa } 1616194228Sthompsa 1617190738Sthompsa // Local constant functions: 1618190738Sthompsa /*non-public*/ static final NamedFunction 1619184610Salfred NF_checkSpreadArgument, 1620184610Salfred NF_guardWithCatch, 1621184610Salfred NF_throwException, 1622194228Sthompsa NF_profileBoolean; 1623187173Sthompsa 1624184610Salfred static { 1625184610Salfred try { 1626184610Salfred NF_checkSpreadArgument = new NamedFunction(MethodHandleImpl.class 1627194228Sthompsa .getDeclaredMethod("checkSpreadArgument", Object.class, int.class)); 1628184610Salfred NF_guardWithCatch = new NamedFunction(MethodHandleImpl.class 1629184610Salfred .getDeclaredMethod("guardWithCatch", MethodHandle.class, Class.class, 1630184610Salfred MethodHandle.class, Object[].class)); 1631184610Salfred NF_throwException = new NamedFunction(MethodHandleImpl.class 1632184610Salfred .getDeclaredMethod("throwException", Throwable.class)); 1633184610Salfred NF_profileBoolean = new NamedFunction(MethodHandleImpl.class 1634194228Sthompsa .getDeclaredMethod("profileBoolean", boolean.class, int[].class)); 1635184610Salfred } catch (ReflectiveOperationException ex) { 1636184610Salfred throw newInternalError(ex); 1637184610Salfred } 1638184610Salfred } 1639184610Salfred 1640184824Sthompsa /** 1641184610Salfred * Assembles a loop method handle from the given handles and type information. This works by binding and configuring 1642184610Salfred * the {@linkplain #looper(MethodHandle[], MethodHandle[], MethodHandle[], MethodHandle[], int, int, Object[]) "most 1643184610Salfred * generic loop"}. 1644184610Salfred * 1645197562Sthompsa * @param tloop the return type of the loop. 1646197562Sthompsa * @param targs types of the arguments to be passed to the loop. 1647184610Salfred * @param tvars types of loop-local variables. 1648197562Sthompsa * @param init sanitized array of initializers for loop-local variables. 1649184610Salfred * @param step sanitited array of loop bodies. 1650184610Salfred * @param pred sanitized array of predicates. 1651184610Salfred * @param fini sanitized array of loop finalizers. 1652184610Salfred * 1653184610Salfred * @return a handle that, when invoked, will execute the loop. 1654184610Salfred */ 1655187173Sthompsa static MethodHandle makeLoop(Class<?> tloop, List<Class<?>> targs, List<Class<?>> tvars, List<MethodHandle> init, 1656184610Salfred List<MethodHandle> step, List<MethodHandle> pred, List<MethodHandle> fini) { 1657194228Sthompsa MethodHandle[] ainit = toArrayArgs(init); 1658187173Sthompsa MethodHandle[] astep = toArrayArgs(step); 1659184610Salfred MethodHandle[] apred = toArrayArgs(pred); 1660184610Salfred MethodHandle[] afini = toArrayArgs(fini); 1661184610Salfred 1662194228Sthompsa MethodHandle l = getConstantHandle(MH_looper); 1663184610Salfred 1664184610Salfred // Bind the statically known arguments. 1665184610Salfred l = MethodHandles.insertArguments(l, 0, ainit, astep, apred, afini, tvars.size(), targs.size()); 1666184610Salfred 1667194228Sthompsa // Turn the args array into an argument list. 1668184610Salfred l = l.asCollector(Object[].class, targs.size()); 1669184610Salfred 1670194228Sthompsa // Finally, make loop type. 1671184610Salfred MethodType loopType = MethodType.methodType(tloop, targs); 1672193644Sthompsa l = l.asType(loopType); 1673184610Salfred 1674184610Salfred return l; 1675184610Salfred } 1676184610Salfred 1677184610Salfred /** 1678184824Sthompsa * Converts all handles in the {@code hs} array to handles that accept an array of arguments. 1679184610Salfred * 1680184610Salfred * @param hs method handles to be converted. 1681184610Salfred * 1682184610Salfred * @return the {@code hs} array, with all method handles therein converted. 1683197562Sthompsa */ 1684197562Sthompsa static MethodHandle[] toArrayArgs(List<MethodHandle> hs) { 1685197562Sthompsa return hs.stream().map(h -> h.asSpreader(Object[].class, h.type().parameterCount())).toArray(MethodHandle[]::new); 1686197562Sthompsa } 1687197562Sthompsa 1688197562Sthompsa /** 1689197562Sthompsa * This method embodies the most generic loop for use by {@link MethodHandles#loop(MethodHandle[][])}. A handle on 1690184610Salfred * it will be transformed into a handle on a concrete loop instantiation by {@link #makeLoop}. 1691184610Salfred * 1692184610Salfred * @param init loop-local variable initializers. 1693184610Salfred * @param step bodies. 1694187173Sthompsa * @param pred predicates. 1695197562Sthompsa * @param fini finalizers. 1696197562Sthompsa * @param varSize number of loop-local variables. 1697197562Sthompsa * @param nArgs number of arguments passed to the loop. 1698184610Salfred * @param args arguments to the loop invocation. 1699184610Salfred * 1700184610Salfred * @return the result of executing the loop. 1701184610Salfred */ 1702184610Salfred static Object looper(MethodHandle[] init, MethodHandle[] step, MethodHandle[] pred, MethodHandle[] fini, 1703184610Salfred int varSize, int nArgs, Object[] args) throws Throwable { 1704184610Salfred Object[] varsAndArgs = new Object[varSize + nArgs]; 1705184610Salfred for (int i = 0, v = 0; i < init.length; ++i) { 1706184610Salfred if (init[i].type().returnType() == void.class) { 1707184610Salfred init[i].invoke(args); 1708184610Salfred } else { 1709184610Salfred varsAndArgs[v++] = init[i].invoke(args); 1710184610Salfred } 1711184610Salfred } 1712184610Salfred System.arraycopy(args, 0, varsAndArgs, varSize, nArgs); 1713184610Salfred final int nSteps = step.length; 1714184610Salfred for (; ; ) { 1715184610Salfred for (int i = 0, v = 0; i < nSteps; ++i) { 1716193644Sthompsa MethodHandle p = pred[i]; 1717184610Salfred MethodHandle s = step[i]; 1718184610Salfred MethodHandle f = fini[i]; 1719184610Salfred if (s.type().returnType() == void.class) { 1720184610Salfred s.invoke(varsAndArgs); 1721184610Salfred } else { 1722184610Salfred varsAndArgs[v++] = s.invoke(varsAndArgs); 1723184610Salfred } 1724184610Salfred if (!(boolean) p.invoke(varsAndArgs)) { 1725184610Salfred return f.invoke(varsAndArgs); 1726193644Sthompsa } 1727184610Salfred } 1728184610Salfred } 1729184610Salfred } 1730194228Sthompsa 1731184610Salfred /** 1732184610Salfred * This method is bound as the predicate in {@linkplain MethodHandles#countedLoop(MethodHandle, MethodHandle, 1733184610Salfred * MethodHandle) counting loops}. 1734184610Salfred * 1735193644Sthompsa * @param counter the counter parameter, passed in during loop execution. 1736184610Salfred * @param limit the upper bound of the parameter, statically bound at loop creation time. 1737193644Sthompsa * 1738184610Salfred * @return whether the counter has reached the limit. 1739184610Salfred */ 1740184610Salfred static boolean countedLoopPredicate(int counter, int limit) { 1741184610Salfred return counter <= limit; 1742184610Salfred } 1743193644Sthompsa 1744194228Sthompsa /** 1745184610Salfred * This method is bound as the step function in {@linkplain MethodHandles#countedLoop(MethodHandle, MethodHandle, 1746184610Salfred * MethodHandle) counting loops} to increment the counter. 1747184610Salfred * 1748187173Sthompsa * @param counter the loop counter. 1749184610Salfred * 1750184610Salfred * @return the loop counter incremented by 1. 1751184610Salfred */ 1752194228Sthompsa static int countedLoopStep(int counter, int limit) { 1753184610Salfred return counter + 1; 1754184610Salfred } 1755184610Salfred 1756184610Salfred /** 1757184610Salfred * This method is bound as a filter in {@linkplain MethodHandles#countedLoop(MethodHandle, MethodHandle, MethodHandle, 1758184610Salfred * MethodHandle) counting loops} to pass the correct counter value to the body. 1759184610Salfred * 1760184610Salfred * @param counter the loop counter. 1761194228Sthompsa * 1762184610Salfred * @return the loop counter decremented by 1. 1763192984Sthompsa */ 1764192984Sthompsa static int decrementCounter(int counter) { 1765184610Salfred return counter - 1; 1766188600Sthompsa } 1767188600Sthompsa 1768188600Sthompsa /** 1769188600Sthompsa * This is bound to initialize the loop-local iterator in {@linkplain MethodHandles#iteratedLoop iterating loops}. 1770184824Sthompsa * 1771184610Salfred * @param it the {@link Iterable} over which the loop iterates. 1772184610Salfred * 1773184610Salfred * @return an {@link Iterator} over the argument's elements. 1774184610Salfred */ 1775184610Salfred static Iterator<?> initIterator(Iterable<?> it) { 1776187173Sthompsa return it.iterator(); 1777184610Salfred } 1778184610Salfred 1779187173Sthompsa /** 1780184610Salfred * This method is bound as the predicate in {@linkplain MethodHandles#iteratedLoop iterating loops}. 1781184610Salfred * 1782187173Sthompsa * @param it the iterator to be checked. 1783184610Salfred * 1784184610Salfred * @return {@code true} iff there are more elements to iterate over. 1785184610Salfred */ 1786184610Salfred static boolean iteratePredicate(Iterator<?> it) { 1787187173Sthompsa return it.hasNext(); 1788184610Salfred } 1789184610Salfred 1790184610Salfred /** 1791187173Sthompsa * This method is bound as the step for retrieving the current value from the iterator in {@linkplain 1792184610Salfred * MethodHandles#iteratedLoop iterating loops}. 1793184610Salfred * 1794184610Salfred * @param it the iterator. 1795184610Salfred * 1796194228Sthompsa * @return the next element from the iterator. 1797184610Salfred */ 1798184610Salfred static Object iterateNext(Iterator<?> it) { 1799184610Salfred return it.next(); 1800184610Salfred } 1801184610Salfred 1802184610Salfred /** 1803184610Salfred * Makes a {@code try-finally} handle that conforms to the type constraints. 1804194228Sthompsa * 1805184610Salfred * @param target the target to execute in a {@code try-finally} block. 1806184610Salfred * @param cleanup the cleanup to execute in the {@code finally} block. 1807194228Sthompsa * @param type the result type of the entire construct. 1808184610Salfred * @param argTypes the types of the arguments. 1809184610Salfred * 1810184610Salfred * @return a handle on the constructed {@code try-finally} block. 1811184610Salfred */ 1812184610Salfred static MethodHandle makeTryFinally(MethodHandle target, MethodHandle cleanup, Class<?> type, List<Class<?>> argTypes) { 1813187173Sthompsa MethodHandle tf = getConstantHandle(type == void.class ? MH_tryFinallyVoidExec : MH_tryFinallyExec); 1814184824Sthompsa 1815184610Salfred // Bind the statically known arguments. 1816184824Sthompsa tf = MethodHandles.insertArguments(tf, 0, target, cleanup); 1817184610Salfred 1818194228Sthompsa // Turn the args array into an argument list. 1819184610Salfred tf = tf.asCollector(Object[].class, argTypes.size()); 1820198775Sthompsa 1821198775Sthompsa // Finally, make try-finally type. 1822198775Sthompsa MethodType tfType = MethodType.methodType(type, argTypes); 1823198775Sthompsa tf = tf.asType(tfType); 1824198775Sthompsa 1825198775Sthompsa return tf; 1826198775Sthompsa } 1827198775Sthompsa 1828198775Sthompsa /** 1829198775Sthompsa * A method that will be bound during construction of a {@code try-finally} handle with non-{@code void} return type 1830184610Salfred * by {@link MethodHandles#tryFinally(MethodHandle, MethodHandle)}. 1831198775Sthompsa * 1832184610Salfred * @param target the handle to wrap in a {@code try-finally} block. This will be bound. 1833184610Salfred * @param cleanup the handle to run in any case before returning. This will be bound. 1834184610Salfred * @param args the arguments to the call. These will remain as the argument list. 1835184610Salfred * 1836194227Sthompsa * @return whatever the execution of the {@code target} returned (it may have been modified by the execution of 1837184610Salfred * {@code cleanup}). 1838184824Sthompsa * @throws Throwable in case anything is thrown by the execution of {@code target}, the {@link Throwable} will be 1839184610Salfred * passed to the {@code cleanup} handle, which may decide to throw any exception it sees fit. 1840184610Salfred */ 1841194677Sthompsa static Object tryFinallyExecutor(MethodHandle target, MethodHandle cleanup, Object[] args) throws Throwable { 1842194677Sthompsa Throwable t = null; 1843194677Sthompsa Object r = null; 1844194677Sthompsa try { 1845194677Sthompsa r = target.invoke(args); 1846194677Sthompsa } catch (Throwable thrown) { 1847194677Sthompsa t = thrown; 1848194677Sthompsa throw t; 1849199059Sthompsa } finally { 1850199059Sthompsa r = cleanup.invoke(t, r, args); 1851199059Sthompsa } 1852199059Sthompsa return r; 1853199059Sthompsa } 1854199059Sthompsa 1855199059Sthompsa /** 1856199059Sthompsa * A method that will be bound during construction of a {@code try-finally} handle with {@code void} return type by 1857199059Sthompsa * {@link MethodHandles#tryFinally(MethodHandle, MethodHandle)}. 1858199059Sthompsa * 1859199059Sthompsa * @param target the handle to wrap in a {@code try-finally} block. This will be bound. 1860199059Sthompsa * @param cleanup the handle to run in any case before returning. This will be bound. 1861199059Sthompsa * @param args the arguments to the call. These will remain as the argument list. 1862199059Sthompsa * 1863199059Sthompsa * @throws Throwable in case anything is thrown by the execution of {@code target}, the {@link Throwable} will be 1864199059Sthompsa * passed to the {@code cleanup} handle, which may decide to throw any exception it sees fit. 1865199059Sthompsa */ 1866194677Sthompsa static void tryFinallyVoidExecutor(MethodHandle target, MethodHandle cleanup, Object[] args) throws Throwable { 1867194682Sthompsa Throwable t = null; 1868194677Sthompsa try { 1869194677Sthompsa target.invoke(args); 1870194677Sthompsa } catch (Throwable thrown) { 1871194677Sthompsa t = thrown; 1872194677Sthompsa throw t; 1873194677Sthompsa } finally { 1874184610Salfred cleanup.invoke(t, args); 1875194677Sthompsa } 1876184610Salfred } 1877184610Salfred 1878184610Salfred // Indexes into constant method handles: 1879184610Salfred static final int 1880184610Salfred MH_cast = 0, 1881184610Salfred MH_selectAlternative = 1, 1882184610Salfred MH_copyAsPrimitiveArray = 2, 1883194677Sthompsa MH_fillNewTypedArray = 3, 1884194677Sthompsa MH_fillNewArray = 4, 1885184610Salfred MH_arrayIdentity = 5, 1886194677Sthompsa MH_looper = 6, 1887194677Sthompsa MH_countedLoopPred = 7, 1888184610Salfred MH_countedLoopStep = 8, 1889184610Salfred MH_iteratePred = 9, 1890194677Sthompsa MH_initIterator = 10, 1891184610Salfred MH_iterateNext = 11, 1892184610Salfred MH_tryFinallyExec = 12, 1893194677Sthompsa MH_tryFinallyVoidExec = 13, 1894194682Sthompsa MH_decrementCounter = 14, 1895194677Sthompsa MH_LIMIT = 15; 1896194677Sthompsa 1897194677Sthompsa static MethodHandle getConstantHandle(int idx) { 1898194677Sthompsa MethodHandle handle = HANDLES[idx]; 1899194677Sthompsa if (handle != null) { 1900194677Sthompsa return handle; 1901194677Sthompsa } 1902194677Sthompsa return setCachedHandle(idx, makeConstantHandle(idx)); 1903194677Sthompsa } 1904194677Sthompsa 1905194677Sthompsa private static synchronized MethodHandle setCachedHandle(int idx, final MethodHandle method) { 1906194677Sthompsa // Simulate a CAS, to avoid racy duplication of results. 1907194677Sthompsa MethodHandle prev = HANDLES[idx]; 1908194677Sthompsa if (prev != null) { 1909194677Sthompsa return prev; 1910194677Sthompsa } 1911194677Sthompsa HANDLES[idx] = method; 1912194677Sthompsa return method; 1913194677Sthompsa } 1914194677Sthompsa 1915194677Sthompsa // Local constant method handles: 1916194677Sthompsa private static final @Stable MethodHandle[] HANDLES = new MethodHandle[MH_LIMIT]; 1917194677Sthompsa 1918194677Sthompsa private static MethodHandle makeConstantHandle(int idx) { 1919184610Salfred try { 1920194677Sthompsa switch (idx) { 1921184610Salfred case MH_cast: 1922184610Salfred return IMPL_LOOKUP.findVirtual(Class.class, "cast", 1923184610Salfred MethodType.methodType(Object.class, Object.class)); 1924184610Salfred case MH_copyAsPrimitiveArray: 1925184610Salfred return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "copyAsPrimitiveArray", 1926194677Sthompsa MethodType.methodType(Object.class, Wrapper.class, Object[].class)); 1927193045Sthompsa case MH_arrayIdentity: 1928184610Salfred return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "identity", 1929194677Sthompsa MethodType.methodType(Object[].class, Object[].class)); 1930199816Sthompsa case MH_fillNewArray: 1931194677Sthompsa return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "fillNewArray", 1932184610Salfred MethodType.methodType(Object[].class, Integer.class, Object[].class)); 1933184610Salfred case MH_fillNewTypedArray: 1934184610Salfred return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "fillNewTypedArray", 1935184610Salfred MethodType.methodType(Object[].class, Object[].class, Integer.class, Object[].class)); 1936184610Salfred case MH_selectAlternative: 1937184610Salfred return makeIntrinsic(IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "selectAlternative", 1938194677Sthompsa MethodType.methodType(MethodHandle.class, boolean.class, MethodHandle.class, MethodHandle.class)), 1939194677Sthompsa Intrinsic.SELECT_ALTERNATIVE); 1940194677Sthompsa case MH_looper: 1941194677Sthompsa return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "looper", MethodType.methodType(Object.class, 1942194677Sthompsa MethodHandle[].class, MethodHandle[].class, MethodHandle[].class, MethodHandle[].class, 1943194677Sthompsa int.class, int.class, Object[].class)); 1944194677Sthompsa case MH_countedLoopPred: 1945194677Sthompsa return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "countedLoopPredicate", 1946194677Sthompsa MethodType.methodType(boolean.class, int.class, int.class)); 1947194677Sthompsa case MH_countedLoopStep: 1948194677Sthompsa return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "countedLoopStep", 1949194677Sthompsa MethodType.methodType(int.class, int.class, int.class)); 1950194677Sthompsa case MH_iteratePred: 1951194677Sthompsa return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "iteratePredicate", 1952194677Sthompsa MethodType.methodType(boolean.class, Iterator.class)); 1953194677Sthompsa case MH_initIterator: 1954194677Sthompsa return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "initIterator", 1955194677Sthompsa MethodType.methodType(Iterator.class, Iterable.class)); 1956194677Sthompsa case MH_iterateNext: 1957194677Sthompsa return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "iterateNext", 1958194677Sthompsa MethodType.methodType(Object.class, Iterator.class)); 1959194677Sthompsa case MH_tryFinallyExec: 1960194677Sthompsa return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "tryFinallyExecutor", 1961194677Sthompsa MethodType.methodType(Object.class, MethodHandle.class, MethodHandle.class, Object[].class)); 1962194677Sthompsa case MH_tryFinallyVoidExec: 1963194677Sthompsa return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "tryFinallyVoidExecutor", 1964194677Sthompsa MethodType.methodType(void.class, MethodHandle.class, MethodHandle.class, Object[].class)); 1965194677Sthompsa case MH_decrementCounter: 1966194677Sthompsa return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "decrementCounter", 1967194677Sthompsa MethodType.methodType(int.class, int.class)); 1968194677Sthompsa } 1969194677Sthompsa } catch (ReflectiveOperationException ex) { 1970194677Sthompsa throw newInternalError(ex); 1971194677Sthompsa } 1972194677Sthompsa throw newInternalError("Unknown function index: " + idx); 1973194677Sthompsa } 1974194677Sthompsa} 1975194677Sthompsa