Java Code Examples for java.lang.invoke.MethodHandles#foldArguments()

The following examples show how to use java.lang.invoke.MethodHandles#foldArguments() . You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: PermuteArgsReturnVoidTest.java    From openjdk-jdk8u with GNU General Public License v2.0 6 votes vote down vote up
@Test
public void testReturnOnStack() throws Throwable {
    MethodHandles.Lookup l = MethodHandles.lookup();

    MethodHandle consumeIdentity = l.findStatic(
            PermuteArgsReturnVoidTest.class, "consumeIdentity",
            MethodType.methodType(String.class, String.class, int.class, int.class));
    MethodHandle consumeVoid = l.findStatic(
            PermuteArgsReturnVoidTest.class, "consumeVoid",
            MethodType.methodType(void.class, String.class, int.class, int.class));

    MethodHandle f = MethodHandles.foldArguments(consumeIdentity, consumeVoid);

    MethodHandle p = MethodHandles.permuteArguments(f, MethodType.methodType(String.class, String.class, int.class, int.class), 0, 2, 1);

    String s = (String) p.invoke("IN", 0, 0);
    Assert.assertEquals(s.getClass(), String.class);
    Assert.assertEquals(s, "IN");
}
 
Example 2
Source File: PermuteArgsReturnVoidTest.java    From dragonwell8_jdk with GNU General Public License v2.0 6 votes vote down vote up
@Test
public void testReturnOnStack() throws Throwable {
    MethodHandles.Lookup l = MethodHandles.lookup();

    MethodHandle consumeIdentity = l.findStatic(
            PermuteArgsReturnVoidTest.class, "consumeIdentity",
            MethodType.methodType(String.class, String.class, int.class, int.class));
    MethodHandle consumeVoid = l.findStatic(
            PermuteArgsReturnVoidTest.class, "consumeVoid",
            MethodType.methodType(void.class, String.class, int.class, int.class));

    MethodHandle f = MethodHandles.foldArguments(consumeIdentity, consumeVoid);

    MethodHandle p = MethodHandles.permuteArguments(f, MethodType.methodType(String.class, String.class, int.class, int.class), 0, 2, 1);

    String s = (String) p.invoke("IN", 0, 0);
    Assert.assertEquals(s.getClass(), String.class);
    Assert.assertEquals(s, "IN");
}
 
Example 3
Source File: PermuteArgsReturnVoidTest.java    From openjdk-jdk8u-backup with GNU General Public License v2.0 6 votes vote down vote up
@Test
public void testReturnFromArg() throws Throwable {
    MethodHandles.Lookup l = MethodHandles.lookup();

    MethodHandle consumeIdentity = dropArguments(
            identity(String.class), 1, int.class, int.class);
    MethodHandle consumeVoid = l.findStatic(
            PermuteArgsReturnVoidTest.class, "consumeVoid",
            MethodType.methodType(void.class, String.class, int.class, int.class));

    MethodHandle f = MethodHandles.foldArguments(consumeIdentity, consumeVoid);

    MethodHandle p = MethodHandles.permuteArguments(f, MethodType.methodType(String.class, String.class, int.class, int.class), 0, 2, 1);

    String s = (String) p.invoke("IN", 0, 0);
    Assert.assertEquals(s.getClass(), String.class);
    Assert.assertEquals(s, "IN");
}
 
Example 4
Source File: FoldTest.java    From openjdk-jdk9 with GNU General Public License v2.0 5 votes vote down vote up
@Test
public static void testFold0b() throws Throwable {
    // test foldArguments equivalence with multiple types
    MethodHandle fold = MethodHandles.foldArguments(Fold.MH_str, 0, Fold.MH_comb);
    assertEquals(Fold.MT_folded2, fold.type());
    assertEquals(23, (int) fold.invoke("true", true, 23));
}
 
Example 5
Source File: ChainedCallSite.java    From nashorn with GNU General Public License v2.0 5 votes vote down vote up
/**
 * Creates a method that rebuilds our call chain, pruning it of any invalidated switchpoints, and then invokes that
 * chain.
 * @param relink the ultimate fallback for the chain (the {@code DynamicLinker}'s relink).
 * @return a method handle for prune-and-invoke
 */
