private static void registerCallSitePlugins(InvocationPlugins plugins) { InvocationPlugin plugin = new InvocationPlugin() { @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { ValueNode callSite = receiver.get(); ValueNode folded = CallSiteTargetNode.tryFold(GraphUtil.originalValue(callSite), b.getMetaAccess(), b.getAssumptions()); if (folded != null) { b.addPush(JavaKind.Object, folded); } else { b.addPush(JavaKind.Object, new CallSiteTargetNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnStamp(b.getAssumptions()), callSite)); } return true; } @Override public boolean inlineOnly() { return true; } }; plugins.register(plugin, ConstantCallSite.class, "getTarget", Receiver.class); plugins.register(plugin, MutableCallSite.class, "getTarget", Receiver.class); plugins.register(plugin, VolatileCallSite.class, "getTarget", Receiver.class); }
public static CallSite bsm_op(Lookup lookup, String name, MethodType methodType, Linker linker) { //System.out.println("link op " + name + methodType); MethodHandle[] mhs = Ops.OP_MAP.get(name); if (mhs == null) { throw new UnsupportedOperationException(name + methodType); } MethodHandle target; if (mhs[0].type() == methodType) { target = mhs[0]; } else { target = mhs[1]; if (target.type().returnType() != methodType.returnType()) { target = MethodHandles.filterReturnValue(target, checkTypeAndConvert(methodType.returnType())); } target = target.asType(methodType); } return new ConstantCallSite(target); }
public CallSite getCallSite(String name, MethodType methodType) { // try built-ins first if (name.equals("print")) { MethodHandle mh; try { mh = MethodHandles.publicLookup().findVirtual(PrintStream.class, "println", MethodType.methodType(void.class, methodType.parameterType(0))); } catch (NoSuchMethodException | IllegalAccessException e) { throw new AssertionError(e); } mh = mh.bindTo(System.out); return new ConstantCallSite(mh.asType(mh.type().changeReturnType(methodType.returnType()))); } Function function = functionMap.get(name); if (function == null || function.fn.parameters().size() != methodType.parameterCount()) { throw new IllegalStateException("no function matching " + name + methodType + " found"); } return function.createCallSite(this, name, methodType); }
/** * Bootstrap method called called in a deoptimisation path when a return value * doesn't fit in the return type. * * @param lookup the lookup object. * @param name the name of the method * @param methodType always (Object)OptimisiticError * @param deoptRet the callback to cause to indicate a deopt error. * @param deoptRetCsts the constant arguments of deoptRet * @return a call site * @throws Throwable if an error occurs */ // called by generated code public static CallSite bsm_optimistic_failure(Lookup lookup, String name, MethodType methodType, MethodHandle deoptRet, Object... deoptRetCsts) throws Throwable { //System.out.println("bsm_optimistic_failure " + name + " with " + deoptRet + "/" + deoptRetCsts.length); // do some checks //if (!deoptRet.type().equals(MethodType.methodType(boolean.class, Object.class))) { // throw new WrongMethodTypeException("invalid deop callback signature ! " + deoptRet.type()); //} // prepend lookup/name/methodType deoptRet = MethodHandles.insertArguments(deoptRet, 0, lookup, name, methodType); // bundle deoptRet constant arguments with deoptRet if necessary if (deoptRetCsts.length != 0) { deoptRet = MethodHandles.insertArguments(deoptRet, 1, deoptRetCsts); } return new ConstantCallSite( MethodHandles.filterReturnValue(OPTIMISTIC_ERROR_VALUE, deoptCallback(MethodHandles.identity(Object.class), deoptRet))); }
/** * Reduce by functional support for int arrays. * @param array array of items to reduce by * @param object object that contains the reduce by function * @param <T> the type of object * @return the final reduction */ public static <T> long reduceBy( final long[] array, T object ) { if (object.getClass().isAnonymousClass()) { return reduceByR(array, object ); } try { ConstantCallSite callSite = Invoker.invokeReducerLongIntReturnLongMethodHandle(object); MethodHandle methodHandle = callSite.dynamicInvoker(); try { long sum = 0; for ( long v : array ) { sum = (long) methodHandle.invokeExact( sum, v ); } return sum; } catch (Throwable throwable) { return handle(Long.class, throwable, "Unable to perform reduceBy"); } } catch (Exception ex) { return reduceByR(array, object); } }
/** * Reduce by functional support for int arrays. * @param array array of items to reduce by * @param object object that contains the reduce by function * @param <T> the type of object * @return the final reduction */ public static <T> double reduceBy( final float[] array, T object ) { if (object.getClass().isAnonymousClass()) { return reduceByR(array, object ); } try { ConstantCallSite callSite = Invoker.invokeReducerLongIntReturnLongMethodHandle(object); MethodHandle methodHandle = callSite.dynamicInvoker(); try { double sum = 0; for ( float v : array ) { sum = (double) methodHandle.invokeExact( sum, v ); } return sum; } catch (Throwable throwable) { return Exceptions.handle(Long.class, throwable, "Unable to perform reduceBy"); } } catch (Exception ex) { return reduceByR(array, object); } }
/** * Reduce by functional support for int arrays. * @param array array of items to reduce by * @param object object that contains the reduce by function * @param <T> the type of object * @return the final reduction */ public static <T> long reduceBy( final int[] array, T object ) { if (object.getClass().isAnonymousClass()) { return reduceByR(array, object ); } try { ConstantCallSite callSite = Invoker.invokeReducerLongIntReturnLongMethodHandle(object); MethodHandle methodHandle = callSite.dynamicInvoker(); try { long sum = 0; for ( int v : array ) { sum = (long) methodHandle.invokeExact( sum, v ); } return sum; } catch (Throwable throwable) { return handle(Long.class, throwable, "Unable to perform reduceBy"); } } catch (Exception ex) { return reduceByR(array, object); } }
/** * Reduce by functional support for int arrays. * @param array array of items to reduce by * @param object object that contains the reduce by function * @param <T> the type of object * @return the final reduction */ public static <T> double reduceBy( final double[] array, T object ) { if (object.getClass().isAnonymousClass()) { return reduceByR(array, object ); } try { ConstantCallSite callSite = Invoker.invokeReducerLongIntReturnLongMethodHandle(object); MethodHandle methodHandle = callSite.dynamicInvoker(); try { double sum = 0; for ( double v : array ) { sum = (double) methodHandle.invokeExact( sum, v ); } return sum; } catch (Throwable throwable) { return Exceptions.handle(Long.class, throwable, "Unable to perform reduceBy"); } } catch (Exception ex) { return reduceByR(array, object); } }
public static CallSite bootstrap(MethodHandles.Lookup callerLookup, String name, MethodType type, long bindingId) { try { ClassLoader classLoader = callerLookup.lookupClass().getClassLoader(); checkArgument(classLoader instanceof DynamicClassLoader, "Expected %s's classloader to be of type %s", callerLookup.lookupClass().getName(), DynamicClassLoader.class.getName()); DynamicClassLoader dynamicClassLoader = (DynamicClassLoader) classLoader; MethodHandle target = dynamicClassLoader.getCallSiteBindings().get(bindingId); checkArgument(target != null, "Binding %s for function %s%s not found", bindingId, name, type.parameterList()); return new ConstantCallSite(target); } catch (Throwable e) { if (e instanceof InterruptedException) { Thread.currentThread().interrupt(); } throw Throwables.propagate(e); } }
@Test public void testCallBinding() throws Throwable { CountDownLatch latch = new CountDownLatch(1); MethodHandle invokee = LOOKUP.findVirtual(CountDownLatch.class, "countDown", MethodType.methodType(Void.TYPE)) .bindTo(latch); MethodHandle boundInvokee = MethodHandles.dropArguments(invokee, 0, Object.class); DynamicInvocationHandler handler = (lookup, name, type, superMethod) -> new ConstantCallSite(boundInvokee.asType(type)); DynamicProxy proxy = DynamicProxy.builder() .withInterfaces(OneMethodInterface.class) .withInvocationHandler(handler) .build(); ((OneMethodInterface)proxy.supplier().get()).foo(); assertEquals(0, latch.getCount()); }
@Test public void whenDefaultImplementationAvailable_itCanBeOverridden() throws Throwable { DynamicInvocationHandler handler = (lookup, name, type, superMethod) -> { MethodHandle h; if (name.equals("foo")) { h = MethodHandles.dropArguments( MethodHandles.constant(String.class, "bar"), 0, Object.class ).asType(type); } else { h = superMethod.asType(type); } return new ConstantCallSite(h); }; I1 obj = (I1) DynamicProxy.builder() .withInvocationHandler(handler) .withInterfaces(I1.class) .build() .constructor() .invoke(); assertEquals("bar", obj.foo()); }
@Test public void whenInterfacesHaveMultipleInheritance_interfaceMethodsAreProxied() throws Throwable { DynamicInvocationHandler handler = (lookup, name, type, supermethod) -> new ConstantCallSite( MethodHandles.dropArguments( MethodHandles.constant(type.returnType(), null), 0, type.parameterList() ) ); IFaceC obj = DynamicProxy.builder() .withInvocationHandler(handler) .withInterfaces(IFaceC.class) .build() .construct(); obj.a(); obj.b(); }
public static CallSite bsm(Lookup lookup, String name, MethodType methodType) { int index = name.indexOf(':'); String protocol = name.substring(0, index); String op = name.substring(index + 1); MethodHandle target; switch(protocol) { case "call": // function call case "binary": // binary op case "instanceof": // instanceof op case "asthrowable": // wrap into an error if needed JSFunction function = (JSFunction)GLOBAL_MAP.get(lookup.lookupClass()).get(op); if (function == null) { // add an error message if the object is not a function throw new Error("fail to do " + protocol + " on " + op); } target = function.getFunctionTarget(genericMethodType(methodType.parameterCount())).asType(methodType); break; case "truth": // give me the truth target = identity(Object.class).asType(methodType(boolean.class, Object.class)); break; default: throw new Error("unknown protocol " + protocol + ":" + op); } return new ConstantCallSite(target.asType(methodType)); }
public static void main(String[] args) { ProxyFactory<IntBinaryOperator> factory = Proxy2.createAnonymousProxyFactory(IntBinaryOperator.class, new Class<?>[] { IntBinaryOperator.class }, new ProxyHandler.Default() { @Override public CallSite bootstrap(ProxyContext context) throws Throwable { MethodHandle target = methodBuilder(context.type()) .dropFirst() .before(b -> b .dropFirst() .unreflect(publicLookup(), Intercept.class.getMethod("intercept", int.class, int.class))) .unreflect(publicLookup(), context.method()); return new ConstantCallSite(target); } }); //IntBinaryOperator op = (a, b) -> a + b; IntBinaryOperator op = (a, b) -> { throw null; }; IntBinaryOperator op2 = factory.create(op); System.out.println(op2.applyAsInt(1, 2)); }
public static void main(String[] args) { ProxyFactory<Delegation> factory = Proxy2.createAnonymousProxyFactory(Delegation.class, new Class<?>[] { PrintStream.class }, new ProxyHandler.Default() { @Override public CallSite bootstrap(ProxyContext context) throws Throwable { MethodHandle target = methodBuilder(context.type()) .dropFirst() .unreflect(publicLookup(), PrintStream.class.getMethod("println", String.class)); return new ConstantCallSite(target); } }); Delegation hello = factory.create(System.out); hello.println("hello proxy2"); }
public static void main(String[] args) { ProxyFactory<Print> factory = Proxy2.createAnonymousProxyFactory(Print.class, new ProxyHandler.Default() { @Override public CallSite bootstrap(ProxyContext context) throws Throwable { MethodHandle target = methodBuilder(context.type()) .dropFirst() .insertAt(0, PrintStream.class, System.out) .unreflect(publicLookup(), PrintStream.class.getMethod("println", String.class)); return new ConstantCallSite(target); } }); Print hello = factory.create(); hello.println("hello proxy2"); }
public static void main(String[] args) { ProxyFactory<IntBinaryOperator> factory = Proxy2.createAnonymousProxyFactory(IntBinaryOperator.class, new Class<?>[] { IntBinaryOperator.class }, new ProxyHandler.Default() { @Override public CallSite bootstrap(ProxyContext context) throws Throwable { MethodHandle target = methodBuilder(context.type()) .dropFirst() .unreflect(publicLookup(), context.method()); return new ConstantCallSite(target); } }); IntBinaryOperator op = (a, b) -> a + b; IntBinaryOperator op2 = factory.create(op); System.out.println(op2.applyAsInt(1, 2)); }
public static void main(String[] args) { ProxyFactory<Runnable> factory = Proxy2.createAnonymousProxyFactory(Runnable.class, new ProxyHandler.Default() { @Override public CallSite bootstrap(ProxyContext context) throws Throwable { return new ConstantCallSite( dropArguments( insertArguments( publicLookup().findVirtual(PrintStream.class, "println", methodType(void.class, String.class)), 0, System.out, "hello proxy"), 0, Object.class)); } }); Runnable runnable = factory.create(); runnable.run(); factory = null; runnable = null; System.gc(); // should unload the proxy class }
public static void main(String[] args) { ProxyFactory<IntBinaryOperator> factory = Proxy2.createAnonymousProxyFactory(IntBinaryOperator.class, new Class<?>[] { IntBinaryOperator.class }, new ProxyHandler.Default() { @Override public CallSite bootstrap(ProxyContext context) throws Throwable { MethodHandle target = methodBuilder(context.type()) .dropFirst() .before(b -> b .dropFirst() .boxAll() .unreflect(publicLookup(), Intercept2.class.getMethod("intercept", Object[].class))) .unreflect(publicLookup(), context.method()); return new ConstantCallSite(target); } }); IntBinaryOperator op = (a, b) -> a + b; IntBinaryOperator op2 = factory.create(op); System.out.println(op2.applyAsInt(1, 2)); }
@Override protected MethodHandle computeValue(Class<?> type) { Lookup lookup = lookup(); return Proxy2.createAnonymousProxyFactory(publicLookup(), methodType(type), new ProxyHandler.Default() { @Override public CallSite bootstrap(ProxyContext context) throws Throwable { Method method = context.method(); switch(method.getName()) { case "create": MethodHandle target = methodBuilder(context.type()) .dropFirst() .insertAt(0, ClassValue.class, beanFactories) .insertAt(1, Class.class, method.getReturnType()) .convertTo(Object.class, ClassValue.class, Class.class) .unreflect(lookup, ORMapper.class.getDeclaredMethod("newBean", ClassValue.class, Class.class)); return new ConstantCallSite(target); default: throw new NoSuchMethodError(method.toString()); } } }); }
public static void main(String[] args) { ProxyFactory<Hello> factory = Proxy2.createAnonymousProxyFactory(Hello.class, new ProxyHandler.Default() { @Override public CallSite bootstrap(ProxyContext context) throws Throwable { System.out.println("bootstrap method " + context.method()); System.out.println("bootstrap type " + context.type()); MethodHandle target = methodBuilder(context.type()) .dropFirst() .unreflect(publicLookup(), String.class.getMethod("concat", String.class)); return new ConstantCallSite(target); } }); Hello simple = factory.create(); System.out.println(simple.message("hello ", "proxy")); System.out.println(simple.message("hello ", "proxy 2")); }
@MethodInfo(hidden=true) public static CallSite bsm_symbol(Lookup lookup, String name, @SuppressWarnings("unused")MethodType mtype, String symbol) { ScriptClassLoader classLoader = (ScriptClassLoader)lookup.lookupClass().getClassLoader(); Script script = classLoader.getScript(); Object constant = script.resolveKlass(symbol); if (constant == null) { if (!name.equals("symbolOrString")) { throw new BootstrapMethodError("unknown local variable " + symbol); } constant = symbol; } //System.out.println("resolved symbol " + symbol + " as " + constant.getClass()); return new ConstantCallSite(MethodHandles.constant(Object.class, constant)); }
@MethodInfo(hidden=true) public static CallSite bsm_lambda(Lookup lookup, @SuppressWarnings("unused") String name, MethodType type, int constantIndex) { ScriptClassLoader classLoader = (ScriptClassLoader)lookup.lookupClass().getClassLoader(); Script script = classLoader.getScript(); ProtoFun protoFun = (ProtoFun)script.dictionary.getConstantAt(constantIndex); List<String> freeVars = protoFun.freeVars; Lambda lambda = protoFun.lambda; List<String> parameters = lambda.getParameters().stream().map(Parameter::getName).collect(Collectors.toList()); // no free variables, always return the same function if (freeVars.isEmpty()) { Function function = Function.createFromLambda(script, freeVars, parameters, lambda); return new ConstantCallSite(MethodHandles.constant(Object.class, function)); } BoundInfo boundInfo = new BoundInfo(script, freeVars, parameters, lambda); return new ConstantCallSite(BOUND_FUNCTION.bindTo(boundInfo).asCollector(Object[].class, type.parameterCount())); }
@NotNull CallSite bootstrap(@NotNull MethodHandles.Lookup caller, @NotNull MethodType type, @NotNull String targetMethodName, @NotNull String targetMethodDescriptor, @NotNull int parameterIndex, @NotNull String parameterName) { //assert type.returnType() == void.class; //assert type.parameterCount() == 1; //assert parameterIndex >= -1; MethodType targetType = MethodType.fromMethodDescriptorString(targetMethodDescriptor, caller.lookupClass().getClassLoader()); MethodGuards guards = callSiteCache.get(new MethodPointer(targetMethodName, targetType)); if ( guards == null ) { return new ConstantCallSite(Indy.nopHandle(type.parameterType(0))); //throw new GuardsInternalError("Guards requested for non-guarded method " + Diagnostics.toString(caller.lookupClass(), name, guardedMethodType)); } else { return guards.getCallSite(parameterIndex, parameterName); } }
/** * Returns the native call {@code CallSite} object. * * @param caller * the caller lookup object * @param name * the native call name * @param type * the native call type * @return the native call {@code CallSite} object */ public static CallSite bootstrapDynamic(MethodHandles.Lookup caller, String name, MethodType type) { MethodHandle target; try { if (!name.startsWith("native:")) { throw new IllegalArgumentException(); } String methodName = name.substring("native:".length()); MethodHandle mh = nativeMethods.computeIfAbsent(methodName, NativeCalls::getNativeMethodHandle); if (mh == null) { return createRuntimeCallSite(methodName, type); } target = adaptMethodHandle(methodName, type, mh); } catch (IllegalArgumentException e) { target = invalidCallHandle(name, type); } return new ConstantCallSite(target); }
public static CallSite bsmLookupStaticWithExtraArgs( MethodHandles.Lookup caller, String name, MethodType type, int i, long l, float f, double d) throws NoSuchMethodException, IllegalAccessException { System.out.println(i); System.out.println(l); System.out.println(f); System.out.println(d); final MethodHandles.Lookup lookup = MethodHandles.lookup(); final MethodHandle targetMH = lookup.findStatic(lookup.lookupClass(), name, type); return new ConstantCallSite(targetMH.asType(type)); }
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); }
public static CallSite bsmCreateCallCallingtargetMethodTest7( 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( J.class, "targetMethodTest7", MethodType.methodType(void.class)); return new ConstantCallSite(targetMH); }
public static CallSite bsmCreateCallCallingtargetMethodTest8( 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( J.class, "targetMethodTest8", MethodType.methodType(void.class)); return new ConstantCallSite(targetMH); }
public static CallSite bsmCreateCallCallingtargetMethodTest9( 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( InvokeCustom.class, "targetMethodTest9", MethodType.methodType(void.class)); return new ConstantCallSite(targetMH); }
public static CallSite bsmCreateCallCallingtargetMethodTest10( 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( InvokeCustom.class, "targetMethodTest10", MethodType.methodType(void.class)); return new ConstantCallSite(targetMH); }
public static String testCallSiteGetTargetSnippet(int i) throws Exception { ConstantCallSite site; MethodHandles.Lookup lookup = MethodHandles.lookup(); switch (i) { case 1: site = GraalDirectives.opaque(new ConstantCallSite(lookup.findVirtual(String.class, "replace", MethodType.methodType(String.class, char.class, char.class)))); break; default: site = GraalDirectives.opaque(new ConstantCallSite(lookup.findStatic(java.util.Arrays.class, "asList", MethodType.methodType(java.util.List.class, Object[].class)))); } return site.getTarget().toString(); }
public JavaConstant getCallSiteTarget(Assumptions assumptions) { if (object instanceof CallSite) { CallSite callSite = (CallSite) object; MethodHandle target = callSite.getTarget(); if (!(callSite instanceof ConstantCallSite)) { if (assumptions == null) { return null; } assumptions.record(new Assumptions.CallSiteTargetValue(callSite, target)); } return HotSpotObjectConstantImpl.forObject(target); } return null; }
public static CallSite getCallSite() { try { MethodHandle mh = MethodHandles.lookup().findStatic( BootstrapMethodErrorTest.class, "target", MethodType.methodType(Object.class, Object.class)); return new ConstantCallSite(mh); } catch (Exception e) { throw new RuntimeException(e); } }
public static void main(String[] args) throws ReflectiveOperationException { // Objects test(new Object()); test("TEST"); test(new VMAnonymousClasses()); test(null); // Class test(String.class); // Arrays test(new boolean[0]); test(new byte[0]); test(new char[0]); test(new short[0]); test(new int[0]); test(new long[0]); test(new float[0]); test(new double[0]); test(new Object[0]); // Multi-dimensional arrays test(new byte[0][0]); test(new Object[0][0]); // MethodHandle-related MethodType mt = MethodType.methodType(void.class, String[].class); MethodHandle mh = MethodHandles.lookup().findStatic(VMAnonymousClasses.class, "main", mt); test(mt); test(mh); test(new ConstantCallSite(mh)); test(new MutableCallSite(MethodType.methodType(void.class))); test(new VolatileCallSite(MethodType.methodType(void.class))); System.out.println("TEST PASSED"); }