8006525: Give StaticClass objects their own linker

Mon, 21 Jan 2013 11:03:56 +0100

author
attila
date
Mon, 21 Jan 2013 11:03:56 +0100
changeset 40
0cee498b330d
parent 39
a8966074d4e9
child 41
8b3cc4ad1810

8006525: Give StaticClass objects their own linker
Reviewed-by: hannesw, lagergren

src/jdk/nashorn/internal/runtime/linker/Bootstrap.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/linker/NashornPrimitiveLinker.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/linker/NashornStaticClassLinker.java file | annotate | diff | comparison | revisions
     1.1 --- a/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java	Sat Jan 19 22:35:43 2013 +0530
     1.2 +++ b/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java	Mon Jan 21 11:03:56 2013 +0100
     1.3 @@ -54,7 +54,8 @@
     1.4      private static final DynamicLinker dynamicLinker;
     1.5      static {
     1.6          final DynamicLinkerFactory factory = new DynamicLinkerFactory();
     1.7 -        factory.setPrioritizedLinkers(new NashornLinker(), new NashornPrimitiveLinker(), new JSObjectLinker());
     1.8 +        factory.setPrioritizedLinkers(new NashornLinker(), new NashornPrimitiveLinker(), new NashornStaticClassLinker(),
     1.9 +                new JSObjectLinker());
    1.10          factory.setFallbackLinkers(new BeansLinker(), new NashornBottomLinker());
    1.11          factory.setSyncOnRelink(true);
    1.12          final int relinkThreshold = Options.getIntProperty("nashorn.unstable.relink.threshold", -1);
     2.1 --- a/src/jdk/nashorn/internal/runtime/linker/NashornPrimitiveLinker.java	Sat Jan 19 22:35:43 2013 +0530
     2.2 +++ b/src/jdk/nashorn/internal/runtime/linker/NashornPrimitiveLinker.java	Mon Jan 21 11:03:56 2013 +0100
     2.3 @@ -31,44 +31,28 @@
     2.4  import java.lang.invoke.MethodHandles;
     2.5  import jdk.nashorn.internal.runtime.ConsString;
     2.6  import jdk.nashorn.internal.runtime.Context;
     2.7 -import jdk.nashorn.internal.runtime.ECMAErrors;
     2.8  import jdk.nashorn.internal.runtime.GlobalObject;
     2.9 -import org.dynalang.dynalink.beans.BeansLinker;
    2.10 -import org.dynalang.dynalink.beans.StaticClass;
    2.11  import org.dynalang.dynalink.linker.ConversionComparator;
    2.12  import org.dynalang.dynalink.linker.GuardedInvocation;
    2.13 -import org.dynalang.dynalink.linker.GuardingDynamicLinker;
    2.14  import org.dynalang.dynalink.linker.GuardingTypeConverterFactory;
    2.15  import org.dynalang.dynalink.linker.LinkRequest;
    2.16  import org.dynalang.dynalink.linker.LinkerServices;
    2.17  import org.dynalang.dynalink.linker.TypeBasedGuardingDynamicLinker;
    2.18 -import org.dynalang.dynalink.support.Guards;
    2.19  import org.dynalang.dynalink.support.TypeUtilities;
    2.20  
    2.21  /**
    2.22 - * Internal linker for String, Boolean, Number, and {@link StaticClass} objects, only ever used by Nashorn engine and
    2.23 - * not exposed to other engines. It is used for treatment of strings, boolean, and numbers, as JavaScript primitives,
    2.24 - * as well as for extending the "new" operator on StaticClass in order to be able to instantiate interfaces and abstract
    2.25 - * classes by passing a ScriptObject or ScriptFunction as their implementation, e.g.:
    2.26 - * <pre>
    2.27 - *   var r = new Runnable() { run: function() { print("Hello World" } }
    2.28 - * </pre>
    2.29 - * or even, for SAM types:
    2.30 - * <pre>
    2.31 - *   var r = new Runnable(function() { print("Hello World" })
    2.32 - * </pre>
    2.33 + * Internal linker for String, Boolean, and Number objects, only ever used by Nashorn engine and not exposed to other
    2.34 + * engines. It is used for treatment of strings, boolean, and numbers as JavaScript primitives. Also provides ECMAScript
    2.35 + * primitive type conversions for these types when linking to Java methods.
    2.36   */
    2.37  class NashornPrimitiveLinker implements TypeBasedGuardingDynamicLinker, GuardingTypeConverterFactory, ConversionComparator {
    2.38 -    private static final GuardingDynamicLinker staticClassLinker = BeansLinker.getLinkerForClass(StaticClass.class);
    2.39 -
    2.40      @Override
    2.41      public boolean canLinkType(final Class<?> type) {
    2.42          return canLinkTypeStatic(type);
    2.43      }
    2.44  
    2.45      private static boolean canLinkTypeStatic(final Class<?> type) {
    2.46 -        return type == String.class || type == Boolean.class || type == StaticClass.class ||
    2.47 -                type == ConsString.class || Number.class.isAssignableFrom(type);
    2.48 +        return type == String.class || type == Boolean.class || type == ConsString.class || Number.class.isAssignableFrom(type);
    2.49      }
    2.50  
    2.51      @Override
    2.52 @@ -86,41 +70,10 @@
    2.53             return Bootstrap.asType(global.stringLookup(desc, (CharSequence) self), linkerServices, desc);
    2.54          } else if (self instanceof Boolean) {
    2.55              return Bootstrap.asType(global.booleanLookup(desc, (Boolean) self), linkerServices, desc);
    2.56 -        } else if (self instanceof StaticClass) {
    2.57 -            // We intercept "new" on StaticClass instances to provide additional capabilities
    2.58 -            if ("new".equals(desc.getOperator())) {
    2.59 -                final Class<?> receiverClass = ((StaticClass) self).getRepresentedClass();
    2.60 -                // Is the class abstract? (This includes interfaces.)
    2.61 -                if (JavaAdapterFactory.isAbstractClass(receiverClass)) {
    2.62 -                    // Change this link request into a link request on the adapter class.
    2.63 -                    final Object[] args = request.getArguments();
    2.64 -                    args[0] = JavaAdapterFactory.getAdapterClassFor(new Class<?>[] { receiverClass });
    2.65 -                    final LinkRequest adapterRequest = request.replaceArguments(request.getCallSiteDescriptor(), args);
    2.66 -                    final GuardedInvocation gi = checkNullConstructor(
    2.67 -                            staticClassLinker.getGuardedInvocation(adapterRequest, linkerServices), receiverClass);
    2.68 -                    // Finally, modify the guard to test for the original abstract class.
    2.69 -                    return gi.replaceMethods(gi.getInvocation(), Guards.getIdentityGuard(self));
    2.70 -                }
    2.71 -                // If the class was not abstract, just link to the ordinary constructor. Make an additional check to
    2.72 -                // ensure we have a constructor. We could just fall through to the next "return" statement, except we
    2.73 -                // also insert a call to checkNullConstructor() which throws an error with a more intuitive message when
    2.74 -                // no suitable constructor is found.
    2.75 -                return checkNullConstructor(staticClassLinker.getGuardedInvocation(request, linkerServices), receiverClass);
    2.76 -            }
    2.77 -            // In case this was not a "new" operation, just link with the standard StaticClass linker.
    2.78 -            return staticClassLinker.getGuardedInvocation(request, linkerServices);
    2.79          }
    2.80 -
    2.81          throw new AssertionError(); // Can't reach here
    2.82      }
    2.83  
    2.84 -    private static GuardedInvocation checkNullConstructor(final GuardedInvocation ctorInvocation, final Class<?> receiverClass) {
    2.85 -        if(ctorInvocation == null) {
    2.86 -            ECMAErrors.typeError(Context.getGlobal(), "no.constructor.matches.args", receiverClass.getName());
    2.87 -        }
    2.88 -        return ctorInvocation;
    2.89 -    }
    2.90 -
    2.91      /**
    2.92       * This implementation of type converter factory will pretty much allow implicit conversions of anything to anything
    2.93       * else that's allowed among JavaScript primitive types (string to number, boolean to string, etc.)
    2.94 @@ -144,7 +97,8 @@
    2.95       * @param sourceType the source type to convert from
    2.96       * @param targetType1 one candidate target type
    2.97       * @param targetType2 another candidate target type
    2.98 -     * @return one of {@link org.dynalang.dynalink.linker.ConversionComparator.Comparison} values signifying which target type should be favored for conversion.
    2.99 +     * @return one of {@link org.dynalang.dynalink.linker.ConversionComparator.Comparison} values signifying which
   2.100 +     * target type should be favored for conversion.
   2.101       */
   2.102      @Override
   2.103      public Comparison compareConversion(final Class<?> sourceType, final Class<?> targetType1, final Class<?> targetType2) {
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/src/jdk/nashorn/internal/runtime/linker/NashornStaticClassLinker.java	Mon Jan 21 11:03:56 2013 +0100
     3.3 @@ -0,0 +1,101 @@
     3.4 +/*
     3.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
     3.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3.7 + *
     3.8 + * This code is free software; you can redistribute it and/or modify it
     3.9 + * under the terms of the GNU General Public License version 2 only, as
    3.10 + * published by the Free Software Foundation.  Oracle designates this
    3.11 + * particular file as subject to the "Classpath" exception as provided
    3.12 + * by Oracle in the LICENSE file that accompanied this code.
    3.13 + *
    3.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
    3.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    3.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    3.17 + * version 2 for more details (a copy is included in the LICENSE file that
    3.18 + * accompanied this code).
    3.19 + *
    3.20 + * You should have received a copy of the GNU General Public License version
    3.21 + * 2 along with this work; if not, write to the Free Software Foundation,
    3.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    3.23 + *
    3.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    3.25 + * or visit www.oracle.com if you need additional information or have any
    3.26 + * questions.
    3.27 + */
    3.28 +
    3.29 +package jdk.nashorn.internal.runtime.linker;
    3.30 +
    3.31 +import jdk.nashorn.internal.runtime.Context;
    3.32 +import jdk.nashorn.internal.runtime.ECMAErrors;
    3.33 +import org.dynalang.dynalink.CallSiteDescriptor;
    3.34 +import org.dynalang.dynalink.beans.BeansLinker;
    3.35 +import org.dynalang.dynalink.beans.StaticClass;
    3.36 +import org.dynalang.dynalink.linker.GuardedInvocation;
    3.37 +import org.dynalang.dynalink.linker.GuardingDynamicLinker;
    3.38 +import org.dynalang.dynalink.linker.LinkRequest;
    3.39 +import org.dynalang.dynalink.linker.LinkerServices;
    3.40 +import org.dynalang.dynalink.linker.TypeBasedGuardingDynamicLinker;
    3.41 +import org.dynalang.dynalink.support.Guards;
    3.42 +
    3.43 +/**
    3.44 + * Internal linker for {@link StaticClass} objects, only ever used by Nashorn engine and not exposed to other engines.
    3.45 + * It is used for extending the "new" operator on StaticClass in order to be able to instantiate interfaces and abstract
    3.46 + * classes by passing a ScriptObject or ScriptFunction as their implementation, e.g.:
    3.47 + * <pre>
    3.48 + *   var r = new Runnable() { run: function() { print("Hello World" } }
    3.49 + * </pre>
    3.50 + * or for SAM types, even just passing a function:
    3.51 + * <pre>
    3.52 + *   var r = new Runnable(function() { print("Hello World" })
    3.53 + * </pre>
    3.54 + */
    3.55 +class NashornStaticClassLinker implements TypeBasedGuardingDynamicLinker {
    3.56 +    private static final GuardingDynamicLinker staticClassLinker = BeansLinker.getLinkerForClass(StaticClass.class);
    3.57 +
    3.58 +    @Override
    3.59 +    public boolean canLinkType(Class<?> type) {
    3.60 +        return type == StaticClass.class;
    3.61 +    }
    3.62 +
    3.63 +    @Override
    3.64 +    public GuardedInvocation getGuardedInvocation(LinkRequest linkRequest, LinkerServices linkerServices) throws Exception {
    3.65 +        final LinkRequest request = linkRequest.withoutRuntimeContext(); // Nashorn has no runtime context
    3.66 +        final Object self = request.getReceiver();
    3.67 +        if (self.getClass() != StaticClass.class) {
    3.68 +            return null;
    3.69 +        }
    3.70 +        final CallSiteDescriptor desc = request.getCallSiteDescriptor();
    3.71 +        // We intercept "new" on StaticClass instances to provide additional capabilities
    3.72 +        if ("new".equals(desc.getNameToken(CallSiteDescriptor.OPERATOR))) {
    3.73 +            final Class<?> receiverClass = ((StaticClass) self).getRepresentedClass();
    3.74 +            // Is the class abstract? (This includes interfaces.)
    3.75 +            if (JavaAdapterFactory.isAbstractClass(receiverClass)) {
    3.76 +                // Change this link request into a link request on the adapter class.
    3.77 +                final Object[] args = request.getArguments();
    3.78 +                args[0] = JavaAdapterFactory.getAdapterClassFor(new Class<?>[] { receiverClass });
    3.79 +                final LinkRequest adapterRequest = request.replaceArguments(request.getCallSiteDescriptor(), args);
    3.80 +                final GuardedInvocation gi = checkNullConstructor(delegate(linkerServices, adapterRequest), receiverClass);
    3.81 +                // Finally, modify the guard to test for the original abstract class.
    3.82 +                return gi.replaceMethods(gi.getInvocation(), Guards.getIdentityGuard(self));
    3.83 +            }
    3.84 +            // If the class was not abstract, just delegate linking to the standard StaticClass linker. Make an
    3.85 +            // additional check to ensure we have a constructor. We could just fall through to the next "return"
    3.86 +            // statement, except we also insert a call to checkNullConstructor() which throws an ECMAScript TypeError
    3.87 +            // with a more intuitive message when no suitable constructor is found.
    3.88 +            return checkNullConstructor(delegate(linkerServices, request), receiverClass);
    3.89 +        }
    3.90 +        // In case this was not a "new" operation, just delegate to the the standard StaticClass linker.
    3.91 +        return delegate(linkerServices, request);
    3.92 +    }
    3.93 +
    3.94 +    private static GuardedInvocation delegate(LinkerServices linkerServices, final LinkRequest request) throws Exception {
    3.95 +        return staticClassLinker.getGuardedInvocation(request, linkerServices);
    3.96 +    }
    3.97 +
    3.98 +    private static GuardedInvocation checkNullConstructor(final GuardedInvocation ctorInvocation, final Class<?> receiverClass) {
    3.99 +        if(ctorInvocation == null) {
   3.100 +            ECMAErrors.typeError(Context.getGlobal(), "no.constructor.matches.args", receiverClass.getName());
   3.101 +        }
   3.102 +        return ctorInvocation;
   3.103 +    }
   3.104 +}

mercurial