8169050: underscore_linker.js sample fails after dynalink changes for JDK-8168005
authorsundar
Wed, 02 Nov 2016 18:36:26 +0530
changeset 41843 40da931419f1
parent 41842 50202a344d28
child 41844 bde614bca5d9
8169050: underscore_linker.js sample fails after dynalink changes for JDK-8168005 Reviewed-by: jlaskey, hannesw
nashorn/samples/dynalink/underscore_linker.js
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java
nashorn/test/src/META-INF/services/jdk.dynalink.linker.GuardingDynamicLinkerExporter
nashorn/test/src/jdk/dynalink/test/TrustedUnderscoreNameLinkerExporter.java
nashorn/test/src/jdk/nashorn/api/javaaccess/test/ArrayConversionTest.java
nashorn/test/src/jdk/nashorn/api/scripting/test/JDK_8169050_Test.java
--- a/nashorn/samples/dynalink/underscore_linker.js	Tue Nov 01 15:31:44 2016 +0100
+++ b/nashorn/samples/dynalink/underscore_linker.js	Wed Nov 02 18:36:26 2016 +0530
@@ -46,5 +46,6 @@
 // but make sure classpath points to the pluggable linker jar!
 
 `jjs -cp underscore_linker.jar underscore.js`
+print($ERR)
 print($OUT)
 
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java	Tue Nov 01 15:31:44 2016 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java	Wed Nov 02 18:36:26 2016 +0530
@@ -542,4 +542,9 @@
     public CallSiteDescriptor changeMethodTypeInternal(final MethodType newMethodType) {
         return get(getLookupPrivileged(), getOperation(), newMethodType, flags);
     }
+
+    @Override
+    protected CallSiteDescriptor changeOperationInternal(final Operation newOperation) {
+        return get(getLookupPrivileged(), newOperation, getMethodType(), flags);
+    }
 }
--- a/nashorn/test/src/META-INF/services/jdk.dynalink.linker.GuardingDynamicLinkerExporter	Tue Nov 01 15:31:44 2016 +0100
+++ b/nashorn/test/src/META-INF/services/jdk.dynalink.linker.GuardingDynamicLinkerExporter	Wed Nov 02 18:36:26 2016 +0530
@@ -1,2 +1,3 @@
 jdk.dynalink.test.UntrustedGuardingDynamicLinkerExporter
 jdk.dynalink.test.TrustedGuardingDynamicLinkerExporter
