提交 2721ef00 编写于 作者: S sundar

8023368: Instance __proto__ property should exist and be writable.

Reviewed-by: attila, hannesw
上级 3de49f15
......@@ -373,6 +373,19 @@ public final class ScriptObjectMirror extends JSObject implements Bindings {
});
}
/**
* Set the __proto__ of this object.
* @param proto new proto for this object
*/
public void setProto(final Object proto) {
inGlobal(new Callable<Void>() {
@Override public Void call() {
sobj.setProtoCheck(unwrap(proto, global));
return null;
}
});
}
/**
* ECMA 8.12.1 [[GetOwnProperty]] (P)
*
......
......@@ -124,6 +124,28 @@ public final class NativeObject {
}
}
/**
* 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 )
*
......@@ -184,7 +206,7 @@ public final class NativeObject {
// 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);
}
......
......@@ -54,4 +54,13 @@ public interface PropertyListener {
*
*/
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);
}
......@@ -140,6 +140,21 @@ public class PropertyListenerManager implements PropertyListener {
}
}
/**
* 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 class PropertyListenerManager implements PropertyListener {
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);
}
}
......@@ -230,7 +230,7 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
}
/**
* Indicate that a prototype property hash changed.
* Indicate that a prototype property has changed.
*
* @param property {@link Property} to invalidate.
*/
......@@ -250,6 +250,18 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
}
}
/**
* 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<SwitchPoint> 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
......@@ -878,6 +890,15 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
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.
*/
......
......@@ -128,9 +128,6 @@ public final class ScriptEnvironment {
/** 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 @@ public final class ScriptEnvironment {
_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");
......
......@@ -1129,6 +1129,9 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
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 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
* @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();
......
......@@ -94,6 +94,8 @@ type.error.cant.delete.property=Cannot delete property "{0}" of {1}
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
......
......@@ -216,15 +216,6 @@ nashorn.option.no.typed.arrays = { \
default=false \
}
nashorn.option.package = { \
name="--package", \
is_undocumented=true, \
desc="Package to which generated .class files are added.", \
params="<package>", \
type=String, \
default="" \
}
nashorn.option.parse.only = { \
name="--parse-only", \
is_undocumented=true, \
......
......@@ -144,7 +144,7 @@ Object.defineProperty(Object.prototype, "__proto__", {
return Object.getPrototypeOf(this);
},
set: function(x) {
throw new TypeError("__proto__ set not supported");
Object.setPrototypeOf(this, x);
}
});
......
/*
* 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);
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
/*
* 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);
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
/*
* 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);
}
TypeError: Cannot create__proto__ cycle for [object Object]
/*
* 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);
/*
* 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);
}
TypeError: Cannot set __proto__ of non-extensible [object Object]
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册