private MethodHandle makePruneAndInvokeMethod(MethodHandle relink) {
    // Bind prune to (this, relink)
    final MethodHandle boundPrune = MethodHandles.insertArguments(PRUNE, 0, this, relink);
    // Make it ignore all incoming arguments
    final MethodHandle ignoreArgsPrune = MethodHandles.dropArguments(boundPrune, 0, type().parameterList());
    // Invoke prune, then invoke the call site target with original arguments
    return MethodHandles.foldArguments(MethodHandles.exactInvoker(type()), ignoreArgsPrune);
}
 
Example 6
Source File: ChainedCallSite.java    From hottub with GNU General Public License v2.0 5 votes vote down vote up
/**
 * Creates a method that rebuilds our call chain, pruning it of any invalidated switchpoints, and then invokes that
 * chain.
 * @param relink the ultimate fallback for the chain (the {@code DynamicLinker}'s relink).
 * @return a method handle for prune-and-invoke
 */
private MethodHandle makePruneAndInvokeMethod(final MethodHandle relink, final MethodHandle prune) {
    // Bind prune to (this, relink)
    final MethodHandle boundPrune = MethodHandles.insertArguments(prune, 0, this, relink);
    // Make it ignore all incoming arguments
    final MethodHandle ignoreArgsPrune = MethodHandles.dropArguments(boundPrune, 0, type().parameterList());
    // Invoke prune, then invoke the call site target with original arguments
    return MethodHandles.foldArguments(MethodHandles.exactInvoker(type()), ignoreArgsPrune);
}
 
Example 7
Source File: DynamicLinker.java    From openjdk-jdk8u-backup with GNU General Public License v2.0 5 votes vote down vote up
private MethodHandle createRelinkAndInvokeMethod(final RelinkableCallSite callSite, final int relinkCount) {
    // Make a bound MH of invoke() for this linker and call site
    final MethodHandle boundRelinker = MethodHandles.insertArguments(RELINK, 0, this, callSite, Integer.valueOf(
            relinkCount));
    // Make a MH that gathers all arguments to the invocation into an Object[]
    final MethodType type = callSite.getDescriptor().getMethodType();
    final MethodHandle collectingRelinker = boundRelinker.asCollector(Object[].class, type.parameterCount());
    return MethodHandles.foldArguments(MethodHandles.exactInvoker(type), collectingRelinker.asType(
            type.changeReturnType(MethodHandle.class)));
}
 
Example 8
Source File: DynamicLinker.java    From openjdk-8 with GNU General Public License v2.0 5 votes vote down vote up
private MethodHandle createRelinkAndInvokeMethod(final RelinkableCallSite callSite, int relinkCount) {
    // Make a bound MH of invoke() for this linker and call site
    final MethodHandle boundRelinker = MethodHandles.insertArguments(RELINK, 0, this, callSite, Integer.valueOf(
            relinkCount));
    // Make a MH that gathers all arguments to the invocation into an Object[]
    final MethodType type = callSite.getDescriptor().getMethodType();
    final MethodHandle collectingRelinker = boundRelinker.asCollector(Object[].class, type.parameterCount());
    return MethodHandles.foldArguments(MethodHandles.exactInvoker(type), collectingRelinker.asType(
            type.changeReturnType(MethodHandle.class)));
}
 
Example 9
Source File: FoldTest.java    From openjdk-jdk9 with GNU General Public License v2.0 5 votes vote down vote up
@Test
public static void testFold1a() throws Throwable {
    // test foldArguments for folding position 1
    MethodHandle fold = MethodHandles.foldArguments(Fold.MH_multer, 1, Fold.MH_adder1);
    assertEquals(Fold.MT_folded1, fold.type());
    assertEquals(540, (int) fold.invoke(3, 4, 5));
}
 
Example 10
Source File: ChainedCallSite.java    From openjdk-8-source with GNU General Public License v2.0 5 votes vote down vote up
/**
 * Creates a method that rebuilds our call chain, pruning it of any invalidated switchpoints, and then invokes that
 * chain.
 * @param relink the ultimate fallback for the chain (the {@code DynamicLinker}'s relink).
 * @return a method handle for prune-and-invoke
 */
private MethodHandle makePruneAndInvokeMethod(MethodHandle relink) {
    // Bind prune to (this, relink)
    final MethodHandle boundPrune = MethodHandles.insertArguments(PRUNE, 0, this, relink);
    // Make it ignore all incoming arguments
    final MethodHandle ignoreArgsPrune = MethodHandles.dropArguments(boundPrune, 0, type().parameterList());
    // Invoke prune, then invoke the call site target with original arguments
    return MethodHandles.foldArguments(MethodHandles.exactInvoker(type()), ignoreArgsPrune);
}
 
