static { try { MethodType idType = MethodType.genericMethodType(1); MethodType castType = idType.insertParameterTypes(0, Class.class); MethodType ignoreType = idType.changeReturnType(void.class); MethodType zeroObjectType = MethodType.genericMethodType(0); IDENTITY = IMPL_LOOKUP.findStatic(THIS_CLASS, "identity", idType); // CAST_REFERENCE = IMPL_LOOKUP.findVirtual(Class.class, "cast", idType); CAST_REFERENCE = IMPL_LOOKUP.findStatic(THIS_CLASS, "castReference", castType); ZERO_OBJECT = IMPL_LOOKUP.findStatic(THIS_CLASS, "zeroObject", zeroObjectType); IGNORE = IMPL_LOOKUP.findStatic(THIS_CLASS, "ignore", ignoreType); EMPTY = IMPL_LOOKUP.findStatic(THIS_CLASS, "empty", ignoreType.dropParameterTypes(0, 1)); ARRAY_IDENTITY = IMPL_LOOKUP.findStatic( THIS_CLASS, "identity", MethodType.methodType(Object[].class, Object[].class)); FILL_NEW_ARRAY = IMPL_LOOKUP.findStatic( THIS_CLASS, "fillNewArray", MethodType.methodType(Object[].class, Integer.class, Object[].class)); FILL_NEW_TYPED_ARRAY = IMPL_LOOKUP.findStatic( THIS_CLASS, "fillNewTypedArray", MethodType.methodType(Object[].class, Object[].class, Integer.class, Object[].class)); } catch (NoSuchMethodException | IllegalAccessException ex) { throw newInternalError("uncaught exception", ex); } }
public static MethodHandle identity(Wrapper wrap) { EnumMap<Wrapper, MethodHandle> cache = CONSTANT_FUNCTIONS[1]; MethodHandle mh = cache.get(wrap); if (mh != null) { return mh; } // slow path MethodType type = MethodType.methodType(wrap.primitiveType()); if (wrap != Wrapper.VOID) type = type.appendParameterTypes(wrap.primitiveType()); try { mh = IMPL_LOOKUP.findStatic(THIS_CLASS, "identity", type); } catch (ReflectiveOperationException ex) { mh = null; } if (mh == null && wrap == Wrapper.VOID) { mh = EMPTY; // #(){} : #()void } if (mh != null) { cache.put(wrap, mh); return mh; } if (mh != null) { cache.put(wrap, mh); return mh; } throw new IllegalArgumentException("cannot find identity for " + wrap); }
/** * Return a method handle that takes the indicated number of typed arguments and returns an array * of them. The type argument is the array type. */ public static MethodHandle varargsArray(Class<?> arrayType, int nargs) { Class<?> elemType = arrayType.getComponentType(); if (elemType == null) throw new IllegalArgumentException("not an array: " + arrayType); // FIXME: Need more special casing and caching here. if (nargs >= MAX_JVM_ARITY / 2 - 1) { int slots = nargs; final int MAX_ARRAY_SLOTS = MAX_JVM_ARITY - 1; // 1 for receiver MH if (arrayType == double[].class || arrayType == long[].class) slots *= 2; if (slots > MAX_ARRAY_SLOTS) throw new IllegalArgumentException( "too many arguments: " + arrayType.getSimpleName() + ", length " + nargs); } if (elemType == Object.class) return varargsArray(nargs); // other cases: primitive arrays, subtypes of Object[] MethodHandle cache[] = TYPED_COLLECTORS.get(elemType); MethodHandle mh = nargs < cache.length ? cache[nargs] : null; if (mh != null) return mh; if (elemType.isPrimitive()) { MethodHandle builder = FILL_NEW_ARRAY; MethodHandle producer = buildArrayProducer(arrayType); mh = buildVarargsArray(builder, producer, nargs); } else { @SuppressWarnings("unchecked") Class<? extends Object[]> objArrayType = (Class<? extends Object[]>) arrayType; Object[] example = Arrays.copyOf(NO_ARGS_ARRAY, 0, objArrayType); MethodHandle builder = FILL_NEW_TYPED_ARRAY.bindTo(example); MethodHandle producer = ARRAY_IDENTITY; mh = buildVarargsArray(builder, producer, nargs); } mh = mh.asType(MethodType.methodType(arrayType, Collections.<Class<?>>nCopies(nargs, elemType))); assert (assertCorrectArity(mh, nargs)); if (nargs < cache.length) cache[nargs] = mh; return mh; }
public static MethodHandle convertPrimitive(Wrapper wsrc, Wrapper wdst) { EnumMap<Wrapper, MethodHandle> cache = CONVERT_PRIMITIVE_FUNCTIONS[wsrc.ordinal()]; MethodHandle mh = cache.get(wdst); if (mh != null) { return mh; } // slow path Class<?> src = wsrc.primitiveType(); Class<?> dst = wdst.primitiveType(); MethodType type = src == void.class ? MethodType.methodType(dst) : MethodType.methodType(dst, src); if (wsrc == wdst) { mh = identity(src); } else if (wsrc == Wrapper.VOID) { mh = zeroConstantFunction(wdst); } else if (wdst == Wrapper.VOID) { mh = MethodHandles.dropArguments(EMPTY, 0, src); // Defer back to MethodHandles. } else if (wsrc == Wrapper.OBJECT) { mh = unboxCast(dst); } else if (wdst == Wrapper.OBJECT) { mh = box(src); } else { assert (src.isPrimitive() && dst.isPrimitive()); try { mh = IMPL_LOOKUP.findStatic( THIS_CLASS, src.getSimpleName() + "To" + capitalize(dst.getSimpleName()), type); } catch (ReflectiveOperationException ex) { mh = null; } } if (mh != null) { assert (mh.type() == type) : mh; cache.put(wdst, mh); return mh; } throw new IllegalArgumentException( "cannot find primitive conversion function for " + src.getSimpleName() + " -> " + dst.getSimpleName()); }
static { try { // MAKE_ARRAY = IMPL_LOOKUP.findStatic(THIS_CLASS, "makeArray", // MethodType.methodType(Object[].class, Object[].class)); COPY_AS_REFERENCE_ARRAY = IMPL_LOOKUP.findStatic( THIS_CLASS, "copyAsReferenceArray", MethodType.methodType(Object[].class, Class.class, Object[].class)); COPY_AS_PRIMITIVE_ARRAY = IMPL_LOOKUP.findStatic( THIS_CLASS, "copyAsPrimitiveArray", MethodType.methodType(Object.class, Wrapper.class, Object[].class)); MAKE_LIST = IMPL_LOOKUP.findStatic( THIS_CLASS, "makeList", MethodType.methodType(List.class, Object[].class)); } catch (ReflectiveOperationException ex) { throw newInternalError("uncaught exception", ex); } }
public static MethodHandle zeroConstantFunction(Wrapper wrap) { EnumMap<Wrapper, MethodHandle> cache = CONSTANT_FUNCTIONS[0]; MethodHandle mh = cache.get(wrap); if (mh != null) { return mh; } // slow path MethodType type = MethodType.methodType(wrap.primitiveType()); switch (wrap) { case VOID: mh = EMPTY; break; case OBJECT: case INT: case LONG: case FLOAT: case DOUBLE: try { mh = IMPL_LOOKUP.findStatic(THIS_CLASS, "zero" + wrap.wrapperSimpleName(), type); } catch (ReflectiveOperationException ex) { mh = null; } break; } if (mh != null) { cache.put(wrap, mh); return mh; } // use zeroInt and cast the result if (wrap.isSubwordOrInt() && wrap != Wrapper.INT) { mh = MethodHandles.explicitCastArguments(zeroConstantFunction(Wrapper.INT), type); cache.put(wrap, mh); return mh; } throw new IllegalArgumentException("cannot find zero constant for " + wrap); }
private static MethodType boxType(Wrapper wrap) { // be exact, since return casts are hard to compose Class<?> boxType = wrap.wrapperType(); return MethodType.methodType(boxType, wrap.primitiveType()); }
private static MethodType unboxType(Wrapper wrap) { return MethodType.methodType(wrap.primitiveType(), Object.class, boolean.class); }