author | Eddy Bruel <ejpbruel@mozilla.com> |
Fri, 22 Mar 2013 19:43:12 -0700 | |
changeset 126572 | 2e564ec4c11d2cbc37a43e1247c4c72078ebcb24 |
parent 126571 | 804c5ca59d99e89c7ee1e1d223a6ceafd34e0b65 |
child 126573 | 321ce1200edea58447113365dd89f6257136a664 |
push id | 24488 |
push user | ryanvm@gmail.com |
push date | Fri, 29 Mar 2013 00:54:52 +0000 |
treeherder | mozilla-central@8aeabe064932 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | jwalden, jorendorff |
bugs | 789897 |
milestone | 22.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/js/src/jit-test/tests/proxy/testDirectProxyDefineProperty2.js +++ b/js/src/jit-test/tests/proxy/testDirectProxyDefineProperty2.js @@ -19,10 +19,17 @@ var handler = { } } var desc = { value: 'bar', writable: true, enumerable: false, configurable: true }; -Object.defineProperty(new Proxy(target, handler), 'foo', desc); + +var p = new Proxy(target, handler); +Object.defineProperty(p, 'foo', desc); assertEq(called, true); +assertEq(Object.isExtensible(target), true); +assertEq(Object.isExtensible(p), true); +Object.preventExtensions(target); +assertEq(Object.isExtensible(target), false); +assertEq(Object.isExtensible(p), false);
new file mode 100644 --- /dev/null +++ b/js/src/jit-test/tests/proxy/testDirectProxyPreventExtensions1.js @@ -0,0 +1,4 @@ +// Forward to the target if the trap is not defined +var target = {}; +Object.preventExtensions(new Proxy(target, {})); +assertEq(Object.isExtensible(target), false);
new file mode 100644 --- /dev/null +++ b/js/src/jit-test/tests/proxy/testDirectProxyPreventExtensions2.js @@ -0,0 +1,17 @@ +/* + * Call the trap with the handler as the this value and the target as the first + * argument. + */ +var target = {}; +var called = false; +var handler = { + preventExtensions: function (target1) { + assertEq(this, handler); + assertEq(target1, target); + Object.preventExtensions(target1); + called = true; + return true; + } +}; +Object.preventExtensions(new Proxy(target, handler)); +assertEq(called, true);
new file mode 100644 --- /dev/null +++ b/js/src/jit-test/tests/proxy/testDirectProxyPreventExtensions3.js @@ -0,0 +1,10 @@ +load(libdir + "asserts.js"); + +// Throw a TypeError if the trap reports an extensible object as non-extensible +assertThrowsInstanceOf(function () { + Object.preventExtensions(new Proxy({}, { + preventExtensions: function () { + return true; + } + })); +}, TypeError);
new file mode 100644 --- /dev/null +++ b/js/src/jit-test/tests/proxy/testDirectProxyPreventExtensions4.js @@ -0,0 +1,10 @@ +load(libdir + "asserts.js"); + +// Throw a TypeError if the object refuses to be made non-extensible +assertThrowsInstanceOf(function () { + Object.preventExtensions(new Proxy({}, { + preventExtensions: function () { + return false; + } + })); +}, TypeError);
--- a/js/src/js.msg +++ b/js/src/js.msg @@ -230,17 +230,17 @@ MSG_DEF(JSMSG_UNUSED176, 17 MSG_DEF(JSMSG_UNUSED177, 177, 0, JSEXN_NONE, "") MSG_DEF(JSMSG_UNUSED178, 178, 0, JSEXN_NONE, "") MSG_DEF(JSMSG_UNUSED179, 179, 0, JSEXN_NONE, "") MSG_DEF(JSMSG_UNUSED180, 180, 0, JSEXN_NONE, "") MSG_DEF(JSMSG_UNUSED181, 181, 0, JSEXN_NONE, "") MSG_DEF(JSMSG_BAD_GENERATOR_SEND, 182, 1, JSEXN_TYPEERR, "attempt to send {0} to newborn generator") MSG_DEF(JSMSG_UNUSED183, 183, 0, JSEXN_NONE, "") MSG_DEF(JSMSG_UNUSED184, 184, 0, JSEXN_NONE, "") -MSG_DEF(JSMSG_UNUSED185, 185, 0, JSEXN_NONE, "") +MSG_DEF(JSMSG_CANT_REPORT_AS_NON_EXTENSIBLE, 185, 0, JSEXN_TYPEERR, "proxy can't report an extensible object as non-extensible") MSG_DEF(JSMSG_UNUSED186, 186, 0, JSEXN_NONE, "") MSG_DEF(JSMSG_UNUSED187, 187, 0, JSEXN_NONE, "") MSG_DEF(JSMSG_INCOMPATIBLE_METHOD, 188, 3, JSEXN_TYPEERR, "{0} {1} called on incompatible {2}") MSG_DEF(JSMSG_UNUSED189, 189, 0, JSEXN_NONE, "") MSG_DEF(JSMSG_UNUSED190, 190, 0, JSEXN_NONE, "") MSG_DEF(JSMSG_UNUSED191, 191, 0, JSEXN_NONE, "") MSG_DEF(JSMSG_UNUSED192, 192, 0, JSEXN_NONE, "") MSG_DEF(JSMSG_BAD_FOR_EACH_LOOP, 193, 0, JSEXN_SYNTAXERR, "invalid for each loop")
--- a/js/src/jsproxy.cpp +++ b/js/src/jsproxy.cpp @@ -1039,16 +1039,17 @@ GetDirectProxyHandlerObject(JSObject *pr /* Derived class for all scripted direct proxy handlers. */ class ScriptedDirectProxyHandler : public DirectProxyHandler { public: ScriptedDirectProxyHandler(); virtual ~ScriptedDirectProxyHandler(); /* ES5 Harmony fundamental proxy traps. */ + virtual bool preventExtensions(JSContext *cx, HandleObject proxy) MOZ_OVERRIDE; virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id, PropertyDescriptor *desc, unsigned flags) MOZ_OVERRIDE; virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id, PropertyDescriptor *desc, unsigned flags) MOZ_OVERRIDE; virtual bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id, PropertyDescriptor *desc) MOZ_OVERRIDE; virtual bool getOwnPropertyNames(JSContext *cx, HandleObject proxy, AutoIdVector &props); virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) MOZ_OVERRIDE; @@ -1607,16 +1608,58 @@ ScriptedDirectProxyHandler::ScriptedDire : DirectProxyHandler(&sScriptedDirectProxyHandlerFamily) { } ScriptedDirectProxyHandler::~ScriptedDirectProxyHandler() { } +bool +ScriptedDirectProxyHandler::preventExtensions(JSContext *cx, HandleObject proxy) +{ + // step a + RootedObject handler(cx, GetDirectProxyHandlerObject(proxy)); + + // step b + RootedObject target(cx, GetProxyTargetObject(proxy)); + + // step c + RootedValue trap(cx); + if (!JSObject::getProperty(cx, handler, handler, cx->names().preventExtensions, &trap)) + return false; + + // step d + if (trap.isUndefined()) + return DirectProxyHandler::preventExtensions(cx, proxy); + + // step e + Value argv[] = { + ObjectValue(*target) + }; + RootedValue trapResult(cx); + if (!Invoke(cx, ObjectValue(*handler), trap, 1, argv, trapResult.address())) + return false; + + // step f + bool success = ToBoolean(trapResult); + if (success) { + // step g + if (target->isExtensible()) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_REPORT_AS_NON_EXTENSIBLE); + return false; + } + return true; + } + + // step h + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_CHANGE_EXTENSIBILITY); + return false; +} + // FIXME: Move to Proxy::getPropertyDescriptor once ScriptedIndirectProxy is removed bool ScriptedDirectProxyHandler::getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id, PropertyDescriptor *desc, unsigned flags) { JS_CHECK_RECURSION(cx, return false); if (!GetOwnPropertyDescriptor(cx, proxy, id, desc))
--- a/js/src/vm/CommonPropertyNames.h +++ b/js/src/vm/CommonPropertyNames.h @@ -109,16 +109,17 @@ macro(numeric, numeric, "numeric") \ macro(objectNull, objectNull, "[object Null]") \ macro(objectUndefined, objectUndefined, "[object Undefined]") \ macro(of, of, "of") \ macro(offset, offset, "offset") \ macro(parseFloat, parseFloat, "parseFloat") \ macro(parseInt, parseInt, "parseInt") \ macro(pattern, pattern, "pattern") \ + macro(preventExtensions, preventExtensions, "preventExtensions") \ macro(propertyIsEnumerable, propertyIsEnumerable, "propertyIsEnumerable") \ macro(proto, proto, "__proto__") \ macro(return, return_, "return") \ macro(sensitivity, sensitivity, "sensitivity") \ macro(set, set, "set") \ macro(shape, shape, "shape") \ macro(source, source, "source") \ macro(stack, stack, "stack") \