--- old/samples/MissingMethodLinkerExporter.java 2015-12-09 13:17:50.315464300 +0530 +++ /dev/null 2015-12-09 13:17:50.000000000 +0530 @@ -1,190 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; -import java.util.ArrayList; -import java.util.List; -import jdk.dynalink.CallSiteDescriptor; -import jdk.dynalink.CompositeOperation; -import jdk.dynalink.NamedOperation; -import jdk.dynalink.Operation; -import jdk.dynalink.StandardOperation; -import jdk.dynalink.beans.BeansLinker; -import jdk.dynalink.linker.GuardingDynamicLinker; -import jdk.dynalink.linker.GuardingDynamicLinkerExporter; -import jdk.dynalink.linker.GuardedInvocation; -import jdk.dynalink.linker.TypeBasedGuardingDynamicLinker; -import jdk.dynalink.linker.LinkRequest; -import jdk.dynalink.linker.LinkerServices; -import jdk.dynalink.linker.support.Guards; -import jdk.dynalink.linker.support.Lookup; - -/** - * This is a dynalink pluggable linker (see http://openjdk.java.net/jeps/276). - * This linker routes missing methods to Smalltalk-style doesNotUnderstand method. - * Object of any Java class that implements MissingMethodHandler is handled by this linker. - * For any method call, if a matching Java method is found, it is called. If there is no - * method by that name, then MissingMethodHandler.doesNotUnderstand is called. - */ -public final class MissingMethodLinkerExporter extends GuardingDynamicLinkerExporter { - static { - System.out.println("pluggable dynalink missing method linker loaded"); - } - - // represents a MissingMethod - just stores as name and also serves a guard type - public static class MissingMethod { - private final String name; - - public MissingMethod(String name) { - this.name = name; - } - - public String getName() { - return name; - } - } - - // MissingMethodHandler.doesNotUnderstand method - private static final MethodHandle DOES_NOT_UNDERSTAND; - - // type of MissingMethodHandler - but "this" and String args are flipped - private static final MethodType FLIPPED_DOES_NOT_UNDERSTAND_TYPE; - - // "is this a MissingMethod?" guard - private static final MethodHandle IS_MISSING_METHOD; - - // MissingMethod object->it's name filter - private static final MethodHandle MISSING_METHOD_TO_NAME; - - static { - DOES_NOT_UNDERSTAND = Lookup.PUBLIC.findVirtual( - MissingMethodHandler.class, - "doesNotUnderstand", - MethodType.methodType(Object.class, String.class, Object[].class)); - FLIPPED_DOES_NOT_UNDERSTAND_TYPE = - MethodType.methodType(Object.class, String.class, MissingMethodHandler.class, Object[].class); - IS_MISSING_METHOD = Guards.isOfClass(MissingMethod.class, - MethodType.methodType(Boolean.TYPE, Object.class)); - MISSING_METHOD_TO_NAME = Lookup.PUBLIC.findVirtual(MissingMethod.class, - "getName", MethodType.methodType(String.class)); - } - - // locate the first standard operation from the call descriptor - private static StandardOperation getFirstStandardOperation(final CallSiteDescriptor desc) { - final Operation base = NamedOperation.getBaseOperation(desc.getOperation()); - if (base instanceof StandardOperation) { - return (StandardOperation)base; - } else if (base instanceof CompositeOperation) { - final CompositeOperation cop = (CompositeOperation)base; - for(int i = 0; i < cop.getOperationCount(); ++i) { - final Operation op = cop.getOperation(i); - if (op instanceof StandardOperation) { - return (StandardOperation)op; - } - } - } - return null; - } - - @Override - public List get() { - final ArrayList linkers = new ArrayList<>(); - final BeansLinker beansLinker = new BeansLinker(); - linkers.add(new TypeBasedGuardingDynamicLinker() { - // only handles MissingMethodHandler and MissingMethod objects - @Override - public boolean canLinkType(final Class type) { - return - MissingMethodHandler.class.isAssignableFrom(type) || - type == MissingMethod.class; - } - - @Override - public GuardedInvocation getGuardedInvocation(LinkRequest request, - LinkerServices linkerServices) throws Exception { - final Object self = request.getReceiver(); - CallSiteDescriptor desc = request.getCallSiteDescriptor(); - - // any method call is done by two steps. Step (1) GET_METHOD and (2) is CALL - // For step (1), we check if GET_METHOD can succeed by Java linker, if so - // we return that method object. If not, we return a MissingMethod object. - if (self instanceof MissingMethodHandler) { - // Check if this is a named GET_METHOD first. - boolean isGetMethod = getFirstStandardOperation(desc) == StandardOperation.GET_METHOD; - Object name = NamedOperation.getName(desc.getOperation()); - if (isGetMethod && name instanceof String) { - GuardingDynamicLinker javaLinker = beansLinker.getLinkerForClass(self.getClass()); - GuardedInvocation inv; - try { - inv = javaLinker.getGuardedInvocation(request, linkerServices); - } catch (final Throwable th) { - inv = null; - } - - String nameStr = name.toString(); - if (inv == null) { - // use "this" for just guard and drop it -- return a constant Method handle - // that returns a newly created MissingMethod object - MethodHandle mh = MethodHandles.constant(Object.class, new MissingMethod(nameStr)); - inv = new GuardedInvocation( - MethodHandles.dropArguments(mh, 0, Object.class), - Guards.isOfClass(self.getClass(), MethodType.methodType(Boolean.TYPE, Object.class))); - } - - return inv; - } - } else if (self instanceof MissingMethod) { - // This is step (2). We call MissingMethodHandler.doesNotUnderstand here - // Check if this is this a CALL first. - boolean isCall = getFirstStandardOperation(desc) == StandardOperation.CALL; - if (isCall) { - MethodHandle mh = DOES_NOT_UNDERSTAND; - - // flip "this" and method name (String) - mh = MethodHandles.permuteArguments(mh, FLIPPED_DOES_NOT_UNDERSTAND_TYPE, 1, 0, 2); - - // collect rest of the arguments as vararg - mh = mh.asCollector(Object[].class, desc.getMethodType().parameterCount() - 2); - - // convert MissingMethod object to it's name - mh = MethodHandles.filterArguments(mh, 0, MISSING_METHOD_TO_NAME); - return new GuardedInvocation(mh, IS_MISSING_METHOD); - } - } - - return null; - } - }); - return linkers; - } -} --- /dev/null 2015-12-09 13:17:50.000000000 +0530 +++ new/samples/dynalink/MissingMethodLinkerExporter.java 2015-12-09 13:17:49.619424500 +0530 @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.util.ArrayList; +import java.util.List; +import jdk.dynalink.CallSiteDescriptor; +import jdk.dynalink.CompositeOperation; +import jdk.dynalink.NamedOperation; +import jdk.dynalink.Operation; +import jdk.dynalink.StandardOperation; +import jdk.dynalink.beans.BeansLinker; +import jdk.dynalink.linker.GuardingDynamicLinker; +import jdk.dynalink.linker.GuardingDynamicLinkerExporter; +import jdk.dynalink.linker.GuardedInvocation; +import jdk.dynalink.linker.TypeBasedGuardingDynamicLinker; +import jdk.dynalink.linker.LinkRequest; +import jdk.dynalink.linker.LinkerServices; +import jdk.dynalink.linker.support.Guards; +import jdk.dynalink.linker.support.Lookup; + +/** + * This is a dynalink pluggable linker (see http://openjdk.java.net/jeps/276). + * This linker routes missing methods to Smalltalk-style doesNotUnderstand method. + * Object of any Java class that implements MissingMethodHandler is handled by this linker. + * For any method call, if a matching Java method is found, it is called. If there is no + * method by that name, then MissingMethodHandler.doesNotUnderstand is called. + */ +public final class MissingMethodLinkerExporter extends GuardingDynamicLinkerExporter { + static { + System.out.println("pluggable dynalink missing method linker loaded"); + } + + // represents a MissingMethod - just stores as name and also serves a guard type + public static class MissingMethod { + private final String name; + + public MissingMethod(String name) { + this.name = name; + } + + public String getName() { + return name; + } + } + + // MissingMethodHandler.doesNotUnderstand method + private static final MethodHandle DOES_NOT_UNDERSTAND; + + // type of MissingMethodHandler - but "this" and String args are flipped + private static final MethodType FLIPPED_DOES_NOT_UNDERSTAND_TYPE; + + // "is this a MissingMethod?" guard + private static final MethodHandle IS_MISSING_METHOD; + + // MissingMethod object->it's name filter + private static final MethodHandle MISSING_METHOD_TO_NAME; + + static { + DOES_NOT_UNDERSTAND = Lookup.PUBLIC.findVirtual( + MissingMethodHandler.class, + "doesNotUnderstand", + MethodType.methodType(Object.class, String.class, Object[].class)); + FLIPPED_DOES_NOT_UNDERSTAND_TYPE = + MethodType.methodType(Object.class, String.class, MissingMethodHandler.class, Object[].class); + IS_MISSING_METHOD = Guards.isOfClass(MissingMethod.class, + MethodType.methodType(Boolean.TYPE, Object.class)); + MISSING_METHOD_TO_NAME = Lookup.PUBLIC.findVirtual(MissingMethod.class, + "getName", MethodType.methodType(String.class)); + } + + // locate the first standard operation from the call descriptor + private static StandardOperation getFirstStandardOperation(final CallSiteDescriptor desc) { + final Operation base = NamedOperation.getBaseOperation(desc.getOperation()); + if (base instanceof StandardOperation) { + return (StandardOperation)base; + } else if (base instanceof CompositeOperation) { + final CompositeOperation cop = (CompositeOperation)base; + for(int i = 0; i < cop.getOperationCount(); ++i) { + final Operation op = cop.getOperation(i); + if (op instanceof StandardOperation) { + return (StandardOperation)op; + } + } + } + return null; + } + + @Override + public List get() { + final ArrayList linkers = new ArrayList<>(); + final BeansLinker beansLinker = new BeansLinker(); + linkers.add(new TypeBasedGuardingDynamicLinker() { + // only handles MissingMethodHandler and MissingMethod objects + @Override + public boolean canLinkType(final Class type) { + return + MissingMethodHandler.class.isAssignableFrom(type) || + type == MissingMethod.class; + } + + @Override + public GuardedInvocation getGuardedInvocation(LinkRequest request, + LinkerServices linkerServices) throws Exception { + final Object self = request.getReceiver(); + CallSiteDescriptor desc = request.getCallSiteDescriptor(); + + // any method call is done by two steps. Step (1) GET_METHOD and (2) is CALL + // For step (1), we check if GET_METHOD can succeed by Java linker, if so + // we return that method object. If not, we return a MissingMethod object. + if (self instanceof MissingMethodHandler) { + // Check if this is a named GET_METHOD first. + boolean isGetMethod = getFirstStandardOperation(desc) == StandardOperation.GET_METHOD; + Object name = NamedOperation.getName(desc.getOperation()); + if (isGetMethod && name instanceof String) { + GuardingDynamicLinker javaLinker = beansLinker.getLinkerForClass(self.getClass()); + GuardedInvocation inv; + try { + inv = javaLinker.getGuardedInvocation(request, linkerServices); + } catch (final Throwable th) { + inv = null; + } + + String nameStr = name.toString(); + if (inv == null) { + // use "this" for just guard and drop it -- return a constant Method handle + // that returns a newly created MissingMethod object + MethodHandle mh = MethodHandles.constant(Object.class, new MissingMethod(nameStr)); + inv = new GuardedInvocation( + MethodHandles.dropArguments(mh, 0, Object.class), + Guards.isOfClass(self.getClass(), MethodType.methodType(Boolean.TYPE, Object.class))); + } + + return inv; + } + } else if (self instanceof MissingMethod) { + // This is step (2). We call MissingMethodHandler.doesNotUnderstand here + // Check if this is this a CALL first. + boolean isCall = getFirstStandardOperation(desc) == StandardOperation.CALL; + if (isCall) { + MethodHandle mh = DOES_NOT_UNDERSTAND; + + // flip "this" and method name (String) + mh = MethodHandles.permuteArguments(mh, FLIPPED_DOES_NOT_UNDERSTAND_TYPE, 1, 0, 2); + + // collect rest of the arguments as vararg + mh = mh.asCollector(Object[].class, desc.getMethodType().parameterCount() - 2); + + // convert MissingMethod object to it's name + mh = MethodHandles.filterArguments(mh, 0, MISSING_METHOD_TO_NAME); + return new GuardedInvocation(mh, IS_MISSING_METHOD); + } + } + + return null; + } + }); + return linkers; + } +}