Mon, 21 Jan 2013 11:03:56 +0100
8006525: Give StaticClass objects their own linker
Reviewed-by: hannesw, lagergren
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 +}