changeset 1678:58cac5dc254d

8150731: Nashorn JSObject linker should be exposed as a service provider Reviewed-by: jlaskey, hannesw
author sundar
date Fri, 06 May 2016 20:27:20 +0530
parents 4a9fca4fd993
children f62f25cbd211
files src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/linker/NashornLinkerExporter.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/Bootstrap.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java src/jdk.scripting.nashorn/share/classes/module-info.java test/src/jdk/dynalink/test/DynamicLinkerFactoryTest.java
diffstat 5 files changed, 140 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/linker/NashornLinkerExporter.java	Fri May 06 20:27:20 2016 +0530
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+package jdk.nashorn.api.linker;
+
+import java.util.List;
+import jdk.dynalink.linker.GuardingDynamicLinker;
+import jdk.dynalink.linker.GuardingDynamicLinkerExporter;
+import jdk.nashorn.internal.runtime.linker.Bootstrap;
+
+/**
+ * This linker exporter is a service provider that exports Nashorn Dynalink
+ * linkers to external users. Other languague runtimes that use Dynalink
+ * can use the linkers exported by this provider to support tight integration
+ * of Nashorn objects.
+ */
+public final class NashornLinkerExporter extends GuardingDynamicLinkerExporter {
+    /**
+     * The default constructor.
+     */
+    public NashornLinkerExporter() {}
+
+    /**
+     * Returns a list of exported nashorn specific linkers.
+     *
+     * @return list of exported nashorn specific linkers
+     */
+    @Override
+    public List<GuardingDynamicLinker> get() {
+        return Bootstrap.getExposedLinkers();
+    }
+}
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/Bootstrap.java	Thu May 05 19:10:51 2016 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/Bootstrap.java	Fri May 06 20:27:20 2016 +0530
@@ -33,6 +33,8 @@
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodHandles.Lookup;
 import java.lang.invoke.MethodType;
+import java.util.Collections;
+import java.util.List;
 import jdk.dynalink.CallSiteDescriptor;
 import jdk.dynalink.DynamicLinker;
 import jdk.dynalink.DynamicLinkerFactory;
@@ -70,6 +72,7 @@
     private static final BeansLinker beansLinker = new BeansLinker(Bootstrap::createMissingMemberHandler);
     private static final GuardingDynamicLinker[] prioritizedLinkers;
     private static final GuardingDynamicLinker[] fallbackLinkers;