Example 11
Source File: DynamicLinker.java    From nashorn with GNU General Public License v2.0 5 votes vote down vote up
private MethodHandle createRelinkAndInvokeMethod(final RelinkableCallSite callSite, int relinkCount) {
    // Make a bound MH of invoke() for this linker and call site
    final MethodHandle boundRelinker = MethodHandles.insertArguments(RELINK, 0, this, callSite, Integer.valueOf(
            relinkCount));
    // Make a MH that gathers all arguments to the invocation into an Object[]
    final MethodType type = callSite.getDescriptor().getMethodType();
    final MethodHandle collectingRelinker = boundRelinker.asCollector(Object[].class, type.parameterCount());
    return MethodHandles.foldArguments(MethodHandles.exactInvoker(type), collectingRelinker.asType(
            type.changeReturnType(MethodHandle.class)));
}
 
Example 12
Source File: MethodHandleUtil.java    From presto with Apache License 2.0 5 votes vote down vote up
/**
 * @param f (U, V)R
 * @param g (S1, S2, ..., Sm)U
 * @param h (T1, T2, ..., Tn)V
 * @return (S1, S2, ..., Sm, T1, T2, ..., Tn)R
 */
public static MethodHandle compose(MethodHandle f, MethodHandle g, MethodHandle h)
{
    if (f.type().parameterCount() != 2) {
        throw new IllegalArgumentException(format("f.parameterCount != 2. f: %s", f.type()));
    }
    if (f.type().parameterType(0) != g.type().returnType()) {
        throw new IllegalArgumentException(format("f.parameter(0) != g.return. f: %s  g: %s", f.type(), g.type()));
    }
    if (f.type().parameterType(1) != h.type().returnType()) {
        throw new IllegalArgumentException(format("f.parameter(0) != h.return. f: %s  h: %s", f.type(), h.type()));
    }

    // (V, T1, T2, ..., Tn, U)R
    MethodType typeVTU = f.type().dropParameterTypes(0, 1).appendParameterTypes(h.type().parameterList()).appendParameterTypes(f.type().parameterType(0));
    // Semantics: f => f
    // Type: (U, V)R => (V, T1, T2, ..., Tn, U)R
    MethodHandle fVTU = MethodHandles.permuteArguments(f, typeVTU, h.type().parameterCount() + 1, 0);
    // Semantics: f => fh
    // Type: (V, T1, T2, ..., Tn, U)R => (T1, T2, ..., Tn, U)R
    MethodHandle fhTU = MethodHandles.foldArguments(fVTU, h);

    // reorder: [m+1, m+2, ..., m+n, 0]
    int[] reorder = new int[fhTU.type().parameterCount()];
    for (int i = 0; i < reorder.length - 1; i++) {
        reorder[i] = i + 1 + g.type().parameterCount();
    }
    reorder[reorder.length - 1] = 0;

    // (U, S1, S2, ..., Sm, T1, T2, ..., Tn)R
    MethodType typeUST = f.type().dropParameterTypes(1, 2).appendParameterTypes(g.type().parameterList()).appendParameterTypes(h.type().parameterList());
    // Semantics: f.h => f.h
    // Type: (T1, T2, ..., Tn, U)R => (U, S1, S2, ..., Sm, T1, T2, ..., Tn)R
    MethodHandle fhUST = MethodHandles.permuteArguments(fhTU, typeUST, reorder);

    // Semantics: fh => fgh
    // Type: (U, S1, S2, ..., Sm, T1, T2, ..., Tn)R => (S1, S2, ..., Sm, T1, T2, ..., Tn)R
    return MethodHandles.foldArguments(fhUST, g);
}
 
Example 13
Source File: MethodHandleUtil.java    From presto with Apache License 2.0 5 votes vote down vote up
/**
 * @param f (U, S1, S2, ..., Sm)R
 * @param g (T1, T2, ..., Tn)U
 * @return (T1, T2, ..., Tn, S1, S2, ..., Sm)R
 */
