/** * Generate test with an invokedynamic, a static bootstrap method with an extra arg that is a * MethodHandle of kind invoke interface. The target method is a default method into an interface * that is at the end of a chain of interfaces. */ private void generateMethodTest6(ClassVisitor cv) { MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "test6", "()V", null, null); MethodType mt = MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class, MethodHandle.class); Handle bootstrap = new Handle(Opcodes.H_INVOKESTATIC, Type.getInternalName(InvokeCustom.class), "bsmCreateCallCallingtargetMethodTest7", mt.toMethodDescriptorString(), false); mv.visitTypeInsn(Opcodes.NEW, Type.getInternalName(InvokeCustom.class)); mv.visitInsn(Opcodes.DUP); mv.visitMethodInsn( Opcodes.INVOKESPECIAL, Type.getInternalName(InvokeCustom.class), "<init>", "()V", false); mv.visitInvokeDynamicInsn("targetMethodTest7", "(Linvokecustom/J;)V", bootstrap, new Handle(Opcodes.H_INVOKEINTERFACE, Type.getInternalName(J.class), "targetMethodTest7", "()V", true)); mv.visitInsn(Opcodes.RETURN); mv.visitMaxs(-1, -1); }
/** * Generate test with an invokedynamic, a static bootstrap method with an extra arg that is a * MethodHandle of kind invoke interface. The target method is a method into an interface * that is shadowed by another definition into a sub interfaces. */ private void generateMethodTest7(ClassVisitor cv) { MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "test7", "()V", null, null); MethodType mt = MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class, MethodHandle.class); Handle bootstrap = new Handle(Opcodes.H_INVOKESTATIC, Type.getInternalName(InvokeCustom.class), "bsmCreateCallCallingtargetMethodTest8", mt.toMethodDescriptorString(), false); mv.visitTypeInsn(Opcodes.NEW, Type.getInternalName(InvokeCustom.class)); mv.visitInsn(Opcodes.DUP); mv.visitMethodInsn( Opcodes.INVOKESPECIAL, Type.getInternalName(InvokeCustom.class), "<init>", "()V", false); mv.visitInvokeDynamicInsn("targetMethodTest8", "(Linvokecustom/J;)V", bootstrap, new Handle(Opcodes.H_INVOKEINTERFACE, Type.getInternalName(J.class), "targetMethodTest8", "()V", true)); mv.visitInsn(Opcodes.RETURN); mv.visitMaxs(-1, -1); }
private MethodHandle getTestMH(Class clazz, String methodName, Object param, boolean isNegativeTest) throws Exception { MethodType mType = (param != null) ? MethodType.genericMethodType(1) : MethodType.methodType(String.class); MethodHandles.Lookup lookup = MethodHandles.lookup(); if (!isNegativeTest) { return methodName.equals("staticMethod") ? lookup.findStatic(clazz, methodName, mType) : lookup.findVirtual(clazz, methodName, mType); } else { return methodName.equals("staticMethod") ? lookup.findVirtual(clazz, methodName, mType) : lookup.findStatic(clazz, methodName, mType); } }
/** * ECMA 15.4.4.20 Array.prototype.filter ( callbackfn [ , thisArg ] ) * * @param self self reference * @param callbackfn callback function per element * @param thisArg this argument * @return filtered array */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) public static NativeArray filter(final Object self, final Object callbackfn, final Object thisArg) { return new IteratorAction<NativeArray>(Global.toObject(self), callbackfn, thisArg, new NativeArray()) { private long to = 0; private final MethodHandle filterInvoker = getFILTER_CALLBACK_INVOKER(); @Override protected boolean forEach(final Object val, final long i) throws Throwable { if ((boolean)filterInvoker.invokeExact(callbackfn, thisArg, val, i, self)) { result.defineOwnProperty(ArrayIndex.getArrayIndex(to++), val); } return true; } }.apply(); }
public void testInvokePolymorphicWithAllTypes() { try { MethodHandle mth = MethodHandles.lookup() .findStatic( InvokePolymorphic.class, "testWithAllTypes", MethodType.methodType( void.class, boolean.class, char.class, short.class, int.class, long.class, float.class, double.class, String.class, Object.class)); mth.invokeExact(false,'h', (short) 56, 72, Integer.MAX_VALUE + 42l, 0.56f, 100.0d, "hello", (Object) "goodbye"); } catch (Throwable t) { t.printStackTrace(); } }
private MethodHandle debug(final MethodHandle mh, final Class<?> forType, final Class<?> type, final String tag) { if (!Context.DEBUG || !Global.hasInstance()) { return mh; } final Context context = Context.getContextTrusted(); assert context != null; return context.addLoggingToHandle( ObjectClassGenerator.class, Level.INFO, mh, 0, true, new Supplier<String>() { @Override public String get() { return tag + " '" + getKey() + "' (property="+ Debug.id(this) + ", slot=" + getSlot() + " " + getClass().getSimpleName() + " forType=" + stripName(forType) + ", type=" + stripName(type) + ')'; } }); }
private final MethodHandle findReadWriteObjectForSerialization(Class<?> cl, String methodName, Class<?> streamClass) { if (!Serializable.class.isAssignableFrom(cl)) { return null; } try { Method meth = cl.getDeclaredMethod(methodName, streamClass); int mods = meth.getModifiers(); if (meth.getReturnType() != Void.TYPE || Modifier.isStatic(mods) || !Modifier.isPrivate(mods)) { return null; } meth.setAccessible(true); return MethodHandles.lookup().unreflect(meth); } catch (NoSuchMethodException ex) { return null; } catch (IllegalAccessException ex1) { throw new InternalError("Error", ex1); } }
public void testTargetClassInOpenModule() throws Throwable { // m1/p1.Type Class<?> clazz = Class.forName("p1.Type"); assertEquals(clazz.getModule().getName(), "m1"); // ensure that this module reads m1 Module thisModule = getClass().getModule(); Module m1 = clazz.getModule(); thisModule.addReads(clazz.getModule()); assertTrue(m1.isOpen("p1", thisModule)); Lookup lookup = MethodHandles.privateLookupIn(clazz, MethodHandles.lookup()); assertTrue(lookup.lookupClass() == clazz); assertTrue(lookup.hasPrivateAccess()); // get obj field MethodHandle mh = lookup.findStaticGetter(clazz, "obj", Object.class); Object obj = mh.invokeExact(); }
@Test public void testInitialize() { final DynamicLinkerFactory factory = new DynamicLinkerFactory(); final DynamicLinker linker = factory.createLinker(); final MethodType mt = MethodType.methodType(Object.class, Object.class); final boolean[] initializeCalled = { Boolean.FALSE }; linker.link(new SimpleRelinkableCallSite(new CallSiteDescriptor( MethodHandles.publicLookup(), GET_PROPERTY.named("DO_NOT_CARE"), mt)) { @Override public void initialize(final MethodHandle relinkAndInvoke) { initializeCalled[0] = Boolean.TRUE; super.initialize(relinkAndInvoke); } }); Assert.assertTrue(initializeCalled[0]); }
public void testInterfaceCast0() throws Throwable { if (CAN_SKIP_WORKING) return; startTest("interfaceCast"); assert( (((Object)"foo") instanceof CharSequence)); assert(!(((Object)"foo") instanceof Iterable)); for (MethodHandle mh : new MethodHandle[]{ MethodHandles.identity(String.class), MethodHandles.identity(CharSequence.class), MethodHandles.identity(Iterable.class) }) { if (verbosity > 0) System.out.println("-- mh = "+mh); for (Class<?> ctype : new Class<?>[]{ Object.class, String.class, CharSequence.class, Number.class, Iterable.class }) { if (verbosity > 0) System.out.println("---- ctype = "+ctype.getName()); // doret docast testInterfaceCast(mh, ctype, false, false); testInterfaceCast(mh, ctype, true, false); testInterfaceCast(mh, ctype, false, true); testInterfaceCast(mh, ctype, true, true); } } }
static MethodHandle getCached(final int slot, final boolean isPrimitive, final boolean isGetter) { //Reference<Accessors> ref = ACCESSOR_CACHE.get(slot); ensure(slot); Accessors acc = ACCESSOR_CACHE[slot]; if (acc == null) { acc = new Accessors(slot); ACCESSOR_CACHE[slot] = acc; } return acc.getOrCreate(isPrimitive, isGetter); }
MethodHandle createConverter(final Class<?> sourceType, final Class<?> targetType) throws Exception { final MethodType type = MethodType.methodType(targetType, sourceType); final MethodHandle identity = IDENTITY_CONVERSION.asType(type); MethodHandle last = identity; final LookupSupplier lookupSupplier = new LookupSupplier(); try { for(int i = factories.length; i-- > 0;) { final GuardedInvocation next = factories[i].convertToType(sourceType, targetType, lookupSupplier); if(next != null) { last = next.compose(last); } } } finally { lookupSupplier.closed = true; } if(last == identity) { return IDENTITY_CONVERSION; } if(!lookupSupplier.returnedLookup) { return last; } // At least one of the consulted converter factories obtained the // lookup, so we must presume the created converter is sensitive to the // lookup class and thus we will not cache it. throw new NotCacheableConverter(last); }
private static MethodHandle getCreateProgramFunctionHandle(final Class<?> script) { try { return LOOKUP.findStatic(script, CREATE_PROGRAM_FUNCTION.symbolName(), CREATE_PROGRAM_FUNCTION_TYPE); } catch (NoSuchMethodException | IllegalAccessException e) { throw new AssertionError("Failed to retrieve a handle for the program function for " + script.getName(), e); } }
@Override public void logX(sun.util.logging.PlatformLogger.Bridge logger, Level level, Object... args) { try { MethodHandle handle = lookup.findVirtual(bridgeLoggerClass, method, mt).bindTo(logger); final int last = mt.parameterCount()-1; boolean isVarargs = mt.parameterType(last).isArray(); args = makeArgs(level, args); final StringBuilder builder = new StringBuilder(); builder.append(logger.getClass().getSimpleName()).append('.') .append(this.method).append('('); String sep = ""; int offset = 0; Object[] params = args; for (int i=0; (i-offset) < params.length; i++) { if (isVarargs && i == last) { offset = last; params = (Object[])args[i]; if (params == null) break; } Object p = params[i - offset]; String quote = (p instanceof String) ? "\"" : ""; p = p instanceof Level ? "Level."+p : p; builder.append(sep).append(quote).append(p).append(quote); sep = ", "; } builder.append(')'); if (verbose) System.out.println(builder); handle.invokeWithArguments(args); } catch (Throwable ex) { throw new RuntimeException(ex); } }
public Stream<MethodHandle> methodHandles(Class<?> target) { return Methods.declaredMethodsInAncestors(target) .map(method -> { try { return lookup.unreflect(method); } catch(IllegalAccessException e) { return null; } }).filter(h -> h != null); }
@Override public MethodHandle getElementGetter(final Class<?> returnType, final int programPoint) { if (returnType == int.class) { return null; } return getContinuousElementGetter(getClass(), GET_ELEM, returnType, programPoint); }
public static void main(String[] args) throws Throwable { MethodHandle mh = MethodHandles.lookup().findVirtual(CharSequence.class, "toString", MethodType.methodType(String.class)); MethodType mt = MethodType.methodType(Object.class, CharSequence.class); mh = mh.asType(mt); Object res = mh.invokeExact((CharSequence)"123"); System.out.println("TEST PASSED"); }
/** * Checks that the lambda forms of the two adapter method handles adapter1 * and adapter2 are the same. * * @param adapter1 First method handle. * @param adapter2 Second method handle. */ public void checkLFCaching(MethodHandle adapter1, MethodHandle adapter2) { try { if (!adapter1.type().equals(adapter2.type())) { throw new Error("TESTBUG: Types of the two method handles are not the same"); } Object lambdaForm0 = LambdaFormTestCase.INTERNAL_FORM.invoke(adapter1); Object lambdaForm1 = LambdaFormTestCase.INTERNAL_FORM.invoke(adapter2); if (lambdaForm0 == null || lambdaForm1 == null) { throw new Error("Unexpected error: One or both lambda forms of the method handles are null"); } if (lambdaForm0 != lambdaForm1) { // Since LambdaForm caches are based on SoftReferences, GC can cause element eviction. if (noGCHappened()) { System.err.println("Lambda form 0 toString is:"); System.err.println(lambdaForm0); System.err.println("Lambda form 1 toString is:"); System.err.println(lambdaForm1); throw new AssertionError("Error: Lambda forms of the two method handles" + " are not the same. LF cahing does not work"); } else { System.err.println("LambdaForms differ, but there was a GC in between. Ignore the failure."); } } } catch (IllegalAccessException | IllegalArgumentException | SecurityException | InvocationTargetException ex) { throw new Error("Unexpected exception", ex); } }
public static CallSite bsmCreateCallSite( MethodHandles.Lookup caller, String name, MethodType type, MethodHandle mh) throws Throwable { // Using mh to create the call site fails when run on Art. See b/36957105 for details. final MethodHandle targetMH = MethodHandles.lookup().findSpecial(Super.class, "targetMethodTest5", MethodType.methodType(void.class), InvokeCustom.class); return new ConstantCallSite(targetMH); }
public static CallSite bsmCreateCallCallingtargetMethodTest6( MethodHandles.Lookup caller, String name, MethodType type, MethodHandle mh) throws Throwable { // Using mh to create the call site fails when run on Art. See b/36957105 for details. final MethodHandle targetMH = MethodHandles.lookup().findVirtual( I.class, "targetMethodTest6", MethodType.methodType(void.class)); return new ConstantCallSite(targetMH); }
/** * Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflect(Method)}, converting any encountered * {@link IllegalAccessException} into an {@link IllegalAccessError}. * * @param lookup the lookup used to unreflect * @param m the method to unreflect * @return the unreflected method handle. */ public static MethodHandle unreflect(final MethodHandles.Lookup lookup, final Method m) { try { return lookup.unreflect(m); } catch(final IllegalAccessException e) { final IllegalAccessError ee = new IllegalAccessError("Failed to unreflect method " + m); ee.initCause(e); throw ee; } }
@SuppressWarnings("unused") private static void invokeNumberSetter(final Accessors gs, final MethodHandle invoker, final String name, final Object self, final double value) throws Throwable { final Object func = gs.setter; if (func instanceof ScriptFunction) { invoker.invokeExact(func, self, value); } else if (name != null) { throw typeError("property.has.no.setter", name, ScriptRuntime.safeToString(self)); } }
/** * Given a method handle and an expected return type, perform return value filtering * according to the optimistic type coercion rules * @param mh method handle * @param expectedReturnType expected return type * @param programPoint program point * @return filtered method */ public static MethodHandle filterOptimisticReturnValue(final MethodHandle mh, final Class<?> expectedReturnType, final int programPoint) { if(!isValid(programPoint)) { return mh; } final MethodType type = mh.type(); final Class<?> actualReturnType = type.returnType(); if(TypeUtilities.isConvertibleWithoutLoss(actualReturnType, expectedReturnType)) { return mh; } final MethodHandle guard = getOptimisticTypeGuard(expectedReturnType, actualReturnType); return guard == null ? mh : MH.filterReturnValue(mh, MH.insertArguments(guard, guard.type().parameterCount() - 1, programPoint)); }
private static MethodHandle getCALL_CMP() { return Global.instance().getDynamicInvoker(CALL_CMP, new Callable<MethodHandle>() { @Override public MethodHandle call() { return Bootstrap.createDynamicCallInvoker(double.class, Object.class, Object.class, Object.class, Object.class); } }); }
private static MethodHandle getReplaceValueInvoker() { return Global.instance().getDynamicInvoker(REPLACE_VALUE, new Callable<MethodHandle>() { @Override public MethodHandle call() { return Bootstrap.createDynamicCallInvoker(String.class, Object.class, Object.class, Object[].class); } }); }
@Test @ExpectedExceptions(IllegalArgumentException.class) public void dropArgumentsToMatchTestWithVoid() throws Throwable { MethodHandle cat = lookup().findVirtual(String.class, "concat", MethodType.methodType(String.class, String.class)); MethodType bigTypewithVoid = cat.type().insertParameterTypes(0, void.class, String.class, int.class); MethodHandle handle2 = MethodHandles.dropArgumentsToMatch(cat, 0, bigTypewithVoid.parameterList(), 1); }
@Test public static void testFoldArgumentsExample() throws Throwable { // test the JavaDoc foldArguments-with-pos example StringWriter swr = new StringWriter(); MethodHandle trace = LOOKUP.findVirtual(StringWriter.class, "write", methodType(void.class, String.class)).bindTo(swr); MethodHandle cat = LOOKUP.findVirtual(String.class, "concat", methodType(String.class, String.class)); assertEquals("boojum", (String) cat.invokeExact("boo", "jum")); MethodHandle catTrace = MethodHandles.foldArguments(cat, 1, trace); assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum")); assertEquals("jum", swr.toString()); }
@Test(dataProvider = "countedLoopBodyParameters") public static void testCountedLoopBodyParameters(MethodType countType, MethodType initType, MethodType bodyType) throws Throwable { MethodHandle loop = MethodHandles.countedLoop( MethodHandles.empty(countType), initType == null ? null : MethodHandles.empty(initType), MethodHandles.empty(bodyType)); // The rule: If body takes the minimum number of parameters, then take what countType offers. // The initType has to just roll with whatever the other two agree on. int innerParams = (bodyType.returnType() == void.class ? 1 : 2); MethodType expectType = bodyType.dropParameterTypes(0, innerParams); if (expectType.parameterCount() == 0) expectType = expectType.insertParameterTypes(0, countType.parameterList()); assertEquals(expectType, loop.type()); }
@Override public MethodHandle getElementGetter(final Class<?> returnType, final int programPoint) { if (returnType.isPrimitive()) { return null; } return getContinuousElementGetter(HAS_GET_ELEM, returnType, programPoint); }
/** Returns an appropriate method handle for a unary or shift operator, based only on the receiver (LHS) */ public static MethodHandle lookupUnary(Class<?> receiverClass, String name) { MethodHandle handle = TYPE_OP_MAPPING.get(promote(unbox(receiverClass))).get(name); if (handle == null) { throw new ClassCastException("Cannot apply operator [" + name + "] to type [" + receiverClass + "]"); } return handle; }
private static MethodHandle getObjectGetterInvoker() { return Context.getGlobal().getDynamicInvoker(OBJECT_GETTER_INVOKER_KEY, new Callable<MethodHandle>() { @Override public MethodHandle call() throws Exception { return getINVOKE_UA_GETTER(Object.class, INVALID_PROGRAM_POINT); } }); }
@Override public MethodHandle findSpecial(final MethodHandles.Lookup explicitLookup, final Class<?> clazz, final String name, final MethodType type, final Class<?> thisClass) { try { final MethodHandle mh = explicitLookup.findSpecial(clazz, name, type, thisClass); return debug(mh, "findSpecial", explicitLookup, clazz, name, type); } catch (final NoSuchMethodException | IllegalAccessException e) { throw new LookupException(e); } }
@Override public void setTarget(final MethodHandle newTarget) { if (!getNashornDescriptor().isTraceEnterExit()) { super.setTarget(newTarget); return; } final MethodType type = type(); final boolean isVoid = type.returnType() == void.class; MethodHandle traceMethodHandle = isVoid ? TRACEVOID : TRACEOBJECT; traceMethodHandle = MH.bindTo(traceMethodHandle, this); traceMethodHandle = MH.bindTo(traceMethodHandle, newTarget); traceMethodHandle = MH.asCollector(traceMethodHandle, Object[].class, type.parameterCount()); traceMethodHandle = MH.asType(traceMethodHandle, type); super.setTarget(traceMethodHandle); }
public static MethodHandle cast(MethodHandle mh, MethodType mt) throws Throwable { println("calling " + mh.type() + " as " + mt); if (explicit) { return MethodHandles.explicitCastArguments(mh, mt); } else { return mh.asType(mt); } }
public static MethodHandle findFieldGetter(Class<?> clazz, String... fieldNames) { final Field field = ReflectionHelper.findField(clazz, fieldNames); try { return MethodHandles.lookup().unreflectGetter(field); } catch (IllegalAccessException e) { throw new ReflectionHelper.UnableToAccessFieldException(fieldNames, e); } }
@Test public static void testFold0a() throws Throwable { // equivalence to foldArguments(MethodHandle,MethodHandle) MethodHandle fold = MethodHandles.foldArguments(Fold.MH_multer, 0, Fold.MH_adder); assertEquals(Fold.MT_folded1, fold.type()); assertEquals(720, (int) fold.invoke(3, 4, 5)); }
/** * Hook that is called just before invoking method handle * from ScriptFunctionData via invoke, constructor method calls. * * @param mh script class method about to be invoked. */ static void notifyInvoke(final MethodHandle mh) { // Do nothing here. This is placeholder method on which a // debugger can place a breakpoint so that it can access the // (script class) method handle that is about to be invoked. // See ScriptFunctionData.invoke and ScriptFunctionData.construct. }
private static MethodHandle getREVIVER_INVOKER() { return Context.getGlobal().getDynamicInvoker(REVIVER_INVOKER, new Callable<MethodHandle>() { @Override public MethodHandle call() { return Bootstrap.createDynamicCallInvoker(Object.class, Object.class, Object.class, String.class, Object.class); } }); }
void testFindStatic(boolean positive, Lookup lookup, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable { countTest(positive); String methodName = name.substring(1 + name.indexOf('/')); // foo/bar => foo MethodType type = MethodType.methodType(ret, params); MethodHandle target = null; Exception noAccess = null; try { if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type); target = maybeMoveIn(lookup, defc).findStatic(defc, methodName, type); } catch (ReflectiveOperationException ex) { noAccess = ex; assertExceptionClass( (name.contains("bogus") || INIT_REF_CAUSES_NSME && name.contains("<init>")) ? NoSuchMethodException.class : IllegalAccessException.class, noAccess); if (verbosity >= 5) ex.printStackTrace(System.out); } if (verbosity >= 3) System.out.println("findStatic "+lookup+": "+defc.getName()+"."+name+"/"+type+" => "+target +(noAccess == null ? "" : " !! "+noAccess)); if (positive && noAccess != null) throw noAccess; assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null); if (!positive) return; // negative test failed as expected assertEquals(type, target.type()); assertNameStringContains(target, methodName); Object[] args = randomArgs(params); printCalled(target, name, args); target.invokeWithArguments(args); assertCalled(name, args); if (verbosity >= 1) System.out.print(':'); }
@Test public static void testIterateSum() throws Throwable { // Integer[] a = new Integer[]{1,2,3,4,5,6}; int sum = 0; for (int e : a) { sum += e; } return sum; => 21 MethodHandle loop = MethodHandles.iteratedLoop(Iterate.MH_sumIterator, Iterate.MH_sumInit, Iterate.MH_sumStep); assertEquals(Iterate.MT_sum, loop.type()); assertEquals(21, loop.invoke(new Integer[]{1, 2, 3, 4, 5, 6})); }