Bug 603201 - Enable primitive receivers in [[Set]]. r=jorendorff

This commit is contained in:
Jason Orendorff 2015-03-01 13:37:42 -06:00
parent d3cc5fb902
commit 8d8cb64993
6 changed files with 58 additions and 62 deletions

View File

@ -1059,7 +1059,8 @@ function traverse (node, cb) {
cb(node);
keys(node).map(key => {
if (key === 'parent' || !node[key]) return;
node[key].parent = node;
if (typeof node[key] === "object")
node[key].parent = node;
traverse(node[key], cb);
});
}

View File

@ -2766,7 +2766,7 @@ DoSetElemFallback(JSContext* cx, BaselineFrame* frame, ICSetElem_Fallback* stub_
if (!InitArrayElemOperation(cx, pc, obj, index.toInt32(), rhs))
return false;
} else {
if (!SetObjectElement(cx, obj, index, rhs, JSOp(*pc) == JSOP_STRICTSETELEM, script, pc))
if (!SetObjectElement(cx, obj, index, rhs, objv, JSOp(*pc) == JSOP_STRICTSETELEM, script, pc))
return false;
}
@ -4777,9 +4777,12 @@ DoSetPropFallback(JSContext* cx, BaselineFrame* frame, ICSetProp_Fallback* stub_
} else {
MOZ_ASSERT(op == JSOP_SETPROP || op == JSOP_STRICTSETPROP);
RootedValue v(cx, rhs);
if (!PutProperty(cx, obj, id, v, op == JSOP_STRICTSETPROP))
ObjectOpResult result;
if (!SetProperty(cx, obj, id, rhs, lhs, result) ||
!result.checkStrictErrorOrWarning(cx, obj, id, op == JSOP_STRICTSETPROP))
{
return false;
}
}
// Leave the RHS on the stack.

View File

