# HG changeset patch # User sundar # Date 1377086333 -19800 # Node ID 4085b74056ee9ca5eb77cea0b413085a32f1332e # Parent 6b73157185e05f5b178d1c38885db01c8a5e1950 8023368: Instance __proto__ property should exist and be writable. Reviewed-by: attila, hannesw diff -r 6b73157185e0 -r 4085b74056ee nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java --- a/nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java Wed Aug 21 13:39:40 2013 +0200 +++ b/nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java Wed Aug 21 17:28:53 2013 +0530 @@ -374,6 +374,19 @@ } /** + * Set the __proto__ of this object. + * @param proto new proto for this object + */ + public void setProto(final Object proto) { + inGlobal(new Callable() { + @Override public Void call() { + sobj.setProtoCheck(unwrap(proto, global)); + return null; + } + }); + } + + /** * ECMA 8.12.1 [[GetOwnProperty]] (P) * * @param key property key diff -r 6b73157185e0 -r 4085b74056ee nashorn/src/jdk/nashorn/internal/objects/NativeObject.java --- a/nashorn/src/jdk/nashorn/internal/objects/NativeObject.java Wed Aug 21 13:39:40 2013 +0200 +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeObject.java Wed Aug 21 17:28:53 2013 +0530 @@ -125,6 +125,28 @@ } /** + * Nashorn extension: Object.setPrototypeOf ( O, proto ) + * Also found in ES6 draft specification. + * + * @param self self reference + * @param obj object to set prototype for + * @param proto prototype object to be used + * @return object whose prototype is set + */ + @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) + public static Object setPrototypeOf(final Object self, final Object obj, final Object proto) { + if (obj instanceof ScriptObject) { + ((ScriptObject)obj).setProtoCheck(proto); + return obj; + } else if (obj instanceof ScriptObjectMirror) { + ((ScriptObjectMirror)obj).setProto(proto); + return obj; + } + + throw notAnObject(obj); + } + + /** * ECMA 15.2.3.3 Object.getOwnPropertyDescriptor ( O, P ) * * @param self self reference @@ -184,7 +206,7 @@ // FIXME: should we create a proper object with correct number of // properties? final ScriptObject newObj = Global.newEmptyInstance(); - newObj.setProtoCheck(proto); + newObj.setProto((ScriptObject)proto); if (props != UNDEFINED) { NativeObject.defineProperties(self, newObj, props); } diff -r 6b73157185e0 -r 4085b74056ee nashorn/src/jdk/nashorn/internal/runtime/PropertyListener.java --- a/nashorn/src/jdk/nashorn/internal/runtime/PropertyListener.java Wed Aug 21 13:39:40 2013 +0200 +++ b/nashorn/src/jdk/nashorn/internal/runtime/PropertyListener.java Wed Aug 21 17:28:53 2013 +0530 @@ -54,4 +54,13 @@ * */ public void propertyModified(ScriptObject object, Property oldProp, Property newProp); + + /** + * Given object's __proto__ has changed. + * + * @param object object whose __proto__ has changed. + * @param oldProto old __proto__ + * @param newProto new __proto__ + */ + public void protoChanged(ScriptObject object, ScriptObject oldProto, ScriptObject newProto); } diff -r 6b73157185e0 -r 4085b74056ee nashorn/src/jdk/nashorn/internal/runtime/PropertyListenerManager.java --- a/nashorn/src/jdk/nashorn/internal/runtime/PropertyListenerManager.java Wed Aug 21 13:39:40 2013 +0200 +++ b/nashorn/src/jdk/nashorn/internal/runtime/PropertyListenerManager.java Wed Aug 21 17:28:53 2013 +0530 @@ -140,6 +140,21 @@ } } + /** + * This method can be called to notify __proto__ modification to this object's listeners. + * + * @param object The ScriptObject whose __proto__ was changed. + * @param oldProto old __proto__ + * @param newProto new __proto__ + */ + protected synchronized final void notifyProtoChanged(final ScriptObject object, final ScriptObject oldProto, final ScriptObject newProto) { + if (listeners != null) { + for (PropertyListener listener : listeners.keySet()) { + listener.protoChanged(object, oldProto, newProto); + } + } + } + // PropertyListener methods @Override @@ -156,4 +171,9 @@ public final void propertyModified(final ScriptObject object, final Property oldProp, final Property newProp) { notifyPropertyModified(object, oldProp, newProp); } + + @Override + public final void protoChanged(final ScriptObject object, final ScriptObject oldProto, final ScriptObject newProto) { + notifyProtoChanged(object, oldProto, newProto); + } } diff -r 6b73157185e0 -r 4085b74056ee nashorn/src/jdk/nashorn/internal/runtime/PropertyMap.java --- a/nashorn/src/jdk/nashorn/internal/runtime/PropertyMap.java Wed Aug 21 13:39:40 2013 +0200 +++ b/nashorn/src/jdk/nashorn/internal/runtime/PropertyMap.java Wed Aug 21 17:28:53 2013 +0530 @@ -230,7 +230,7 @@ } /** - * Indicate that a prototype property hash changed. + * Indicate that a prototype property has changed. * * @param property {@link Property} to invalidate. */ @@ -251,6 +251,18 @@ } /** + * Indicate that proto itself has changed in hierachy somewhere. + */ + private void invalidateAllProtoGetSwitchPoints() { + assert !isShared() : "proto invalidation on a shared PropertyMap"; + + if (protoGetSwitches != null) { + final Collection sws = protoGetSwitches.values(); + SwitchPoint.invalidateAll(sws.toArray(new SwitchPoint[sws.size()])); + } + } + + /** * Add a property to the map, re-binding its getters and setters, * if available, to a given receiver. This is typically the global scope. See * {@link ScriptObject#addBoundProperties(ScriptObject)} @@ -878,6 +890,15 @@ invalidateProtoGetSwitchPoint(oldProp); } + @Override + public void protoChanged(final ScriptObject object, final ScriptObject oldProto, final ScriptObject newProto) { + // We may walk and invalidate SwitchPoints for properties inherited + // from 'object' or it's old proto chain. But, it may not be worth it. + // For example, a new proto may have a user defined getter/setter for + // a data property down the chain. So, invalidating all is better. + invalidateAllProtoGetSwitchPoints(); + } + /* * Debugging and statistics. */ diff -r 6b73157185e0 -r 4085b74056ee nashorn/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java Wed Aug 21 13:39:40 2013 +0200 +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java Wed Aug 21 17:28:53 2013 +0530 @@ -128,9 +128,6 @@ /** Do not support typed arrays. */ public final boolean _no_typed_arrays; - /** Package to which generated class files are added */ - public final String _package; - /** Only parse the source code, do not compile */ public final boolean _parse_only; @@ -216,7 +213,6 @@ _no_java = options.getBoolean("no.java"); _no_syntax_extensions = options.getBoolean("no.syntax.extensions"); _no_typed_arrays = options.getBoolean("no.typed.arrays"); - _package = options.getString("package"); _parse_only = options.getBoolean("parse.only"); _print_ast = options.getBoolean("print.ast"); _print_lower_ast = options.getBoolean("print.lower.ast"); diff -r 6b73157185e0 -r 4085b74056ee nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java Wed Aug 21 13:39:40 2013 +0200 +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java Wed Aug 21 17:28:53 2013 +0530 @@ -1129,6 +1129,9 @@ proto = newProto; if (isPrototype()) { + // tell listeners that my __proto__ has been changed + notifyProtoChanged(this, oldProto, newProto); + if (oldProto != null) { oldProto.removePropertyListener(this); } @@ -1144,7 +1147,19 @@ * @param newProto Prototype to set. */ public final void setProtoCheck(final Object newProto) { + if (!isExtensible()) { + throw typeError("__proto__.set.non.extensible", ScriptRuntime.safeToString(this)); + } + if (newProto == null || newProto instanceof ScriptObject) { + // check for circularity + ScriptObject proto = (ScriptObject)newProto; + while (proto != null) { + if (proto == this) { + throw typeError("circular.__proto__.set", ScriptRuntime.safeToString(this)); + } + proto = proto.getProto(); + } setProto((ScriptObject)newProto); } else { final ScriptObject global = Context.getGlobalTrusted(); diff -r 6b73157185e0 -r 4085b74056ee nashorn/src/jdk/nashorn/internal/runtime/resources/Messages.properties --- a/nashorn/src/jdk/nashorn/internal/runtime/resources/Messages.properties Wed Aug 21 13:39:40 2013 +0200 +++ b/nashorn/src/jdk/nashorn/internal/runtime/resources/Messages.properties Wed Aug 21 17:28:53 2013 +0530 @@ -94,6 +94,8 @@ type.error.cant.redefine.property=Cannot redefine property "{0}" of {1} type.error.property.not.writable="{0}" is not a writable property of {1} type.error.object.non.extensible=Cannot add new property "{0}" to non-extensible {1} +type.error.__proto__.set.non.extensible=Cannot set __proto__ of non-extensible {0} +type.error.circular.__proto__.set=Cannot create__proto__ cycle for {0} # miscellaneous type.error.regex.cant.supply.flags=Cannot supply flags when constructing one RegExp from another diff -r 6b73157185e0 -r 4085b74056ee nashorn/src/jdk/nashorn/internal/runtime/resources/Options.properties --- a/nashorn/src/jdk/nashorn/internal/runtime/resources/Options.properties Wed Aug 21 13:39:40 2013 +0200 +++ b/nashorn/src/jdk/nashorn/internal/runtime/resources/Options.properties Wed Aug 21 17:28:53 2013 +0530 @@ -216,15 +216,6 @@ default=false \ } -nashorn.option.package = { \ - name="--package", \ - is_undocumented=true, \ - desc="Package to which generated .class files are added.", \ - params="", \ - type=String, \ - default="" \ -} - nashorn.option.parse.only = { \ name="--parse-only", \ is_undocumented=true, \ diff -r 6b73157185e0 -r 4085b74056ee nashorn/src/jdk/nashorn/internal/runtime/resources/mozilla_compat.js --- a/nashorn/src/jdk/nashorn/internal/runtime/resources/mozilla_compat.js Wed Aug 21 13:39:40 2013 +0200 +++ b/nashorn/src/jdk/nashorn/internal/runtime/resources/mozilla_compat.js Wed Aug 21 17:28:53 2013 +0530 @@ -144,7 +144,7 @@ return Object.getPrototypeOf(this); }, set: function(x) { - throw new TypeError("__proto__ set not supported"); + Object.setPrototypeOf(this, x); } }); diff -r 6b73157185e0 -r 4085b74056ee nashorn/test/script/basic/JDK-8023368.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8023368.js Wed Aug 21 17:28:53 2013 +0530 @@ -0,0 +1,73 @@ +/* + * 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-8023368: Instance __proto__ property should exist and be writable. + * + * @test + * @run + */ + +load("nashorn:mozilla_compat.js"); + +// function to force same callsites +function check(obj) { + print(obj.func()); + print(obj.x); + print(obj.toString()); +} + +function Func() { +} + +Func.prototype.func = function() { + return "Func.prototype.func"; +} + +Func.prototype.x = "hello"; + +var obj = new Func(); +var obj2 = Object.create(obj); + +// check direct and indirect __proto__ change +check(obj); +check(obj2); +obj.__proto__ = { + func: function() { + return "obj.__proto__.func @ " + __LINE__; + }, + x: 344 +}; + +check(obj); +check(obj2); + +// check indirect (1 and 2 levels) __proto__ function change +obj.__proto__.__proto__ = { + toString: function() { + return "new object.toString"; + } +}; + +check(obj); +check(obj2); diff -r 6b73157185e0 -r 4085b74056ee nashorn/test/script/basic/JDK-8023368.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8023368.js.EXPECTED Wed Aug 21 17:28:53 2013 +0530 @@ -0,0 +1,18 @@ +Func.prototype.func +hello +[object Object] +Func.prototype.func +hello +[object Object] +obj.__proto__.func @ 57 +344 +[object Object] +obj.__proto__.func @ 57 +344 +[object Object] +obj.__proto__.func @ 57 +344 +new object.toString +obj.__proto__.func @ 57 +344 +new object.toString diff -r 6b73157185e0 -r 4085b74056ee nashorn/test/script/basic/JDK-8023368_2.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8023368_2.js Wed Aug 21 17:28:53 2013 +0530 @@ -0,0 +1,73 @@ +/* + * 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-8023368: Instance __proto__ property should exist and be writable. + * + * @test + * @run + */ + +// check Object.setPrototypeOf extension rather than using __proto__ + +// function to force same callsites +function check(obj) { + print(obj.func()); + print(obj.x); + print(obj.toString()); +} + +function Func() { +} + +Func.prototype.func = function() { + return "Func.prototype.func"; +} + +Func.prototype.x = "hello"; + +var obj = new Func(); +var obj2 = Object.create(obj); + +// check direct and indirect __proto__ change +check(obj); +check(obj2); +Object.setPrototypeOf(obj, { + func: function() { + return "obj.__proto__.func @ " + __LINE__; + }, + x: 344 +}); + +check(obj); +check(obj2); + +// check indirect (1 and 2 levels) __proto__ function change +Object.setPrototypeOf(Object.getPrototypeOf(obj), { + toString: function() { + return "new object.toString"; + } +}); + +check(obj); +check(obj2); diff -r 6b73157185e0 -r 4085b74056ee nashorn/test/script/basic/JDK-8023368_2.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8023368_2.js.EXPECTED Wed Aug 21 17:28:53 2013 +0530 @@ -0,0 +1,18 @@ +Func.prototype.func +hello +[object Object] +Func.prototype.func +hello +[object Object] +obj.__proto__.func @ 57 +344 +[object Object] +obj.__proto__.func @ 57 +344 +[object Object] +obj.__proto__.func @ 57 +344 +new object.toString +obj.__proto__.func @ 57 +344 +new object.toString diff -r 6b73157185e0 -r 4085b74056ee nashorn/test/script/basic/circular_proto.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/circular_proto.js Wed Aug 21 17:28:53 2013 +0530 @@ -0,0 +1,46 @@ +/* + * 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-8023368: Instance __proto__ property should exist and be writable. + * + * @test + * @run + */ + +// check that we cannot create __proto__ cycle +load("nashorn:mozilla_compat.js"); + +var obj = {}; +var obj2 = Object.create(obj); + +// attempt to create __proto__ cycle +try { + obj.__proto__ = obj2; + fail("Should have thrown TypeError"); +} catch (e) { + if (! (e instanceof TypeError)) { + fail("Expected TypeError, got " + e); + } + print(e); +} diff -r 6b73157185e0 -r 4085b74056ee nashorn/test/script/basic/circular_proto.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/circular_proto.js.EXPECTED Wed Aug 21 17:28:53 2013 +0530 @@ -0,0 +1,1 @@ +TypeError: Cannot create__proto__ cycle for [object Object] diff -r 6b73157185e0 -r 4085b74056ee nashorn/test/script/basic/mirror_proto_assign.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/mirror_proto_assign.js Wed Aug 21 17:28:53 2013 +0530 @@ -0,0 +1,52 @@ +/* + * 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-8023368: Instance __proto__ property should exist and be writable. + * + * @test + * @run + */ + +// check that Object.setPrototypeOf works for mirror objects as well. + +var global = loadWithNewGlobal({ + name: "test", + script: "var obj = {}; this" +}); + +var proto = global.eval("({ foo: 323 })"); + +Object.setPrototypeOf(global.obj, proto); + +function func(obj) { + // check proto inherited value + print("obj.foo = " + obj.foo); +} + +func(global.obj); + +var newProto = global.eval("({ foo: 'hello' })"); +Object.setPrototypeOf(global.obj, newProto); + +func(global.obj); diff -r 6b73157185e0 -r 4085b74056ee nashorn/test/script/basic/mirror_proto_assign.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/mirror_proto_assign.js.EXPECTED Wed Aug 21 17:28:53 2013 +0530 @@ -0,0 +1,2 @@ +obj.foo = 323 +obj.foo = hello diff -r 6b73157185e0 -r 4085b74056ee nashorn/test/script/basic/nonextensible_proto_assign.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/nonextensible_proto_assign.js Wed Aug 21 17:28:53 2013 +0530 @@ -0,0 +1,44 @@ +/* + * 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-8023368: Instance __proto__ property should exist and be writable. + * + * @test + * @run + */ + +load("nashorn:mozilla_compat.js") + +// check that we cannot assign to __proto__ of a non-extensible object +try { + var obj = {} + Object.preventExtensions(obj); + obj.__proto__ = { }; + fail("Should have thrown TypeError"); +} catch (e) { + if (! (e instanceof TypeError)) { + fail("Expected TypeError, got " + e); + } + print(e); +} diff -r 6b73157185e0 -r 4085b74056ee nashorn/test/script/basic/nonextensible_proto_assign.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/nonextensible_proto_assign.js.EXPECTED Wed Aug 21 17:28:53 2013 +0530 @@ -0,0 +1,1 @@ +TypeError: Cannot set __proto__ of non-extensible [object Object]