+jdk.dynalink.test.TrustedUnderscoreNameLinkerExporter
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/src/jdk/dynalink/test/TrustedUnderscoreNameLinkerExporter.java	Wed Nov 02 18:36:26 2016 +0530
@@ -0,0 +1,113 @@
+/*
+ * 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.dynalink.test;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import jdk.dynalink.CallSiteDescriptor;
+import jdk.dynalink.NamedOperation;
+import jdk.dynalink.NamespaceOperation;
+import jdk.dynalink.Operation;
+import jdk.dynalink.StandardNamespace;
+import jdk.dynalink.StandardOperation;
+import jdk.dynalink.linker.GuardedInvocation;
+import jdk.dynalink.linker.GuardingDynamicLinker;
+import jdk.dynalink.linker.GuardingDynamicLinkerExporter;
+import jdk.dynalink.linker.LinkRequest;
+import jdk.dynalink.linker.LinkerServices;
+import jdk.dynalink.linker.support.SimpleLinkRequest;
+
+/**
+ * This is a dynalink pluggable linker (see http://openjdk.java.net/jeps/276).
+ * This linker translater underscore_separated method names to CamelCase names
+ * used in Java APIs.
+ */
+public final class TrustedUnderscoreNameLinkerExporter extends GuardingDynamicLinkerExporter {
+    private static final Pattern UNDERSCORE_NAME = Pattern.compile("_(.)");
+
+    // translate underscore_separated name as a CamelCase name
+    private static String translateToCamelCase(final String name) {
+        final Matcher m = UNDERSCORE_NAME.matcher(name);
+        final StringBuilder buf = new StringBuilder();
+        while (m.find()) {
+            m.appendReplacement(buf, m.group(1).toUpperCase());
+        }
+        m.appendTail(buf);
+        return buf.toString();
+    }
+
+    @Override
+    public List<GuardingDynamicLinker> get() {
+        final ArrayList<GuardingDynamicLinker> linkers = new ArrayList<>();
+        linkers.add(new GuardingDynamicLinker() {
+            @Override
+            public GuardedInvocation getGuardedInvocation(final LinkRequest request,
+                final LinkerServices linkerServices) throws Exception {
+                final CallSiteDescriptor desc = request.getCallSiteDescriptor();
+                final Operation op = desc.getOperation();
+                final Object name = NamedOperation.getName(op);
+                final Operation namespaceOp = NamedOperation.getBaseOperation(op);
+                // is this a named GET_METHOD?
+                final boolean isGetMethod =
+                        NamespaceOperation.getBaseOperation(namespaceOp) == StandardOperation.GET
+                        && StandardNamespace.findFirst(namespaceOp) == StandardNamespace.METHOD;
+                if (isGetMethod && name instanceof String) {
+                    final String str = (String)name;
+                    if (str.indexOf('_') == -1) {
+                        return null;
+                    }
+
+                    final String nameStr = translateToCamelCase(str);
+                    // create a new call descriptor to use translated name
+                    final CallSiteDescriptor newDesc = AccessController.doPrivileged(
+                        new PrivilegedAction<CallSiteDescriptor>() {
+                            @Override
+                            public CallSiteDescriptor run() {
+                                return desc.changeOperation(((NamedOperation)op).changeName(nameStr));
+                            }
+                        });
+                    // create a new Link request to link the call site with translated name
+                    final LinkRequest newRequest = request.replaceArguments(newDesc, request.getArguments());
+                    // return guarded invocation linking the translated request
+                    return linkerServices.getGuardedInvocation(newRequest);
+                }
+
+                return null;
+            }
+        });
+        return linkers;
+    }
+}
--- a/nashorn/test/src/jdk/nashorn/api/javaaccess/test/ArrayConversionTest.java	Tue Nov 01 15:31:44 2016 +0100
+++ b/nashorn/test/src/jdk/nashorn/api/javaaccess/test/ArrayConversionTest.java	Wed Nov 02 18:36:26 2016 +0530
@@ -104,11 +104,11 @@
     @Test
     public void testVarArgs() throws ScriptException {
         // Sole NativeArray in vararg position becomes vararg array itself
-        runTest("assertVarArg_42_17", "[42, 17]");
+        runTest("assertVarArgWith42And17", "[42, 17]");
         // NativeArray in vararg position becomes an argument if there are more arguments
-        runTest("assertVarArg_array_17", "[42], 18");
+        runTest("assertVarArgArray7", "[42], 18");
         // Only NativeArray is converted to vararg array, other objects (e.g. a function) aren't
-        runTest("assertVarArg_function", "function() { return 'Hello' }");
+        runTest("assertVarArgFunction", "function() { return 'Hello' }");
     }
 
     private static void runTest(final String testMethodName, final String argument) throws ScriptException {
@@ -209,20 +209,20 @@
         assertEquals(Arrays.asList("apple", "orange"), array[1]);
     }
 
-    public static void assertVarArg_42_17(final Object... args) {
+    public static void assertVarArgWith42And17(final Object... args) {
         assertEquals(2, args.length);
         assertEquals(42, ((Number)args[0]).intValue());
         assertEquals(17, ((Number)args[1]).intValue());
     }
 
-    public static void assertVarArg_array_17(final Object... args) throws ScriptException {
+    public static void assertVarArgArray7(final Object... args) throws ScriptException {
         assertEquals(2, args.length);
         e.getBindings(ScriptContext.ENGINE_SCOPE).put("arr", args[0]);
         assertTrue((Boolean)e.eval("arr instanceof Array && arr.length == 1 && arr[0] == 42"));
         assertEquals(18, ((Number)args[1]).intValue());
     }
 
-    public static void assertVarArg_function(final Object... args) throws ScriptException {
+    public static void assertVarArgFunction(final Object... args) throws ScriptException {
         assertEquals(1, args.length);
         e.getBindings(ScriptContext.ENGINE_SCOPE).put("fn", args[0]);
         assertEquals("Hello", e.eval("fn()"));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/src/jdk/nashorn/api/scripting/test/JDK_8169050_Test.java	Wed Nov 02 18:36:26 2016 +0530
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.nashorn.api.scripting.test;
+
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineManager;
+import javax.script.ScriptException;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+/**
+ * @bug 8169050
+ * @summary underscore_linker.js sample fails after dynalink changes for JDK-8168005
+ */
+public class JDK_8169050_Test {
+    private ScriptEngine engine;
+
+    @BeforeClass
+    public void setupTest() {
+        engine = new ScriptEngineManager().getEngineByName("js");
+    }
+
+    @Test
+    public void testUndersoreName() throws ScriptException {
+        engine.eval("var S = java.util.stream.Stream, v = 0;");
+        // The underscore name 'for_each' exercises pluggable dynalink linker
+        engine.eval("S.of(4, 5, 9).for_each(function(x) { v += x })");
+        assertEquals(18, ((Number)engine.get("v")).intValue());
+    }
+}