public static MethodHandle compose(MethodHandle f, MethodHandle g)
{
    if (f.type().parameterType(0) != g.type().returnType()) {
        throw new IllegalArgumentException(format("f.parameter(0) != g.return(). f: %s  g: %s", f.type(), g.type()));
    }
    // Semantics: f => f
    // Type: (U, S1, S2, ..., Sn)R => (U, T1, T2, ..., Tm, S1, S2, ..., Sn)R
    MethodHandle fUTS = MethodHandles.dropArguments(f, 1, g.type().parameterList());
    // Semantics: f => fg
    // Type: (U, T1, T2, ..., Tm, S1, S2, ..., Sn)R => (T1, T2, ..., Tm, S1, S2, ..., Sn)R
    return MethodHandles.foldArguments(fUTS, g);
}
 
Example 14
Source File: MethodHandleFactory.java    From openjdk-jdk8u with GNU General Public License v2.0 4 votes vote down vote up
@Override
public MethodHandle foldArguments(final MethodHandle target, final MethodHandle combiner) {
    final MethodHandle mh = MethodHandles.foldArguments(target, combiner);
    return debug(mh, "foldArguments", target, combiner);
}
 
Example 15
Source File: MethodHandleFactory.java    From TencentKona-8 with GNU General Public License v2.0 4 votes vote down vote up
@Override
public MethodHandle foldArguments(final MethodHandle target, final MethodHandle combiner) {
    final MethodHandle mh = MethodHandles.foldArguments(target, combiner);
    return debug(mh, "foldArguments", target, combiner);
}
 
Example 16
Source File: JavaSuperAdapterLinker.java    From nashorn with GNU General Public License v2.0 4 votes vote down vote up
@Override
public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices)
        throws Exception {
    final Object objSuperAdapter = linkRequest.getReceiver();
    if(!(objSuperAdapter instanceof JavaSuperAdapter)) {
        return null;
    }

    final CallSiteDescriptor descriptor = linkRequest.getCallSiteDescriptor();
    if(!CallSiteDescriptorFactory.tokenizeOperators(descriptor).contains(GET_METHOD)) {
        // We only handle getMethod
        return null;
    }

    final Object adapter = ((JavaSuperAdapter)objSuperAdapter).getAdapter();

    // Replace argument (javaSuperAdapter, ...) => (adapter, ...) when delegating to BeansLinker
    final Object[] args = linkRequest.getArguments();
    args[0] = adapter;

    // Use R(T0, ...) => R(adapter.class, ...) call site type when delegating to BeansLinker.
    final MethodType type = descriptor.getMethodType();
    final Class<?> adapterClass = adapter.getClass();
    final boolean hasFixedName = descriptor.getNameTokenCount() > 2;
    final String opName = hasFixedName ? (DYN_GET_METHOD_FIXED + descriptor.getNameToken(
            CallSiteDescriptor.NAME_OPERAND)) : DYN_GET_METHOD;

    final CallSiteDescriptor newDescriptor = NashornCallSiteDescriptor.get(descriptor.getLookup(), opName,
            type.changeParameterType(0, adapterClass), 0);

    // Delegate to BeansLinker
    final GuardedInvocation guardedInv = BeansLinker.getLinkerForClass(adapterClass).getGuardedInvocation(
            linkRequest.replaceArguments(newDescriptor, args), linkerServices);

    final MethodHandle guard = IS_ADAPTER_OF_CLASS.bindTo(adapterClass);
    if(guardedInv == null) {
        // Short circuit the lookup here for non-existent methods by linking an empty getter. If we just returned
        // null instead, BeansLinker would find final methods on the JavaSuperAdapter instead: getClass() and
        // wait().
        return new GuardedInvocation(MethodHandles.dropArguments(EMPTY_GETTER, 1,type.parameterList().subList(1,
                type.parameterCount())), guard).asType(descriptor);
    }

    final MethodHandle invocation = guardedInv.getInvocation();
    final MethodType invType = invocation.type();
    // For invocation typed R(T0, ...) create a dynamic method binder of type R(R, T0)
    final MethodHandle typedBinder = BIND_DYNAMIC_METHOD.asType(MethodType.methodType(invType.returnType(),
            invType.returnType(), invType.parameterType(0)));
    // For invocation typed R(T0, T1, ...) create a dynamic method binder of type R(R, T0, T1, ...)
    final MethodHandle droppingBinder = MethodHandles.dropArguments(typedBinder, 2,
            invType.parameterList().subList(1, invType.parameterCount()));
    // Finally, fold the invocation into the binder to produce a method handle that will bind every returned
    // DynamicMethod object from dyn:getMethod calls to the actual receiver
    // R(R(T0, T1, ...), T0, T1, ...)
    final MethodHandle bindingInvocation = MethodHandles.foldArguments(droppingBinder, invocation);

    final MethodHandle typedGetAdapter = asFilterType(GET_ADAPTER, 0, invType, type);
    final MethodHandle adaptedInvocation;
    if(hasFixedName) {
        adaptedInvocation = MethodHandles.filterArguments(bindingInvocation, 0, typedGetAdapter);
    } else {
        // Add a filter that'll prepend "super$" to each name passed to the variable-name "dyn:getMethod".
        final MethodHandle typedAddPrefix = asFilterType(ADD_PREFIX_TO_METHOD_NAME, 1, invType, type);
        adaptedInvocation = MethodHandles.filterArguments(bindingInvocation, 0, typedGetAdapter, typedAddPrefix);
    }

    return guardedInv.replaceMethods(adaptedInvocation, guard).asType(descriptor);
}
 
