# HG changeset patch # User sundar # Date 1456388783 -19800 # Node ID 696d662bcdb77493abbb48e7d4992d8274cabc24 # Parent 1c076468bf7dad5b8f2ee5dcf66e2279caa3e208 8148379: jdk.nashorn.api.scripting spec. adjustments, clarifications Reviewed-by: hannesw, mhaupt diff -r 1c076468bf7d -r 696d662bcdb7 nashorn/make/build.xml --- a/nashorn/make/build.xml Wed Jul 05 21:22:47 2017 +0200 +++ b/nashorn/make/build.xml Thu Feb 25 13:56:23 2016 +0530 @@ -242,6 +242,7 @@ + @@ -261,6 +262,7 @@ + @@ -276,6 +278,7 @@ + @@ -289,6 +292,7 @@ + diff -r 1c076468bf7d -r 696d662bcdb7 nashorn/make/project.properties --- a/nashorn/make/project.properties Wed Jul 05 21:22:47 2017 +0200 +++ b/nashorn/make/project.properties Thu Feb 25 13:56:23 2016 +0530 @@ -34,6 +34,8 @@ javac.source=1.8 javac.target=1.8 +javadoc.option=-tag "implSpec:a:Implementation Requirements:" + # nashorn version information nashorn.version=0.1 nashorn.fullversion=0.1 diff -r 1c076468bf7d -r 696d662bcdb7 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/AbstractJSObject.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/AbstractJSObject.java Wed Jul 05 21:22:47 2017 +0200 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/AbstractJSObject.java Thu Feb 25 13:56:23 2016 +0530 @@ -27,6 +27,7 @@ import java.util.Collection; import java.util.Collections; +import java.util.Objects; import java.util.Set; /** @@ -34,19 +35,19 @@ * * This class can also be subclassed by an arbitrary Java class. Nashorn will * treat objects of such classes just like nashorn script objects. Usual nashorn - * operations like obj[i], obj.foo, obj.func(), delete obj.foo will be glued + * operations like obj[i], obj.foo, obj.func(), delete obj.foo will be delegated * to appropriate method call of this class. * * @since 1.8u40 */ public abstract class AbstractJSObject implements JSObject { /** - * Call this object as a JavaScript function. This is equivalent to - * 'func.apply(thiz, args)' in JavaScript. - * - * @param thiz 'this' object to be passed to the function - * @param args arguments to method - * @return result of call + * The default constructor. + */ + public AbstractJSObject() {} + + /** + * @implSpec This implementation always throws UnsupportedOperationException */ @Override public Object call(final Object thiz, final Object... args) { @@ -54,11 +55,7 @@ } /** - * Call this 'constructor' JavaScript function to create a new object. - * This is equivalent to 'new func(arg1, arg2...)' in JavaScript. - * - * @param args arguments to method - * @return result of constructor call + * @implSpec This implementation always throws UnsupportedOperationException */ @Override public Object newObject(final Object... args) { @@ -66,10 +63,7 @@ } /** - * Evaluate a JavaScript expression. - * - * @param s JavaScript expression to evaluate - * @return evaluation result + * @implSpec This imlementation always throws UnsupportedOperationException */ @Override public Object eval(final String s) { @@ -77,21 +71,16 @@ } /** - * Retrieves a named member of this JavaScript object. - * - * @param name of member - * @return member + * @implSpec This implementation always returns null */ @Override public Object getMember(final String name) { + Objects.requireNonNull(name); return null; } /** - * Retrieves an indexed member of this JavaScript object. - * - * @param index index slot to retrieve - * @return member + * @implSpec This implementation always returns null */ @Override public Object getSlot(final int index) { @@ -99,21 +88,16 @@ } /** - * Does this object have a named member? - * - * @param name name of member - * @return true if this object has a member of the given name + * @implSpec This implementation always returns false */ @Override public boolean hasMember(final String name) { + Objects.requireNonNull(name); return false; } /** - * Does this object have a indexed property? - * - * @param slot index to check - * @return true if this object has a slot + * @implSpec This implementation always returns false */ @Override public boolean hasSlot(final int slot) { @@ -121,31 +105,25 @@ } /** - * Remove a named member from this JavaScript object - * - * @param name name of the member + * @implSpec This implementation is a no-op */ @Override public void removeMember(final String name) { + Objects.requireNonNull(name); //empty } /** - * Set a named member in this JavaScript object - * - * @param name name of the member - * @param value value of the member + * @implSpec This implementation is a no-op */ @Override public void setMember(final String name, final Object value) { + Objects.requireNonNull(name); //empty } /** - * Set an indexed member in this JavaScript object - * - * @param index index of the member slot - * @param value value of the member + * @implSpec This implementation is a no-op */ @Override public void setSlot(final int index, final Object value) { @@ -155,9 +133,7 @@ // property and value iteration /** - * Returns the set of all property names of this object. - * - * @return set of property names + * @implSpec This implementation returns empty set */ @Override public Set keySet() { @@ -165,9 +141,7 @@ } /** - * Returns the set of all property values of this object. - * - * @return set of property values. + * @implSpec This implementation returns empty set */ @Override public Collection values() { @@ -177,22 +151,13 @@ // JavaScript instanceof check /** - * Checking whether the given object is an instance of 'this' object. - * - * @param instance instance to check - * @return true if the given 'instance' is an instance of this 'function' object + * @implSpec This implementation always returns false */ @Override public boolean isInstance(final Object instance) { return false; } - /** - * Checking whether this object is an instance of the given 'clazz' object. - * - * @param clazz clazz to check - * @return true if this object is an instance of the given 'clazz' - */ @Override public boolean isInstanceOf(final Object clazz) { if (clazz instanceof JSObject) { @@ -202,20 +167,13 @@ return false; } - /** - * ECMA [[Class]] property - * - * @return ECMA [[Class]] property value of this object - */ @Override public String getClassName() { return getClass().getName(); } /** - * Is this a function object? - * - * @return if this mirror wraps a ECMAScript function instance + * @implSpec This implementation always returns false */ @Override public boolean isFunction() { @@ -223,9 +181,7 @@ } /** - * Is this a 'use strict' function object? - * - * @return true if this mirror represents a ECMAScript 'use strict' function + * @implSpec This implementation always returns false */ @Override public boolean isStrictFunction() { @@ -233,9 +189,7 @@ } /** - * Is this an array object? - * - * @return if this mirror wraps a ECMAScript array object + * @implSpec This implementation always returns false */ @Override public boolean isArray() { diff -r 1c076468bf7d -r 696d662bcdb7 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/JSObject.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/JSObject.java Wed Jul 05 21:22:47 2017 +0200 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/JSObject.java Thu Feb 25 13:56:23 2016 +0530 @@ -32,7 +32,7 @@ /** * This interface can be implemented by an arbitrary Java class. Nashorn will * treat objects of such classes just like nashorn script objects. Usual nashorn - * operations like obj[i], obj.foo, obj.func(), delete obj.foo will be glued + * operations like obj[i], obj.foo, obj.func(), delete obj.foo will be delegated * to appropriate method call of this interface. * * @since 1.8u40 @@ -42,7 +42,7 @@ * Call this object as a JavaScript function. This is equivalent to * 'func.apply(thiz, args)' in JavaScript. * - * @param thiz 'this' object to be passed to the function + * @param thiz 'this' object to be passed to the function. This may be null. * @param args arguments to method * @return result of call */ @@ -70,6 +70,7 @@ * * @param name of member * @return member + * @throws NullPointerException if name is null */ public Object getMember(final String name); @@ -101,6 +102,7 @@ * Remove a named member from this JavaScript object * * @param name name of the member + * @throws NullPointerException if name is null */ public void removeMember(final String name); @@ -109,6 +111,7 @@ * * @param name name of the member * @param value value of the member + * @throws NullPointerException if name is null */ public void setMember(final String name, final Object value); diff -r 1c076468bf7d -r 696d662bcdb7 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/NashornException.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/NashornException.java Wed Jul 05 21:22:47 2017 +0200 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/NashornException.java Thu Feb 25 13:56:23 2016 +0530 @@ -46,6 +46,8 @@ */ @SuppressWarnings("serial") public abstract class NashornException extends RuntimeException { + private static final long serialVersionUID = 1L; + // script file name private String fileName; // script line number @@ -58,7 +60,7 @@ private Object ecmaError; /** - * Constructor + * Constructor to initialize error message, file name, line and column numbers. * * @param msg exception message * @param fileName file name @@ -70,7 +72,7 @@ } /** - * Constructor + * Constructor to initialize error message, cause exception, file name, line and column numbers. * * @param msg exception message * @param cause exception cause @@ -86,7 +88,7 @@ } /** - * Constructor + * Constructor to initialize error message and cause exception. * * @param msg exception message * @param cause exception cause diff -r 1c076468bf7d -r 696d662bcdb7 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java Wed Jul 05 21:22:47 2017 +0200 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java Thu Feb 25 13:56:23 2016 +0530 @@ -154,7 +154,7 @@ } /** - * Create a new Script engine initialized by given class loader. + * Create a new Script engine initialized with the given class loader. * * @param appLoader class loader to be used as script "app" class loader. * @return newly created script engine. @@ -167,7 +167,7 @@ } /** - * Create a new Script engine initialized by given class filter. + * Create a new Script engine initialized with the given class filter. * * @param classFilter class filter to use. * @return newly created script engine. @@ -181,7 +181,7 @@ } /** - * Create a new Script engine initialized by given arguments. + * Create a new Script engine initialized with the given arguments. * * @param args arguments array passed to script engine. * @return newly created script engine. @@ -195,7 +195,7 @@ } /** - * Create a new Script engine initialized by given arguments. + * Create a new Script engine initialized with the given arguments and the given class loader. * * @param args arguments array passed to script engine. * @param appLoader class loader to be used as script "app" class loader. @@ -210,7 +210,7 @@ } /** - * Create a new Script engine initialized by given arguments. + * Create a new Script engine initialized with the given arguments, class loader and class filter. * * @param args arguments array passed to script engine. * @param appLoader class loader to be used as script "app" class loader. diff -r 1c076468bf7d -r 696d662bcdb7 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/ScriptObjectMirror.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/ScriptObjectMirror.java Wed Jul 05 21:22:47 2017 +0200 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/ScriptObjectMirror.java Thu Feb 25 13:56:23 2016 +0530 @@ -287,22 +287,21 @@ }); } - @Override - public boolean isInstance(final Object obj) { - if (! (obj instanceof ScriptObjectMirror)) { + public boolean isInstance(final Object instance) { + if (! (instance instanceof ScriptObjectMirror)) { return false; } - final ScriptObjectMirror instance = (ScriptObjectMirror)obj; + final ScriptObjectMirror mirror = (ScriptObjectMirror)instance; // if not belongs to my global scope, return false - if (global != instance.global) { + if (global != mirror.global) { return false; } return inGlobal(new Callable() { @Override public Boolean call() { - return sobj.isInstance(instance.sobj); + return sobj.isInstance(mirror.sobj); } }); } @@ -653,10 +652,10 @@ } /** - * Make a script object mirror on given object if needed. Also converts ConsString instances to Strings. + * Make a script object mirror on given object if needed. * * @param obj object to be wrapped/converted - * @param homeGlobal global to which this object belongs. Not used for ConsStrings. + * @param homeGlobal global to which this object belongs. * @return wrapped/converted object */ public static Object wrap(final Object obj, final Object homeGlobal) { @@ -664,13 +663,13 @@ } /** - * Make a script object mirror on given object if needed. Also converts ConsString instances to Strings. The - * created wrapper will implement the Java {@code List} interface if {@code obj} is a JavaScript - * {@code Array} object; this is compatible with Java JSON libraries expectations. Arrays retrieved through its + * Make a script object mirror on given object if needed. The created wrapper will implement + * the Java {@code List} interface if {@code obj} is a JavaScript {@code Array} object; + * this is compatible with Java JSON libraries expectations. Arrays retrieved through its * properties (transitively) will also implement the list interface. * * @param obj object to be wrapped/converted - * @param homeGlobal global to which this object belongs. Not used for ConsStrings. + * @param homeGlobal global to which this object belongs. * @return wrapped/converted object */ public static Object wrapAsJSONCompatible(final Object obj, final Object homeGlobal) { @@ -678,10 +677,10 @@ } /** - * Make a script object mirror on given object if needed. Also converts ConsString instances to Strings. + * Make a script object mirror on given object if needed. * * @param obj object to be wrapped/converted - * @param homeGlobal global to which this object belongs. Not used for ConsStrings. + * @param homeGlobal global to which this object belongs. * @param jsonCompatible if true, the created wrapper will implement the Java {@code List} interface if * {@code obj} is a JavaScript {@code Array} object. Arrays retrieved through its properties (transitively) * will also implement the list interface. diff -r 1c076468bf7d -r 696d662bcdb7 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/ScriptUtils.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/ScriptUtils.java Wed Jul 05 21:22:47 2017 +0200 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/ScriptUtils.java Thu Feb 25 13:56:23 2016 +0530 @@ -74,9 +74,15 @@ * @param func the function to wrap * @param sync the object to synchronize on * @return a synchronizing wrapper function + * @throws IllegalArgumentException if func does not represent a script function */ - public static Object makeSynchronizedFunction(final ScriptFunction func, final Object sync) { - return func.createSynchronized(unwrap(sync)); + public static Object makeSynchronizedFunction(final Object func, final Object sync) { + final Object unwrapped = unwrap(func); + if (unwrapped instanceof ScriptFunction) { + return ((ScriptFunction)unwrapped).createSynchronized(unwrap(sync)); + } + + throw new IllegalArgumentException(); } /** @@ -84,9 +90,19 @@ * * @param obj object to be wrapped * @return wrapped object + * @throws IllegalArgumentException if obj cannot be wrapped */ - public static ScriptObjectMirror wrap(final ScriptObject obj) { - return (ScriptObjectMirror) ScriptObjectMirror.wrap(obj, Context.getGlobal()); + public static ScriptObjectMirror wrap(final Object obj) { + if (obj instanceof ScriptObjectMirror) { + return (ScriptObjectMirror)obj; + } + + if (obj instanceof ScriptObject) { + final ScriptObject sobj = (ScriptObject)obj; + return (ScriptObjectMirror) ScriptObjectMirror.wrap(sobj, Context.getGlobal()); + } + + throw new IllegalArgumentException(); } /** @@ -135,7 +151,8 @@ * Convert the given object to the given type. * * @param obj object to be converted - * @param type destination type to convert to + * @param type destination type to convert to. type is either a Class + * or nashorn representation of a Java type returned by Java.type() call in script. * @return converted object */ public static Object convert(final Object obj, final Object type) { diff -r 1c076468bf7d -r 696d662bcdb7 nashorn/test/script/basic/JDK-8026367.js --- a/nashorn/test/script/basic/JDK-8026367.js Wed Jul 05 21:22:47 2017 +0200 +++ b/nashorn/test/script/basic/JDK-8026367.js Thu Feb 25 13:56:23 2016 +0530 @@ -37,10 +37,12 @@ // Sync called with one argument will synchronize on this-object of invocation inc: sync(function(d) { this.count += d; + Assert.assertTrue(java.lang.Thread.holdsLock(this)); }), // Pass explicit object to synchronize on as second argument dec: sync(function(d) { this.count -= d; + Assert.assertTrue(java.lang.Thread.holdsLock(obj)); }, obj) };