Tue, 15 Oct 2013 17:37:47 +0200
8026367: Add a sync keyword to mozilla_compat
Reviewed-by: sundar, attila, lagergren
1.1 --- a/src/jdk/nashorn/api/scripting/ScriptUtils.java Tue Oct 15 15:57:14 2013 +0200 1.2 +++ b/src/jdk/nashorn/api/scripting/ScriptUtils.java Tue Oct 15 17:37:47 2013 +0200 1.3 @@ -25,6 +25,7 @@ 1.4 1.5 package jdk.nashorn.api.scripting; 1.6 1.7 +import jdk.nashorn.internal.runtime.ScriptFunction; 1.8 import jdk.nashorn.internal.runtime.ScriptRuntime; 1.9 1.10 /** 1.11 @@ -57,4 +58,17 @@ 1.12 public static String format(final String format, final Object[] args) { 1.13 return Formatter.format(format, args); 1.14 } 1.15 + 1.16 + /** 1.17 + * Create a wrapper function that calls {@code func} synchronized on {@code sync} or, if that is undefined, 1.18 + * {@code self}. Used to implement "sync" function in resources/mozilla_compat.js. 1.19 + * 1.20 + * @param func the function to invoke 1.21 + * @param sync the object to synchronize on 1.22 + * @return a synchronizing wrapper function 1.23 + */ 1.24 + public static Object makeSynchronizedFunction(final ScriptFunction func, final Object sync) { 1.25 + return func.makeSynchronizedFunction(sync); 1.26 + } 1.27 + 1.28 }
2.1 --- a/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java Tue Oct 15 15:57:14 2013 +0200 2.2 +++ b/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java Tue Oct 15 17:37:47 2013 +0200 2.3 @@ -25,6 +25,7 @@ 2.4 2.5 package jdk.nashorn.internal.objects; 2.6 2.7 +import static jdk.nashorn.internal.lookup.Lookup.MH; 2.8 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; 2.9 2.10 import java.lang.invoke.MethodHandle; 2.11 @@ -255,6 +256,12 @@ 2.12 return makeFunction(name, methodHandle, null); 2.13 } 2.14 2.15 + @Override 2.16 + public ScriptFunction makeSynchronizedFunction(final Object sync) { 2.17 + final MethodHandle mh = MH.insertArguments(ScriptFunction.INVOKE_SYNC, 0, this, sync); 2.18 + return makeFunction(getName(), mh); 2.19 + } 2.20 + 2.21 /** 2.22 * Same as {@link ScriptFunction#makeBoundFunction(Object, Object[])}. The only reason we override it is so that we 2.23 * can expose it to methods in this package.
3.1 --- a/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java Tue Oct 15 15:57:14 2013 +0200 3.2 +++ b/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java Tue Oct 15 17:37:47 2013 +0200 3.3 @@ -53,7 +53,7 @@ 3.4 public final class RecompilableScriptFunctionData extends ScriptFunctionData { 3.5 3.6 /** FunctionNode with the code for this ScriptFunction */ 3.7 - private volatile FunctionNode functionNode; 3.8 + private FunctionNode functionNode; 3.9 3.10 /** Source from which FunctionNode was parsed. */ 3.11 private final Source source; 3.12 @@ -65,7 +65,7 @@ 3.13 private final PropertyMap allocatorMap; 3.14 3.15 /** Code installer used for all further recompilation/specialization of this ScriptFunction */ 3.16 - private volatile CodeInstaller<ScriptEnvironment> installer; 3.17 + private CodeInstaller<ScriptEnvironment> installer; 3.18 3.19 /** Name of class where allocator function resides */ 3.20 private final String allocatorClassName; 3.21 @@ -178,7 +178,7 @@ 3.22 } 3.23 3.24 @Override 3.25 - protected void ensureCodeGenerated() { 3.26 + protected synchronized void ensureCodeGenerated() { 3.27 if (!code.isEmpty()) { 3.28 return; // nothing to do, we have code, at least some. 3.29 } 3.30 @@ -336,7 +336,7 @@ 3.31 } 3.32 3.33 @Override 3.34 - MethodHandle getBestInvoker(final MethodType callSiteType, final Object[] args) { 3.35 + synchronized MethodHandle getBestInvoker(final MethodType callSiteType, final Object[] args) { 3.36 final MethodType runtimeType = runtimeType(callSiteType, args); 3.37 assert runtimeType.parameterCount() == callSiteType.parameterCount(); 3.38
4.1 --- a/src/jdk/nashorn/internal/runtime/ScriptFunction.java Tue Oct 15 15:57:14 2013 +0200 4.2 +++ b/src/jdk/nashorn/internal/runtime/ScriptFunction.java Tue Oct 15 17:37:47 2013 +0200 4.3 @@ -59,6 +59,9 @@ 4.4 /** Method handle for name getter for this ScriptFunction */ 4.5 public static final MethodHandle G$NAME = findOwnMH("G$name", Object.class, Object.class); 4.6 4.7 + /** Method handle used for implementing sync() in mozilla_compat */ 4.8 + public static final MethodHandle INVOKE_SYNC = findOwnMH("invokeSync", Object.class, ScriptFunction.class, Object.class, Object.class, Object[].class); 4.9 + 4.10 /** Method handle for allocate function for this ScriptFunction */ 4.11 static final MethodHandle ALLOCATE = findOwnMH("allocate", Object.class); 4.12 4.13 @@ -301,6 +304,14 @@ 4.14 public abstract void setPrototype(Object prototype); 4.15 4.16 /** 4.17 + * Create a function that invokes this function synchronized on {@code sync} or the self object 4.18 + * of the invocation. 4.19 + * @param sync the Object to synchronize on, or undefined 4.20 + * @return synchronized function 4.21 + */ 4.22 + public abstract ScriptFunction makeSynchronizedFunction(Object sync); 4.23 + 4.24 + /** 4.25 * Return the most appropriate invoke handle if there are specializations 4.26 * @param type most specific method type to look for invocation with 4.27 * @param args args for trampoline invocation 4.28 @@ -614,6 +625,15 @@ 4.29 return result; 4.30 } 4.31 4.32 + @SuppressWarnings("unused") 4.33 + private static Object invokeSync(final ScriptFunction func, final Object sync, final Object self, final Object... args) 4.34 + throws Throwable { 4.35 + final Object syncObj = sync == UNDEFINED ? self : sync; 4.36 + synchronized (syncObj) { 4.37 + return func.invoke(self, args); 4.38 + } 4.39 + } 4.40 + 4.41 private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) { 4.42 final Class<?> own = ScriptFunction.class; 4.43 final MethodType mt = MH.type(rtype, types);
5.1 --- a/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java Tue Oct 15 15:57:14 2013 +0200 5.2 +++ b/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java Tue Oct 15 17:37:47 2013 +0200 5.3 @@ -675,7 +675,7 @@ 5.4 5.5 /** 5.6 * Heuristic to figure out if the method handle has a callee argument. If it's type is either 5.7 - * {@code (boolean, Object, ScriptFunction, ...)} or {@code (Object, ScriptFunction, ...)}, then we'll assume it has 5.8 + * {@code (boolean, ScriptFunction, ...)} or {@code (ScriptFunction, ...)}, then we'll assume it has 5.9 * a callee argument. We need this as the constructor above is not passed this information, and can't just blindly 5.10 * assume it's false (notably, it's being invoked for creation of new scripts, and scripts have scopes, therefore 5.11 * they also always receive a callee). 5.12 @@ -692,11 +692,11 @@ 5.13 return false; 5.14 } 5.15 5.16 - if (type.parameterType(0) == boolean.class) { 5.17 - return length > 1 && type.parameterType(1) == ScriptFunction.class; 5.18 + if (type.parameterType(0) == ScriptFunction.class) { 5.19 + return true; 5.20 } 5.21 5.22 - return type.parameterType(0) == ScriptFunction.class; 5.23 + return length > 1 && type.parameterType(0) == boolean.class && type.parameterType(1) == ScriptFunction.class; 5.24 } 5.25 5.26 /**
6.1 --- a/src/jdk/nashorn/internal/runtime/resources/mozilla_compat.js Tue Oct 15 15:57:14 2013 +0200 6.2 +++ b/src/jdk/nashorn/internal/runtime/resources/mozilla_compat.js Tue Oct 15 17:37:47 2013 +0200 6.3 @@ -98,6 +98,17 @@ 6.4 6.5 } 6.6 6.7 +// sync 6.8 +Object.defineProperty(this, "sync", { 6.9 + configurable: true, enumerable: false, writable: true, 6.10 + value: function(func, syncobj) { 6.11 + if (arguments.length < 1 || arguments.length > 2 ) { 6.12 + throw "sync(function [,object]) parameter count mismatch"; 6.13 + } 6.14 + return Packages.jdk.nashorn.api.scripting.ScriptUtils.makeSynchronizedFunction(func, syncobj); 6.15 + } 6.16 +}); 6.17 + 6.18 // Object.prototype.__defineGetter__ 6.19 Object.defineProperty(Object.prototype, "__defineGetter__", { 6.20 configurable: true, enumerable: false, writable: true,
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 7.2 +++ b/test/script/basic/JDK-8026367.js Tue Oct 15 17:37:47 2013 +0200 7.3 @@ -0,0 +1,61 @@ 7.4 +/* 7.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 7.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 7.7 + * 7.8 + * This code is free software; you can redistribute it and/or modify it 7.9 + * under the terms of the GNU General Public License version 2 only, as 7.10 + * published by the Free Software Foundation. 7.11 + * 7.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 7.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 7.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 7.15 + * version 2 for more details (a copy is included in the LICENSE file that 7.16 + * accompanied this code). 7.17 + * 7.18 + * You should have received a copy of the GNU General Public License version 7.19 + * 2 along with this work; if not, write to the Free Software Foundation, 7.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 7.21 + * 7.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 7.23 + * or visit www.oracle.com if you need additional information or have any 7.24 + * questions. 7.25 + */ 7.26 + 7.27 +/** 7.28 + * JDK-8026367: Add a sync keyword to mozilla_compat 7.29 + * 7.30 + * @test 7.31 + * @run 7.32 + */ 7.33 + 7.34 +if (typeof sync === "undefined") { 7.35 + load("nashorn:mozilla_compat.js"); 7.36 +} 7.37 + 7.38 +var obj = { 7.39 + count: 0, 7.40 + // Sync called with one argument will synchronize on this-object of invocation 7.41 + inc: sync(function(d) { 7.42 + this.count += d; 7.43 + }), 7.44 + // Pass explicit object to synchronize on as second argument 7.45 + dec: sync(function(d) { 7.46 + this.count -= d; 7.47 + }, obj) 7.48 +}; 7.49 + 7.50 +var t1 = new java.lang.Thread(function() { 7.51 + for (var i = 0; i < 100000; i++) obj.inc(1); 7.52 +}); 7.53 +var t2 = new java.lang.Thread(function() { 7.54 + for (var i = 0; i < 100000; i++) obj.dec(1); 7.55 +}); 7.56 + 7.57 +t1.start(); 7.58 +t2.start(); 7.59 +t1.join(); 7.60 +t2.join(); 7.61 + 7.62 +if (obj.count !== 0) { 7.63 + throw new Error("Expected count == 0, got " + obj.count); 7.64 +}
8.1 --- a/test/script/sandbox/loadcompat.js Tue Oct 15 15:57:14 2013 +0200 8.2 +++ b/test/script/sandbox/loadcompat.js Tue Oct 15 17:37:47 2013 +0200 8.3 @@ -48,3 +48,7 @@ 8.4 if (typeof importPackage != 'function') { 8.5 fail("importPackage function is missing in compatibility script"); 8.6 } 8.7 + 8.8 +if (typeof sync != 'function') { 8.9 + fail("sync function is missing in compatibility script"); 8.10 +}