Example 17
Source File: AbstractJavaLinker.java    From openjdk-8 with GNU General Public License v2.0 4 votes vote down vote up
private GuardedInvocationComponent getPropertySetter(CallSiteDescriptor callSiteDescriptor,
        LinkerServices linkerServices, List<String> operations) throws Exception {
    final MethodType type = callSiteDescriptor.getMethodType();
    switch(callSiteDescriptor.getNameTokenCount()) {
        case 2: {
            // Must have three arguments: target object, property name, and property value.
            assertParameterCount(callSiteDescriptor, 3);

            // What's below is basically:
            //   foldArguments(guardWithTest(isNotNull, invoke, null|nextComponent.invocation),
            //     get_setter_handle(type, linkerServices))
            // only with a bunch of method signature adjustments. Basically, retrieve method setter
            // MethodHandle; if it is non-null, invoke it, otherwise either return null, or delegate to next
            // component's invocation.

            // Call site type is "ret_type(object_type,property_name_type,property_value_type)", which we'll
            // abbreviate to R(O, N, V) going forward.
            // We want setters that conform to "R(O, V)"
            final MethodType setterType = type.dropParameterTypes(1, 2);
            // Bind property setter handle to the expected setter type and linker services. Type is
            // MethodHandle(Object, String, Object)
            final MethodHandle boundGetter = MethodHandles.insertArguments(getPropertySetterHandle, 0,
                    CallSiteDescriptorFactory.dropParameterTypes(callSiteDescriptor, 1, 2), linkerServices);

            // Cast getter to MethodHandle(O, N, V)
            final MethodHandle typedGetter = linkerServices.asType(boundGetter, type.changeReturnType(
                    MethodHandle.class));

            // Handle to invoke the setter R(MethodHandle, O, V)
            final MethodHandle invokeHandle = MethodHandles.exactInvoker(setterType);
            // Handle to invoke the setter, dropping unnecessary fold arguments R(MethodHandle, O, N, V)
            final MethodHandle invokeHandleFolded = MethodHandles.dropArguments(invokeHandle, 2, type.parameterType(
                    1));
            final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor,
                    linkerServices, operations);

            final MethodHandle fallbackFolded;
            if(nextComponent == null) {
                // Object(MethodHandle)->R(MethodHandle, O, N, V); returns constant null
                fallbackFolded = MethodHandles.dropArguments(CONSTANT_NULL_DROP_METHOD_HANDLE, 1,
                        type.parameterList()).asType(type.insertParameterTypes(0, MethodHandle.class));
            } else {
                // R(O, N, V)->R(MethodHandle, O, N, V); adapts the next component's invocation to drop the
                // extra argument resulting from fold
                fallbackFolded = MethodHandles.dropArguments(nextComponent.getGuardedInvocation().getInvocation(),
                        0, MethodHandle.class);
            }

            // fold(R(MethodHandle, O, N, V), MethodHandle(O, N, V))
            final MethodHandle compositeSetter = MethodHandles.foldArguments(MethodHandles.guardWithTest(
                        IS_METHOD_HANDLE_NOT_NULL, invokeHandleFolded, fallbackFolded), typedGetter);
            if(nextComponent == null) {
                return getClassGuardedInvocationComponent(compositeSetter, type);
            }
            return nextComponent.compose(compositeSetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS);
        }
        case 3: {
            // Must have two arguments: target object and property value
            assertParameterCount(callSiteDescriptor, 2);
            final GuardedInvocation gi = createGuardedDynamicMethodInvocation(callSiteDescriptor, linkerServices,
                    callSiteDescriptor.getNameToken(CallSiteDescriptor.NAME_OPERAND), propertySetters);
            // If we have a property setter with this name, this composite operation will always stop here
            if(gi != null) {
                return new GuardedInvocationComponent(gi, clazz, ValidationType.EXACT_CLASS);
            }
            // If we don't have a property setter with this name, always fall back to the next operation in the
            // composite (if any)
            return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, operations);
        }
        default: {
            // More than two name components; don't know what to do with it.
            return null;
        }
    }
}
 