@ -7,34 +7,36 @@
#include "jsapi-tests/tests.h"
using namespace JS;
BEGIN_TEST(testForwardSetProperty)
{
JS::RootedValue v1(cx);
RootedValue v1(cx);
EVAL("var foundValue; \n"
"var obj1 = { set prop(val) { foundValue = this; } }; \n"
"obj1;",
&v1);
JS::RootedValue v2(cx);
RootedValue v2(cx);
EVAL("var obj2 = Object.create(obj1); \n"
"obj2;",
&v2);
JS::RootedValue v3(cx);
RootedValue v3(cx);
EVAL("var obj3 = {}; \n"
"obj3;",
&v3);
JS::RootedObject obj1(cx, &v1.toObject());
JS::RootedObject obj2(cx, &v2.toObject());
JS::RootedObject obj3(cx, &v3.toObject());
RootedObject obj1(cx, &v1.toObject());
RootedObject obj2(cx, &v2.toObject());
RootedObject obj3(cx, &v3.toObject());
JS::RootedValue setval(cx, JS::Int32Value(42));
RootedValue setval(cx, Int32Value(42));
JS::RootedValue propkey(cx);
RootedValue propkey(cx);
EVAL("'prop';", &propkey);
JS::RootedId prop(cx);
RootedId prop(cx);
CHECK(JS_ValueToId(cx, propkey, &prop));
EXEC("function assertEq(a, b, msg) \n"
@ -68,42 +70,20 @@ BEGIN_TEST(testForwardSetProperty)
// Strict setter
EVAL("obj1 = { set prop(val) { 'use strict'; foundValue = this; } }; \n"
"obj1;",
&v1);
RootedValue v4(cx);
EVAL("({ set prop(val) { 'use strict'; foundValue = this; } })", &v4);
RootedObject obj4(cx, &v4.toObject());
CHECK(JS_ForwardSetPropertyTo(cx, obj2, prop, setval, v3, result));
CHECK(JS_ForwardSetPropertyTo(cx, obj4, prop, setval, v3, result));
CHECK(result);
EXEC("assertEq(foundValue, obj3, 'wrong receiver passed to strict setter');");
CHECK(JS_ForwardSetPropertyTo(cx, obj2, prop, setval, setval, result));
CHECK(JS_ForwardSetPropertyTo(cx, obj4, prop, setval, setval, result));
CHECK(result);
JS::RootedValue strictSetSupported(cx);
EVAL("var strictSetSupported = false; \n"
"Object.defineProperty(Object.prototype, \n"
" 'strictSetter', \n"
" { \n"
" set(v) { \n"
" 'use strict'; \n"
" strictSetSupported = \n"
" typeof this === 'number'; \n"
" } \n"
" }); \n"
"17..strictSetter = 42; \n"
"strictSetSupported;",
&strictSetSupported);
CHECK(strictSetSupported.isBoolean());
if (strictSetSupported.toBoolean()) {
// XXX Bug 603201 will fix this.
MOZ_ASSERT(false,
"remove the support-testing check when bug 603201 is fixt");
EXEC("assertEq(foundValue, 42, \n"
" '42 passed as receiver to strict setter ' + \n"
" 'was mangled');");
}
EXEC("assertEq(foundValue, 42, \n"
" '42 passed as receiver to strict setter was mangled');");
return true;
}

View File

@ -27,9 +27,8 @@ Object.defineProperty(Symbol.prototype, "prop", {
set: function (v) {
"use strict";
sets++;
assertEq(typeof this, "object");
assertEq(this instanceof Symbol, true);
assertEq(this.valueOf(), sym);
assertEq(typeof this, "symbol");
assertEq(this, sym);
assertEq(v, "newvalue");
}
});

View File

@ -282,11 +282,8 @@ SetPropertyOperation(JSContext* cx, JSOp op, HandleValue lval, HandleId id, Hand
if (!obj)
return false;
// Note: ES6 specifies that the value lval, not obj, is passed as receiver
// to obj's [[Set]] internal method. See bug 603201.
RootedValue receiver(cx, ObjectValue(*obj));
ObjectOpResult result;
return SetProperty(cx, obj, id, rval, receiver, result) &&
return SetProperty(cx, obj, id, rval, lval, result) &&
result.checkStrictErrorOrWarning(cx, obj, id, op == JSOP_STRICTSETPROP);
}
@ -1409,9 +1406,9 @@ ModOperation(JSContext* cx, HandleValue lhs, HandleValue rhs, MutableHandleValue
}
static MOZ_ALWAYS_INLINE bool
SetObjectElementOperation(JSContext* cx, HandleObject obj, HandleValue receiver, HandleId id,
const Value& value, bool strict, JSScript* script = nullptr,
jsbytecode* pc = nullptr)
SetObjectElementOperation(JSContext* cx, HandleObject obj, HandleId id, HandleValue value,
HandleValue receiver, bool strict,
JSScript* script = nullptr, jsbytecode* pc = nullptr)
{
// receiver != obj happens only at super[expr], where we expect to find the property
// People probably aren't building hashtables with |super| anyway.
@ -1430,9 +1427,8 @@ SetObjectElementOperation(JSContext* cx, HandleObject obj, HandleValue receiver,
if (obj->isNative() && !JSID_IS_INT(id) && !obj->setHadElementsAccess(cx))
return false;
RootedValue tmp(cx, value);
ObjectOpResult result;
return SetProperty(cx, obj, id, tmp, receiver, result) &&
return SetProperty(cx, obj, id, value, receiver, result) &&
result.checkStrictErrorOrWarning(cx, obj, id, strict);
}
@ -2677,13 +2673,15 @@ CASE(JSOP_STRICTSETELEM)
{
static_assert(JSOP_SETELEM_LENGTH == JSOP_STRICTSETELEM_LENGTH,
"setelem and strictsetelem must be the same size");
HandleValue receiver = REGS.stackHandleAt(-3);
ReservedRooted<JSObject*> obj(&rootObject0);
FETCH_OBJECT(cx, -3, obj);
obj = ToObjectFromStack(cx, receiver);
if (!obj)
goto error;
ReservedRooted<jsid> id(&rootId0);
FETCH_ELEMENT_ID(-2, id);
Value& value = REGS.sp[-1];
ReservedRooted<Value> receiver(&rootValue0, ObjectValue(*obj));
if (!SetObjectElementOperation(cx, obj, receiver, id, value, *REGS.pc == JSOP_STRICTSETELEM))
HandleValue value = REGS.stackHandleAt(-1);
if (!SetObjectElementOperation(cx, obj, id, value, receiver, *REGS.pc == JSOP_STRICTSETELEM))
goto error;
REGS.sp[-3] = value;
REGS.sp -= 2;
@ -2700,10 +2698,10 @@ CASE(JSOP_STRICTSETELEM_SUPER)
FETCH_ELEMENT_ID(-4, id);
ReservedRooted<Value> receiver(&rootValue0, REGS.sp[-3]);
ReservedRooted<JSObject*> obj(&rootObject1, &REGS.sp[-2].toObject());
Value& value = REGS.sp[-1];
HandleValue value = REGS.stackHandleAt(-1);
bool strict = JSOp(*REGS.pc) == JSOP_STRICTSETELEM_SUPER;
if (!SetObjectElementOperation(cx, obj, receiver, id, value, strict))
if (!SetObjectElementOperation(cx, obj, id, value, receiver, strict))
goto error;
REGS.sp[-4] = value;
REGS.sp -= 3;
@ -4333,7 +4331,7 @@ js::SetObjectElement(JSContext* cx, HandleObject obj, HandleValue index, HandleV
if (!ToPropertyKey(cx, index, &id))
return false;
RootedValue receiver(cx, ObjectValue(*obj));
return SetObjectElementOperation(cx, obj, receiver, id, value, strict);
return SetObjectElementOperation(cx, obj, id, value, receiver, strict);
}
bool
@ -4345,7 +4343,18 @@ js::SetObjectElement(JSContext* cx, HandleObject obj, HandleValue index, HandleV
if (!ToPropertyKey(cx, index, &id))
return false;
RootedValue receiver(cx, ObjectValue(*obj));
return SetObjectElementOperation(cx, obj, receiver, id, value, strict, script, pc);
return SetObjectElementOperation(cx, obj, id, value, receiver, strict, script, pc);
}
bool
js::SetObjectElement(JSContext* cx, HandleObject obj, HandleValue index, HandleValue value,
HandleValue receiver, bool strict, HandleScript script, jsbytecode* pc)
{
MOZ_ASSERT(pc);
RootedId id(cx);
if (!ToPropertyKey(cx, index, &id))
return false;
return SetObjectElementOperation(cx, obj, id, value, receiver, strict, script, pc);
}
bool

View File

@ -369,6 +369,10 @@ bool
SetObjectElement(JSContext* cx, HandleObject obj, HandleValue index, HandleValue value,
bool strict, HandleScript script, jsbytecode* pc);
bool
SetObjectElement(JSContext* cx, HandleObject obj, HandleValue index, HandleValue value,
HandleValue receiver, bool strict, HandleScript script, jsbytecode* pc);
bool
InitElementArray(JSContext* cx, jsbytecode* pc,
HandleObject obj, uint32_t index, HandleValue value);