зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1377051 - Support JSOP_SETPROP_SUPER in Baseline r=jandem
MozReview-Commit-ID: LNOVCntYDsM --HG-- extra : rebase_source : 987cd42d72fc3beca649025295a9ac725c31b88b
This commit is contained in:
Родитель
d4a17dec07
Коммит
3e2612fce6
|
@ -0,0 +1,64 @@
|
|||
var g_foo = "foo";
|
||||
var g_bar = "bar";
|
||||
|
||||
// Define base class with a read-only and a writable data property
|
||||
class Base
|
||||
{
|
||||
}
|
||||
Object.defineProperty(Base.prototype, "foo", { value: "Base", writable: true });
|
||||
Object.defineProperty(Base.prototype, "bar", { value: "Base", writable: false });
|
||||
|
||||
// Test various cases that should throw during SETPROP_SUPER
|
||||
class Derived extends Base
|
||||
{
|
||||
// ECMA-2018 9.1.9.1, step 4.a
|
||||
testReadonly() {
|
||||
super.bar = "Derived";
|
||||
}
|
||||
testReadonlyElem() {
|
||||
super[g_bar] = "Derived";
|
||||
}
|
||||
|
||||
// ECMA-2018 9.1.9.1, step 4.b
|
||||
testPrimitiveReceiver() {
|
||||
super.foo = "Derived";
|
||||
}
|
||||
testPrimitiveReceiverElem() {
|
||||
super[g_foo] = "Derived";
|
||||
}
|
||||
|
||||
// ECMA-2018 9.1.9.1, step 4.d.i
|
||||
testAccessorShadow() {
|
||||
Object.defineProperty(this, "foo", { get: function() { } });
|
||||
super.foo = "Derived";
|
||||
}
|
||||
testAccessorShadowElem() {
|
||||
Object.defineProperty(this, "foo", { get: function() { } });
|
||||
super[g_foo] = "Derived";
|
||||
}
|
||||
|
||||
// ECMA-2018 9.1.9.1, step 4.d.ii
|
||||
testReadonlyShadow() {
|
||||
Object.defineProperty(this, "foo", { writable: false });
|
||||
super.foo = "Derived";
|
||||
}
|
||||
testReadonlyShadowElem() {
|
||||
Object.defineProperty(this, "foo", { writable: false });
|
||||
super[g_foo] = "Derived";
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < 10; ++i) {
|
||||
var cnt = 0;
|
||||
|
||||
try { new Derived().testReadonly(); } catch(e) { cnt++; }
|
||||
try { new Derived().testReadonlyElem(); } catch(e) { cnt++; }
|
||||
try { Derived.prototype.testPrimitiveReceiver.call(null); } catch(e) { cnt++; }
|
||||
try { Derived.prototype.testPrimitiveReceiverElem.call(null); } catch(e) { cnt++; }
|
||||
try { new Derived().testAccessorShadow(); } catch(e) { cnt++; }
|
||||
try { new Derived().testAccessorShadowElem(); } catch(e) { cnt++; }
|
||||
try { new Derived().testReadonlyShadow(); } catch(e) { cnt++; }
|
||||
try { new Derived().testReadonlyShadowElem(); } catch(e) { cnt++; }
|
||||
|
||||
assertEq(cnt, 8);
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
|
||||
class Base
|
||||
{
|
||||
set setter(val) {
|
||||
this.set_val = val;
|
||||
this.set_this = this;
|
||||
}
|
||||
}
|
||||
Base.prototype.prop = "Base";
|
||||
|
||||
class Derived extends Base
|
||||
{
|
||||
set setter(val) { super.setter = val; }
|
||||
setelem(pname, val) { super[pname] = val; }
|
||||
}
|
||||
|
||||
// Test SETPROP_SUPER invoke setters correctly
|
||||
function testSetterChain() {
|
||||
let d = new Derived();
|
||||
|
||||
for (let i = 0; i < 10; ++i)
|
||||
{
|
||||
d.setter = i;
|
||||
assertEq(d.set_val, i);
|
||||
assertEq(d.set_this, d);
|
||||
}
|
||||
}
|
||||
function testSetterChainElem() {
|
||||
let d = new Derived();
|
||||
|
||||
for (let i = 0; i < 10; ++i)
|
||||
{
|
||||
d.setelem("setter", i);
|
||||
assertEq(d.set_val, i);
|
||||
assertEq(d.set_this, d);
|
||||
}
|
||||
}
|
||||
|
||||
// Test that SETPROP_SUPER modifies |this| and not home object
|
||||
function testSuperSetProp() {
|
||||
let d = new Derived();
|
||||
|
||||
for (let i = 0; i < 10; ++i)
|
||||
{
|
||||
d.prop = i;
|
||||
assertEq(d.prop, i);
|
||||
assertEq(d.hasOwnProperty("prop"), true);
|
||||
assertEq(Derived.prototype.prop, "Base");
|
||||
}
|
||||
}
|
||||
function testSuperSetPropElem() {
|
||||
let d = new Derived();
|
||||
|
||||
for (let i = 0; i < 10; ++i)
|
||||
{
|
||||
d.setelem("prop", i);
|
||||
assertEq(d.prop, i);
|
||||
assertEq(d.hasOwnProperty("prop"), true);
|
||||
assertEq(Derived.prototype.prop, "Base");
|
||||
}
|
||||
}
|
||||
|
||||
testSetterChain();
|
||||
testSetterChainElem();
|
||||
|
||||
testSuperSetProp();
|
||||
testSuperSetPropElem();
|
|
@ -2546,6 +2546,46 @@ BaselineCompiler::emit_JSOP_STRICTSETGNAME()
|
|||
return emit_JSOP_SETPROP();
|
||||
}
|
||||
|
||||
typedef bool (*SetPropertySuperFn)(JSContext*, HandleObject, HandleValue,
|
||||
HandlePropertyName, HandleValue, bool);
|
||||
static const VMFunction SetPropertySuperInfo =
|
||||
FunctionInfo<SetPropertySuperFn>(js::SetPropertySuper, "SetPropertySuper");
|
||||
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_SETPROP_SUPER()
|
||||
{
|
||||
bool strict = IsCheckStrictOp(JSOp(*pc));
|
||||
|
||||
// Incoming stack is |receiver, obj, rval|. We need to shuffle stack to
|
||||
// leave rval when operation is complete.
|
||||
|
||||
// Pop rval into R0, then load receiver into R1 and replace with rval.
|
||||
frame.popRegsAndSync(1);
|
||||
masm.loadValue(frame.addressOfStackValue(frame.peek(-2)), R1);
|
||||
masm.storeValue(R0, frame.addressOfStackValue(frame.peek(-2)));
|
||||
|
||||
prepareVMCall();
|
||||
|
||||
pushArg(Imm32(strict));
|
||||
pushArg(R0); // rval
|
||||
pushArg(ImmGCPtr(script->getName(pc)));
|
||||
pushArg(R1); // receiver
|
||||
masm.unboxObject(frame.addressOfStackValue(frame.peek(-1)), R0.scratchReg());
|
||||
pushArg(R0.scratchReg()); // obj
|
||||
|
||||
if (!callVM(SetPropertySuperInfo))
|
||||
return false;
|
||||
|
||||
frame.pop();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_STRICTSETPROP_SUPER()
|
||||
{
|
||||
return emit_JSOP_SETPROP_SUPER();
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_GETPROP()
|
||||
{
|
||||
|
|
|
@ -138,6 +138,8 @@ namespace jit {
|
|||
_(JSOP_DELPROP) \
|
||||
_(JSOP_STRICTDELPROP) \
|
||||
_(JSOP_GETPROP_SUPER) \
|
||||
_(JSOP_SETPROP_SUPER) \
|
||||
_(JSOP_STRICTSETPROP_SUPER) \
|
||||
_(JSOP_LENGTH) \
|
||||
_(JSOP_GETBOUNDNAME) \
|
||||
_(JSOP_GETALIASEDVAR) \
|
||||
|
|
|
@ -2868,18 +2868,14 @@ CASE(JSOP_STRICTSETPROP_SUPER)
|
|||
static_assert(JSOP_SETPROP_SUPER_LENGTH == JSOP_STRICTSETPROP_SUPER_LENGTH,
|
||||
"setprop-super and strictsetprop-super must be the same size");
|
||||
|
||||
|
||||
ReservedRooted<Value> receiver(&rootValue0, REGS.sp[-3]);
|
||||
ReservedRooted<JSObject*> obj(&rootObject0, ®S.sp[-2].toObject());
|
||||
ReservedRooted<Value> rval(&rootValue1, REGS.sp[-1]);
|
||||
ReservedRooted<jsid> id(&rootId0, NameToId(script->getName(REGS.pc)));
|
||||
|
||||
ObjectOpResult result;
|
||||
if (!SetProperty(cx, obj, id, rval, receiver, result))
|
||||
goto error;
|
||||
ReservedRooted<PropertyName*> name(&rootName0, script->getName(REGS.pc));
|
||||
|
||||
bool strict = JSOp(*REGS.pc) == JSOP_STRICTSETPROP_SUPER;
|
||||
if (!result.checkStrictErrorOrWarning(cx, obj, id, strict))
|
||||
|
||||
if (!SetPropertySuper(cx, obj, receiver, name, rval, strict))
|
||||
goto error;
|
||||
|
||||
REGS.sp[-3] = REGS.sp[-1];
|
||||
|
@ -5257,3 +5253,15 @@ js::ThrowInitializedThis(JSContext* cx, AbstractFramePtr frame)
|
|||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_REINIT_THIS);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
js::SetPropertySuper(JSContext* cx, HandleObject obj, HandleValue receiver,
|
||||
HandlePropertyName name, HandleValue rval, bool strict)
|
||||
{
|
||||
RootedId id(cx, NameToId(name));
|
||||
ObjectOpResult result;
|
||||
if (!SetProperty(cx, obj, id, rval, receiver, result))
|
||||
return false;
|
||||
|
||||
return result.checkStrictErrorOrWarning(cx, obj, id, strict);
|
||||
}
|
||||
|
|
|
@ -598,6 +598,10 @@ HomeObjectSuperBase(JSContext* cx, HandleObject homeObj);
|
|||
JSObject*
|
||||
SuperFunOperation(JSContext* cx, HandleObject callee);
|
||||
|
||||
bool
|
||||
SetPropertySuper(JSContext* cx, HandleObject obj, HandleValue receiver,
|
||||
HandlePropertyName id, HandleValue rval, bool strict);
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* vm_Interpreter_h */
|
||||
|
|
Загрузка…
Ссылка в новой задаче