Example 18
Source File: JavaSuperAdapterLinker.java    From openjdk-8-source with GNU General Public License v2.0 4 votes vote down vote up
@Override
public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices)
        throws Exception {
    final Object objSuperAdapter = linkRequest.getReceiver();
    if(!(objSuperAdapter instanceof JavaSuperAdapter)) {
        return null;
    }

    final CallSiteDescriptor descriptor = linkRequest.getCallSiteDescriptor();
    if(!CallSiteDescriptorFactory.tokenizeOperators(descriptor).contains(GET_METHOD)) {
        // We only handle getMethod
        return null;
    }

    final Object adapter = ((JavaSuperAdapter)objSuperAdapter).getAdapter();

    // Replace argument (javaSuperAdapter, ...) => (adapter, ...) when delegating to BeansLinker
    final Object[] args = linkRequest.getArguments();
    args[0] = adapter;

    // Use R(T0, ...) => R(adapter.class, ...) call site type when delegating to BeansLinker.
    final MethodType type = descriptor.getMethodType();
    final Class<?> adapterClass = adapter.getClass();
    final boolean hasFixedName = descriptor.getNameTokenCount() > 2;
    final String opName = hasFixedName ? (DYN_GET_METHOD_FIXED + descriptor.getNameToken(
            CallSiteDescriptor.NAME_OPERAND)) : DYN_GET_METHOD;

    final CallSiteDescriptor newDescriptor = NashornCallSiteDescriptor.get(descriptor.getLookup(), opName,
            type.changeParameterType(0, adapterClass), 0);

    // Delegate to BeansLinker
    final GuardedInvocation guardedInv = NashornBeansLinker.getGuardedInvocation(
            BeansLinker.getLinkerForClass(adapterClass), linkRequest.replaceArguments(newDescriptor, args),
            linkerServices);

    final MethodHandle guard = IS_ADAPTER_OF_CLASS.bindTo(adapterClass);
    if(guardedInv == null) {
        // Short circuit the lookup here for non-existent methods by linking an empty getter. If we just returned
        // null instead, BeansLinker would find final methods on the JavaSuperAdapter instead: getClass() and
        // wait().
        return new GuardedInvocation(MethodHandles.dropArguments(EMPTY_GETTER, 1,type.parameterList().subList(1,
                type.parameterCount())), guard).asType(descriptor);
    }

    final MethodHandle invocation = guardedInv.getInvocation();
    final MethodType invType = invocation.type();
    // For invocation typed R(T0, ...) create a dynamic method binder of type R(R, T0)
    final MethodHandle typedBinder = BIND_DYNAMIC_METHOD.asType(MethodType.methodType(invType.returnType(),
            invType.returnType(), invType.parameterType(0)));
    // For invocation typed R(T0, T1, ...) create a dynamic method binder of type R(R, T0, T1, ...)
    final MethodHandle droppingBinder = MethodHandles.dropArguments(typedBinder, 2,
            invType.parameterList().subList(1, invType.parameterCount()));
    // Finally, fold the invocation into the binder to produce a method handle that will bind every returned
    // DynamicMethod object from dyn:getMethod calls to the actual receiver
    // R(R(T0, T1, ...), T0, T1, ...)
    final MethodHandle bindingInvocation = MethodHandles.foldArguments(droppingBinder, invocation);

    final MethodHandle typedGetAdapter = asFilterType(GET_ADAPTER, 0, invType, type);
    final MethodHandle adaptedInvocation;
    if(hasFixedName) {
        adaptedInvocation = MethodHandles.filterArguments(bindingInvocation, 0, typedGetAdapter);
    } else {
        // Add a filter that'll prepend "super$" to each name passed to the variable-name "dyn:getMethod".
        final MethodHandle typedAddPrefix = asFilterType(ADD_PREFIX_TO_METHOD_NAME, 1, invType, type);
        adaptedInvocation = MethodHandles.filterArguments(bindingInvocation, 0, typedGetAdapter, typedAddPrefix);
    }

    return guardedInv.replaceMethods(adaptedInvocation, guard).asType(descriptor);
}
 
