# HG changeset patch # User hannesw # Date 1381851467 -7200 # Node ID aa452eb4a5d0f411d7a052c40438085c0cd817ce # Parent 64e841576c6837a869d55af477ed35b1a2fce91b 8026367: Add a sync keyword to mozilla_compat Reviewed-by: sundar, attila, lagergren diff -r 64e841576c68 -r aa452eb4a5d0 src/jdk/nashorn/api/scripting/ScriptUtils.java --- a/src/jdk/nashorn/api/scripting/ScriptUtils.java Tue Oct 15 15:57:14 2013 +0200 +++ b/src/jdk/nashorn/api/scripting/ScriptUtils.java Tue Oct 15 17:37:47 2013 +0200 @@ -25,6 +25,7 @@ package jdk.nashorn.api.scripting; +import jdk.nashorn.internal.runtime.ScriptFunction; import jdk.nashorn.internal.runtime.ScriptRuntime; /** @@ -57,4 +58,17 @@ public static String format(final String format, final Object[] args) { return Formatter.format(format, args); } + + /** + * Create a wrapper function that calls {@code func} synchronized on {@code sync} or, if that is undefined, + * {@code self}. Used to implement "sync" function in resources/mozilla_compat.js. + * + * @param func the function to invoke + * @param sync the object to synchronize on + * @return a synchronizing wrapper function + */ + public static Object makeSynchronizedFunction(final ScriptFunction func, final Object sync) { + return func.makeSynchronizedFunction(sync); + } + } diff -r 64e841576c68 -r aa452eb4a5d0 src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java --- a/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java Tue Oct 15 15:57:14 2013 +0200 +++ b/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java Tue Oct 15 17:37:47 2013 +0200 @@ -25,6 +25,7 @@ package jdk.nashorn.internal.objects; +import static jdk.nashorn.internal.lookup.Lookup.MH; import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; import java.lang.invoke.MethodHandle; @@ -255,6 +256,12 @@ return makeFunction(name, methodHandle, null); } + @Override + public ScriptFunction makeSynchronizedFunction(final Object sync) { + final MethodHandle mh = MH.insertArguments(ScriptFunction.INVOKE_SYNC, 0, this, sync); + return makeFunction(getName(), mh); + } + /** * Same as {@link ScriptFunction#makeBoundFunction(Object, Object[])}. The only reason we override it is so that we * can expose it to methods in this package. diff -r 64e841576c68 -r aa452eb4a5d0 src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java --- a/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java Tue Oct 15 15:57:14 2013 +0200 +++ b/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java Tue Oct 15 17:37:47 2013 +0200 @@ -53,7 +53,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData { /** FunctionNode with the code for this ScriptFunction */ - private volatile FunctionNode functionNode; + private FunctionNode functionNode; /** Source from which FunctionNode was parsed. */ private final Source source; @@ -65,7 +65,7 @@ private final PropertyMap allocatorMap; /** Code installer used for all further recompilation/specialization of this ScriptFunction */ - private volatile CodeInstaller installer; + private CodeInstaller installer; /** Name of class where allocator function resides */ private final String allocatorClassName; @@ -178,7 +178,7 @@ } @Override - protected void ensureCodeGenerated() { + protected synchronized void ensureCodeGenerated() { if (!code.isEmpty()) { return; // nothing to do, we have code, at least some. } @@ -336,7 +336,7 @@ } @Override - MethodHandle getBestInvoker(final MethodType callSiteType, final Object[] args) { + synchronized MethodHandle getBestInvoker(final MethodType callSiteType, final Object[] args) { final MethodType runtimeType = runtimeType(callSiteType, args); assert runtimeType.parameterCount() == callSiteType.parameterCount(); diff -r 64e841576c68 -r aa452eb4a5d0 src/jdk/nashorn/internal/runtime/ScriptFunction.java --- a/src/jdk/nashorn/internal/runtime/ScriptFunction.java Tue Oct 15 15:57:14 2013 +0200 +++ b/src/jdk/nashorn/internal/runtime/ScriptFunction.java Tue Oct 15 17:37:47 2013 +0200 @@ -59,6 +59,9 @@ /** Method handle for name getter for this ScriptFunction */ public static final MethodHandle G$NAME = findOwnMH("G$name", Object.class, Object.class); + /** Method handle used for implementing sync() in mozilla_compat */ + public static final MethodHandle INVOKE_SYNC = findOwnMH("invokeSync", Object.class, ScriptFunction.class, Object.class, Object.class, Object[].class); + /** Method handle for allocate function for this ScriptFunction */ static final MethodHandle ALLOCATE = findOwnMH("allocate", Object.class); @@ -301,6 +304,14 @@ public abstract void setPrototype(Object prototype); /** + * Create a function that invokes this function synchronized on {@code sync} or the self object + * of the invocation. + * @param sync the Object to synchronize on, or undefined + * @return synchronized function + */ + public abstract ScriptFunction makeSynchronizedFunction(Object sync); + + /** * Return the most appropriate invoke handle if there are specializations * @param type most specific method type to look for invocation with * @param args args for trampoline invocation @@ -614,6 +625,15 @@ return result; } + @SuppressWarnings("unused") + private static Object invokeSync(final ScriptFunction func, final Object sync, final Object self, final Object... args) + throws Throwable { + final Object syncObj = sync == UNDEFINED ? self : sync; + synchronized (syncObj) { + return func.invoke(self, args); + } + } + private static MethodHandle findOwnMH(final String name, final Class rtype, final Class... types) { final Class own = ScriptFunction.class; final MethodType mt = MH.type(rtype, types); diff -r 64e841576c68 -r aa452eb4a5d0 src/jdk/nashorn/internal/runtime/ScriptFunctionData.java --- a/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java Tue Oct 15 15:57:14 2013 +0200 +++ b/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java Tue Oct 15 17:37:47 2013 +0200 @@ -675,7 +675,7 @@ /** * Heuristic to figure out if the method handle has a callee argument. If it's type is either - * {@code (boolean, Object, ScriptFunction, ...)} or {@code (Object, ScriptFunction, ...)}, then we'll assume it has + * {@code (boolean, ScriptFunction, ...)} or {@code (ScriptFunction, ...)}, then we'll assume it has * a callee argument. We need this as the constructor above is not passed this information, and can't just blindly * assume it's false (notably, it's being invoked for creation of new scripts, and scripts have scopes, therefore * they also always receive a callee). @@ -692,11 +692,11 @@ return false; } - if (type.parameterType(0) == boolean.class) { - return length > 1 && type.parameterType(1) == ScriptFunction.class; + if (type.parameterType(0) == ScriptFunction.class) { + return true; } - return type.parameterType(0) == ScriptFunction.class; + return length > 1 && type.parameterType(0) == boolean.class && type.parameterType(1) == ScriptFunction.class; } /** diff -r 64e841576c68 -r aa452eb4a5d0 src/jdk/nashorn/internal/runtime/resources/mozilla_compat.js --- a/src/jdk/nashorn/internal/runtime/resources/mozilla_compat.js Tue Oct 15 15:57:14 2013 +0200 +++ b/src/jdk/nashorn/internal/runtime/resources/mozilla_compat.js Tue Oct 15 17:37:47 2013 +0200 @@ -98,6 +98,17 @@ } +// sync +Object.defineProperty(this, "sync", { + configurable: true, enumerable: false, writable: true, + value: function(func, syncobj) { + if (arguments.length < 1 || arguments.length > 2 ) { + throw "sync(function [,object]) parameter count mismatch"; + } + return Packages.jdk.nashorn.api.scripting.ScriptUtils.makeSynchronizedFunction(func, syncobj); + } +}); + // Object.prototype.__defineGetter__ Object.defineProperty(Object.prototype, "__defineGetter__", { configurable: true, enumerable: false, writable: true, diff -r 64e841576c68 -r aa452eb4a5d0 test/script/basic/JDK-8026367.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/JDK-8026367.js Tue Oct 15 17:37:47 2013 +0200 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2010, 2013, 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. + * + * 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. + */ + +/** + * JDK-8026367: Add a sync keyword to mozilla_compat + * + * @test + * @run + */ + +if (typeof sync === "undefined") { + load("nashorn:mozilla_compat.js"); +} + +var obj = { + count: 0, + // Sync called with one argument will synchronize on this-object of invocation + inc: sync(function(d) { + this.count += d; + }), + // Pass explicit object to synchronize on as second argument + dec: sync(function(d) { + this.count -= d; + }, obj) +}; + +var t1 = new java.lang.Thread(function() { + for (var i = 0; i < 100000; i++) obj.inc(1); +}); +var t2 = new java.lang.Thread(function() { + for (var i = 0; i < 100000; i++) obj.dec(1); +}); + +t1.start(); +t2.start(); +t1.join(); +t2.join(); + +if (obj.count !== 0) { + throw new Error("Expected count == 0, got " + obj.count); +} diff -r 64e841576c68 -r aa452eb4a5d0 test/script/sandbox/loadcompat.js --- a/test/script/sandbox/loadcompat.js Tue Oct 15 15:57:14 2013 +0200 +++ b/test/script/sandbox/loadcompat.js Tue Oct 15 17:37:47 2013 +0200 @@ -48,3 +48,7 @@ if (typeof importPackage != 'function') { fail("importPackage function is missing in compatibility script"); } + +if (typeof sync != 'function') { + fail("sync function is missing in compatibility script"); +}