+
     static {
         final NashornBeansLinker nashornBeansLinker = new NashornBeansLinker(beansLinker);
         prioritizedLinkers = new GuardingDynamicLinker[] {
@@ -90,6 +93,19 @@
     }
 
     /**
+     * Returns a list of exposed nashorn dynalink linkers.
+     *
+     * @return a list of exposed nashorn dynalink linkers.
+     */
+    public static List<GuardingDynamicLinker> getExposedLinkers() {
+        // we have to create BeansLinker without nashorn specific missing member handler!
+        // Or else, we'd return values such as 'undefined' to the external world!
+        final NashornBeansLinker nbl = new NashornBeansLinker(new BeansLinker());
+        final JSObjectLinker linker = new JSObjectLinker(nbl);
+        return Collections.singletonList(linker);
+    }
+
+    /**
      * Creates a Nashorn dynamic linker with the given app class loader.
      * @param appLoader the app class loader. It will be used to discover
      * additional language runtime linkers (if any).
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java	Thu May 05 19:10:51 2016 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java	Fri May 06 20:27:20 2016 +0530
@@ -71,6 +71,9 @@
     public GuardedInvocation getGuardedInvocation(final LinkRequest request, final LinkerServices linkerServices) throws Exception {
         final Object self = request.getReceiver();
         final CallSiteDescriptor desc = request.getCallSiteDescriptor();
+        if (self == null || !canLinkTypeStatic(self.getClass())) {
+            return null;
+        }
 
         GuardedInvocation inv;
         if (self instanceof JSObject) {
@@ -82,7 +85,7 @@
             inv = new GuardedInvocation(beanInv.getInvocation(),
                 NashornGuards.combineGuards(beanInv.getGuard(), NashornGuards.getNotJSObjectGuard()));
         } else {
-            throw new AssertionError(); // Should never reach here.
+            throw new AssertionError("got instanceof: " + self.getClass()); // Should never reach here.
         }
 
         return Bootstrap.asTypeSafeReturn(inv, linkerServices, desc);
--- a/src/jdk.scripting.nashorn/share/classes/module-info.java	Thu May 05 19:10:51 2016 +0000
+++ b/src/jdk.scripting.nashorn/share/classes/module-info.java	Fri May 06 20:27:20 2016 +0530
@@ -38,6 +38,10 @@
     exports jdk.nashorn.tools to
         jdk.scripting.nashorn.shell;
 
-    provides javax.script.ScriptEngineFactory with jdk.nashorn.api.scripting.NashornScriptEngineFactory;
+    provides javax.script.ScriptEngineFactory
+        with jdk.nashorn.api.scripting.NashornScriptEngineFactory;
+
+    provides jdk.dynalink.linker.GuardingDynamicLinkerExporter
+        with jdk.nashorn.api.linker.NashornLinkerExporter;
 }
 
--- a/test/src/jdk/dynalink/test/DynamicLinkerFactoryTest.java	Thu May 05 19:10:51 2016 +0000
+++ b/test/src/jdk/dynalink/test/DynamicLinkerFactoryTest.java	Fri May 06 20:27:20 2016 +0530
@@ -30,10 +30,13 @@
 import java.lang.invoke.MethodType;
 import java.util.List;
 import java.util.ServiceConfigurationError;
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineManager;
 import jdk.dynalink.CallSiteDescriptor;
 import jdk.dynalink.DynamicLinker;
 import jdk.dynalink.DynamicLinkerFactory;
 import jdk.dynalink.NoSuchDynamicMethodException;
+import jdk.dynalink.NamedOperation;
 import jdk.dynalink.Operation;
 import jdk.dynalink.StandardOperation;
 import jdk.dynalink.linker.GuardingDynamicLinker;
@@ -41,6 +44,7 @@
 import jdk.dynalink.linker.LinkerServices;
 import jdk.dynalink.support.SimpleRelinkableCallSite;
 import jdk.dynalink.linker.GuardedInvocation;
+import jdk.nashorn.api.scripting.AbstractJSObject;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
@@ -254,4 +258,55 @@
 
         Assert.assertTrue(reachedAutoLinker);
     }
+
+    @Test
+    public void nashornExportedLinkerJSObjectTest() {
+        final DynamicLinkerFactory factory = newDynamicLinkerFactory(false);
+        final DynamicLinker linker = factory.createLinker();
+
+        final MethodType mt = MethodType.methodType(Object.class, Object.class);
+        final NamedOperation op = new NamedOperation(StandardOperation.GET_PROPERTY, "foo");
+        final CallSite cs = linker.link(new SimpleRelinkableCallSite(new CallSiteDescriptor(
+                MethodHandles.publicLookup(), op, mt)));
+        final boolean[] reachedGetMember = new boolean[1];
+        // check that the nashorn exported linker can be used for user defined JSObject
+        Object obj = new AbstractJSObject() {
+                @Override
+                public Object getMember(String name) {
+                    reachedGetMember[0] = true;
+                    return name.equals("foo")? "bar" : "<unknown>";
+                }
+            };
+
+        Object value = null;
+        try {
+            value = cs.getTarget().invoke(obj);
+        } catch (Throwable th) {
+            throw new RuntimeException(th);
+        }
+
+        Assert.assertTrue(reachedGetMember[0]);
+        Assert.assertEquals(value, "bar");
+    }
+
+    @Test
+    public void nashornExportedLinkerScriptObjectMirrorTest() {
+        final DynamicLinkerFactory factory = newDynamicLinkerFactory(false);
+        final DynamicLinker linker = factory.createLinker();
+
+        // check that the nashorn exported linker can be used for ScriptObjectMirror
+        final ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
+        final MethodType mt = MethodType.methodType(Object.class, Object.class);
+        final NamedOperation op = new NamedOperation(StandardOperation.GET_PROPERTY, "foo");
+        final CallSite cs = linker.link(new SimpleRelinkableCallSite(new CallSiteDescriptor(
+                MethodHandles.publicLookup(), op, mt)));
+        Object value = null;
+        try {
+            final Object obj = engine.eval("({ foo: 'hello' })");
+            value = cs.getTarget().invoke(obj);
+        } catch (Throwable th) {
+            throw new RuntimeException(th);
+        }
+        Assert.assertEquals(value, "hello");
+    }
 }