Example 19
Source File: JavaSuperAdapterLinker.java    From openjdk-8 with GNU General Public License v2.0 4 votes vote down vote up
@Override
public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices)
        throws Exception {
    final Object objSuperAdapter = linkRequest.getReceiver();
    if(!(objSuperAdapter instanceof JavaSuperAdapter)) {
        return null;
    }

    final CallSiteDescriptor descriptor = linkRequest.getCallSiteDescriptor();
    if(!CallSiteDescriptorFactory.tokenizeOperators(descriptor).contains(GET_METHOD)) {
        // We only handle getMethod
        return null;
    }

    final Object adapter = ((JavaSuperAdapter)objSuperAdapter).getAdapter();

    // Replace argument (javaSuperAdapter, ...) => (adapter, ...) when delegating to BeansLinker
    final Object[] args = linkRequest.getArguments();
    args[0] = adapter;

    // Use R(T0, ...) => R(adapter.class, ...) call site type when delegating to BeansLinker.
    final MethodType type = descriptor.getMethodType();
    final Class<?> adapterClass = adapter.getClass();
    final boolean hasFixedName = descriptor.getNameTokenCount() > 2;
    final String opName = hasFixedName ? (DYN_GET_METHOD_FIXED + descriptor.getNameToken(
            CallSiteDescriptor.NAME_OPERAND)) : DYN_GET_METHOD;

    final CallSiteDescriptor newDescriptor = NashornCallSiteDescriptor.get(descriptor.getLookup(), opName,
            type.changeParameterType(0, adapterClass), 0);

    // Delegate to BeansLinker
    final GuardedInvocation guardedInv = NashornBeansLinker.getGuardedInvocation(
            BeansLinker.getLinkerForClass(adapterClass), linkRequest.replaceArguments(newDescriptor, args),
            linkerServices);

    final MethodHandle guard = IS_ADAPTER_OF_CLASS.bindTo(adapterClass);
    if(guardedInv == null) {
        // Short circuit the lookup here for non-existent methods by linking an empty getter. If we just returned
        // null instead, BeansLinker would find final methods on the JavaSuperAdapter instead: getClass() and
        // wait().
        return new GuardedInvocation(MethodHandles.dropArguments(EMPTY_GETTER, 1,type.parameterList().subList(1,
                type.parameterCount())), guard).asType(descriptor);
    }

    final MethodHandle invocation = guardedInv.getInvocation();
    final MethodType invType = invocation.type();
    // For invocation typed R(T0, ...) create a dynamic method binder of type R(R, T0)
    final MethodHandle typedBinder = BIND_DYNAMIC_METHOD.asType(MethodType.methodType(invType.returnType(),
            invType.returnType(), invType.parameterType(0)));
    // For invocation typed R(T0, T1, ...) create a dynamic method binder of type R(R, T0, T1, ...)
    final MethodHandle droppingBinder = MethodHandles.dropArguments(typedBinder, 2,
            invType.parameterList().subList(1, invType.parameterCount()));
    // Finally, fold the invocation into the binder to produce a method handle that will bind every returned
    // DynamicMethod object from dyn:getMethod calls to the actual receiver
    // R(R(T0, T1, ...), T0, T1, ...)
    final MethodHandle bindingInvocation = MethodHandles.foldArguments(droppingBinder, invocation);

    final MethodHandle typedGetAdapter = asFilterType(GET_ADAPTER, 0, invType, type);
    final MethodHandle adaptedInvocation;
    if(hasFixedName) {
        adaptedInvocation = MethodHandles.filterArguments(bindingInvocation, 0, typedGetAdapter);
    } else {
        // Add a filter that'll prepend "super$" to each name passed to the variable-name "dyn:getMethod".
        final MethodHandle typedAddPrefix = asFilterType(ADD_PREFIX_TO_METHOD_NAME, 1, invType, type);
        adaptedInvocation = MethodHandles.filterArguments(bindingInvocation, 0, typedGetAdapter, typedAddPrefix);
    }

    return guardedInv.replaceMethods(adaptedInvocation, guard).asType(descriptor);
}
 
Example 20
Source File: AbstractJavaLinker.java    From openjdk-8-source with GNU General Public License v2.0 4 votes vote down vote up
private GuardedInvocationComponent getPropertySetter(CallSiteDescriptor callSiteDescriptor,
        LinkerServices linkerServices, List<String> operations) throws Exception {
    final MethodType type = callSiteDescriptor.getMethodType();
    switch(callSiteDescriptor.getNameTokenCount()) {
        case 2: {
            // Must have three arguments: target object, property name, and property value.
            assertParameterCount(callSiteDescriptor, 3);

            // What's below is basically:
            //   foldArguments(guardWithTest(isNotNull, invoke, null|nextComponent.invocation),
            //     get_setter_handle(type, linkerServices))
            // only with a bunch of method signature adjustments. Basically, retrieve method setter
            // MethodHandle; if it is non-null, invoke it, otherwise either return null, or delegate to next
            // component's invocation.

            // Call site type is "ret_type(object_type,property_name_type,property_value_type)", which we'll
            // abbreviate to R(O, N, V) going forward.
            // We want setters that conform to "R(O, V)"
            final MethodType setterType = type.dropParameterTypes(1, 2);
            // Bind property setter handle to the expected setter type and linker services. Type is
            // MethodHandle(Object, String, Object)
            final MethodHandle boundGetter = MethodHandles.insertArguments(getPropertySetterHandle, 0,
                    CallSiteDescriptorFactory.dropParameterTypes(callSiteDescriptor, 1, 2), linkerServices);

            // Cast getter to MethodHandle(O, N, V)
            final MethodHandle typedGetter = linkerServices.asType(boundGetter, type.changeReturnType(
                    MethodHandle.class));

            // Handle to invoke the setter R(MethodHandle, O, V)
            final MethodHandle invokeHandle = MethodHandles.exactInvoker(setterType);
            // Handle to invoke the setter, dropping unnecessary fold arguments R(MethodHandle, O, N, V)
            final MethodHandle invokeHandleFolded = MethodHandles.dropArguments(invokeHandle, 2, type.parameterType(
                    1));
            final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor,
                    linkerServices, operations);

            final MethodHandle fallbackFolded;
            if(nextComponent == null) {
                // Object(MethodHandle)->R(MethodHandle, O, N, V); returns constant null
                fallbackFolded = MethodHandles.dropArguments(CONSTANT_NULL_DROP_METHOD_HANDLE, 1,
                        type.parameterList()).asType(type.insertParameterTypes(0, MethodHandle.class));
            } else {
                // R(O, N, V)->R(MethodHandle, O, N, V); adapts the next component's invocation to drop the
                // extra argument resulting from fold
                fallbackFolded = MethodHandles.dropArguments(nextComponent.getGuardedInvocation().getInvocation(),
                        0, MethodHandle.class);
            }

            // fold(R(MethodHandle, O, N, V), MethodHandle(O, N, V))
            final MethodHandle compositeSetter = MethodHandles.foldArguments(MethodHandles.guardWithTest(
                        IS_METHOD_HANDLE_NOT_NULL, invokeHandleFolded, fallbackFolded), typedGetter);
            if(nextComponent == null) {
                return getClassGuardedInvocationComponent(compositeSetter, type);
            }
            return nextComponent.compose(compositeSetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS);
        }
        case 3: {
            // Must have two arguments: target object and property value
            assertParameterCount(callSiteDescriptor, 2);
            final GuardedInvocation gi = createGuardedDynamicMethodInvocation(callSiteDescriptor, linkerServices,
                    callSiteDescriptor.getNameToken(CallSiteDescriptor.NAME_OPERAND), propertySetters);
            // If we have a property setter with this name, this composite operation will always stop here
            if(gi != null) {
                return new GuardedInvocationComponent(gi, clazz, ValidationType.EXACT_CLASS);
            }
            // If we don't have a property setter with this name, always fall back to the next operation in the
            // composite (if any)
            return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, operations);
        }
        default: {
            // More than two name components; don't know what to do with it.
            return null;
        }
    }
}