Bug 1144630 - Install class methods as non-enumerable on instances. (r=evilpie)

This commit is contained in:
Eric Faust 2015-11-13 18:01:54 -08:00
parent 6fae252680
commit 1f31ef5b64
11 changed files with 160 additions and 32 deletions

View File

@ -7119,12 +7119,25 @@ BytecodeEmitter::emitPropertyList(ParseNode* pn, MutableHandlePlainObject objp,
return false;
}
// Class methods are not enumerable.
if (type == ClassBody) {
switch (op) {
case JSOP_INITPROP: op = JSOP_INITHIDDENPROP; break;
case JSOP_INITPROP_GETTER: op = JSOP_INITHIDDENPROP_GETTER; break;
case JSOP_INITPROP_SETTER: op = JSOP_INITHIDDENPROP_SETTER; break;
default: MOZ_CRASH("Invalid op");
}
}
if (isIndex) {
objp.set(nullptr);
switch (op) {
case JSOP_INITPROP: op = JSOP_INITELEM; break;
case JSOP_INITPROP_GETTER: op = JSOP_INITELEM_GETTER; break;
case JSOP_INITPROP_SETTER: op = JSOP_INITELEM_SETTER; break;
case JSOP_INITPROP: op = JSOP_INITELEM; break;
case JSOP_INITHIDDENPROP: op = JSOP_INITHIDDENELEM; break;
case JSOP_INITPROP_GETTER: op = JSOP_INITELEM_GETTER; break;
case JSOP_INITHIDDENPROP_GETTER: op = JSOP_INITHIDDENELEM_GETTER; break;
case JSOP_INITPROP_SETTER: op = JSOP_INITELEM_SETTER; break;
case JSOP_INITHIDDENPROP_SETTER: op = JSOP_INITHIDDENELEM_SETTER; break;
default: MOZ_CRASH("Invalid op");
}
if (!emit1(op))
@ -7137,6 +7150,8 @@ BytecodeEmitter::emitPropertyList(ParseNode* pn, MutableHandlePlainObject objp,
return false;
if (objp) {
MOZ_ASSERT(type == ObjectLiteral);
MOZ_ASSERT(!IsHiddenInitOp(op));
MOZ_ASSERT(!objp->inDictionaryMode());
Rooted<jsid> id(cx, AtomToId(key->pn_atom));
RootedValue undefinedValue(cx, UndefinedValue());

View File

@ -1964,6 +1964,12 @@ BaselineCompiler::emit_JSOP_INITELEM()
return true;
}
bool
BaselineCompiler::emit_JSOP_INITHIDDENELEM()
{
return emit_JSOP_INITELEM();
}
typedef bool (*MutateProtoFn)(JSContext* cx, HandlePlainObject obj, HandleValue newProto);
static const VMFunction MutateProtoInfo = FunctionInfo<MutateProtoFn>(MutatePrototype);
@ -2569,7 +2575,9 @@ bool
BaselineCompiler::emitInitPropGetterSetter()
{
MOZ_ASSERT(JSOp(*pc) == JSOP_INITPROP_GETTER ||
JSOp(*pc) == JSOP_INITPROP_SETTER);
JSOp(*pc) == JSOP_INITHIDDENPROP_GETTER ||
JSOp(*pc) == JSOP_INITPROP_SETTER ||
JSOp(*pc) == JSOP_INITHIDDENPROP_SETTER);
// Keep values on the stack for the decompiler.
frame.syncStack(0);
@ -2597,12 +2605,24 @@ BaselineCompiler::emit_JSOP_INITPROP_GETTER()
return emitInitPropGetterSetter();
}
bool
BaselineCompiler::emit_JSOP_INITHIDDENPROP_GETTER()
{
return emitInitPropGetterSetter();
}
bool
BaselineCompiler::emit_JSOP_INITPROP_SETTER()
{
return emitInitPropGetterSetter();
}
bool
BaselineCompiler::emit_JSOP_INITHIDDENPROP_SETTER()
{
return emitInitPropGetterSetter();
}
typedef bool (*InitElemGetterSetterFn)(JSContext*, jsbytecode*, HandleObject, HandleValue,
HandleObject);
static const VMFunction InitElemGetterSetterInfo =
@ -2612,7 +2632,9 @@ bool
BaselineCompiler::emitInitElemGetterSetter()
{
MOZ_ASSERT(JSOp(*pc) == JSOP_INITELEM_GETTER ||
JSOp(*pc) == JSOP_INITELEM_SETTER);
JSOp(*pc) == JSOP_INITHIDDENELEM_GETTER ||
JSOp(*pc) == JSOP_INITELEM_SETTER ||
JSOp(*pc) == JSOP_INITHIDDENELEM_SETTER);
// Load index and value in R0 and R1, but keep values on the stack for the
// decompiler.
@ -2641,12 +2663,24 @@ BaselineCompiler::emit_JSOP_INITELEM_GETTER()
return emitInitElemGetterSetter();
}
bool
BaselineCompiler::emit_JSOP_INITHIDDENELEM_GETTER()
{
return emitInitElemGetterSetter();
}
bool
BaselineCompiler::emit_JSOP_INITELEM_SETTER()
{
return emitInitElemGetterSetter();
}
bool
BaselineCompiler::emit_JSOP_INITHIDDENELEM_SETTER()
{
return emitInitElemGetterSetter();
}
bool
BaselineCompiler::emit_JSOP_INITELEM_INC()
{

View File

@ -208,7 +208,12 @@ namespace jit {
_(JSOP_SUPERCALL) \
_(JSOP_SPREADSUPERCALL) \
_(JSOP_THROWSETCONST) \
_(JSOP_THROWSETALIASEDCONST)
_(JSOP_THROWSETALIASEDCONST) \
_(JSOP_INITHIDDENPROP_GETTER) \
_(JSOP_INITHIDDENPROP_SETTER) \
_(JSOP_INITHIDDENELEM) \
_(JSOP_INITHIDDENELEM_GETTER) \
_(JSOP_INITHIDDENELEM_SETTER)
class BaselineCompiler : public BaselineCompilerSpecific
{

View File

@ -3477,6 +3477,7 @@ DoSetElemFallback(JSContext* cx, BaselineFrame* frame, ICSetElem_Fallback* stub_
MOZ_ASSERT(op == JSOP_SETELEM ||
op == JSOP_STRICTSETELEM ||
op == JSOP_INITELEM ||
op == JSOP_INITHIDDENELEM ||
op == JSOP_INITELEM_ARRAY ||
op == JSOP_INITELEM_INC);
@ -3494,8 +3495,8 @@ DoSetElemFallback(JSContext* cx, BaselineFrame* frame, ICSetElem_Fallback* stub_
oldInitLength = GetAnyBoxedOrUnboxedInitializedLength(obj);
}
if (op == JSOP_INITELEM) {
if (!InitElemOperation(cx, obj, index, rhs))
if (op == JSOP_INITELEM || op == JSOP_INITHIDDENELEM) {
if (!InitElemOperation(cx, pc, obj, index, rhs))
return false;
} else if (op == JSOP_INITELEM_ARRAY) {
MOZ_ASSERT(uint32_t(index.toInt32()) <= INT32_MAX,

View File

@ -4848,7 +4848,7 @@ CodeGenerator::visitNewStringObject(LNewStringObject* lir)
masm.bind(ool->rejoin());
}
typedef bool(*InitElemFn)(JSContext* cx, HandleObject obj,
typedef bool(*InitElemFn)(JSContext* cx, jsbytecode* pc, HandleObject obj,
HandleValue id, HandleValue value);
static const VMFunction InitElemInfo =
FunctionInfo<InitElemFn>(InitElemOperation);
@ -4861,6 +4861,7 @@ CodeGenerator::visitInitElem(LInitElem* lir)
pushArg(ToValue(lir, LInitElem::ValueIndex));
pushArg(ToValue(lir, LInitElem::IdIndex));
pushArg(objReg);
pushArg(ImmPtr(lir->mir()->resumePoint()->pc()));
callVM(InitElemInfo, lir);
}

View File

@ -1839,6 +1839,7 @@ IonBuilder::inspectOpcode(JSOp op)
return jsop_newobject();
case JSOP_INITELEM:
case JSOP_INITHIDDENELEM:
return jsop_initelem();
case JSOP_INITELEM_ARRAY:
@ -1858,13 +1859,17 @@ IonBuilder::inspectOpcode(JSOp op)
}
case JSOP_INITPROP_GETTER:
case JSOP_INITPROP_SETTER: {
case JSOP_INITHIDDENPROP_GETTER:
case JSOP_INITPROP_SETTER:
case JSOP_INITHIDDENPROP_SETTER: {
PropertyName* name = info().getAtom(pc)->asPropertyName();
return jsop_initprop_getter_setter(name);
}
case JSOP_INITELEM_GETTER:
case JSOP_INITHIDDENELEM_GETTER:
case JSOP_INITELEM_SETTER:
case JSOP_INITHIDDENELEM_SETTER:
return jsop_initelem_getter_setter();
case JSOP_FUNCALL:

View File

@ -703,6 +703,14 @@ IsGetPropPC(jsbytecode* pc)
return op == JSOP_LENGTH || op == JSOP_GETPROP || op == JSOP_CALLPROP;
}
inline bool
IsHiddenInitOp(JSOp op)
{
return op == JSOP_INITHIDDENPROP || op == JSOP_INITHIDDENELEM ||
op == JSOP_INITHIDDENPROP_GETTER || op == JSOP_INITHIDDENELEM_GETTER ||
op == JSOP_INITHIDDENPROP_SETTER || op == JSOP_INITHIDDENELEM_SETTER;
}
inline bool
IsStrictSetPC(jsbytecode* pc)
{

View File

@ -52,20 +52,20 @@ for (let a of [testClass,
var aMethDesc = Object.getOwnPropertyDescriptor(a.prototype, \"__proto__\");
assertEq(aMethDesc.writable, true);
assertEq(aMethDesc.configurable, true);
assertEq(aMethDesc.enumerable, true);
assertEq(aMethDesc.enumerable, false);
aMethDesc.value();
assertEq(methodCalled, true);
var aGetDesc = Object.getOwnPropertyDescriptor(a.prototype, \"getter\");
assertEq(aGetDesc.configurable, true);
assertEq(aGetDesc.enumerable, true);
assertEq(aGetDesc.enumerable, false);
aGetDesc.get();
assertThrowsInstanceOf(() => new aGetDesc.get, TypeError);
assertEq(getterCalled, true);
var aSetDesc = Object.getOwnPropertyDescriptor(a.prototype, \"setter\");
assertEq(aSetDesc.configurable, true);
assertEq(aSetDesc.enumerable, true);
assertEq(aSetDesc.enumerable, false);
aSetDesc.set();
assertThrowsInstanceOf(() => new aSetDesc.set, TypeError);
assertEq(setterCalled, true);
@ -74,7 +74,7 @@ for (let a of [testClass,
assertEq(Object.getOwnPropertyDescriptor(new a(), \"staticMethod\"), undefined);
var aStaticMethDesc = Object.getOwnPropertyDescriptor(a, \"staticMethod\");
assertEq(aStaticMethDesc.configurable, true);
assertEq(aStaticMethDesc.enumerable, true);
assertEq(aStaticMethDesc.enumerable, false);
assertEq(aStaticMethDesc.writable, true);
aStaticMethDesc.value();
assertThrowsInstanceOf(() => new aStaticMethDesc.value, TypeError);
@ -83,7 +83,7 @@ for (let a of [testClass,
assertEq(Object.getOwnPropertyDescriptor(new a(), \"staticGetter\"), undefined);
var aStaticGetDesc = Object.getOwnPropertyDescriptor(a, \"staticGetter\");
assertEq(aStaticGetDesc.configurable, true);
assertEq(aStaticGetDesc.enumerable, true);
assertEq(aStaticGetDesc.enumerable, false);
aStaticGetDesc.get();
assertThrowsInstanceOf(() => new aStaticGetDesc.get, TypeError);
assertEq(staticGetterCalled, true);
@ -91,7 +91,7 @@ for (let a of [testClass,
assertEq(Object.getOwnPropertyDescriptor(new a(), \"staticSetter\"), undefined);
var aStaticSetDesc = Object.getOwnPropertyDescriptor(a, \"staticSetter\");
assertEq(aStaticSetDesc.configurable, true);
assertEq(aStaticSetDesc.enumerable, true);
assertEq(aStaticSetDesc.enumerable, false);
aStaticSetDesc.set();
assertThrowsInstanceOf(() => new aStaticSetDesc.set, TypeError);
assertEq(staticSetterCalled, true);

View File

@ -616,7 +616,7 @@ TypeOfObjectOperation(JSObject* obj, JSRuntime* rt)
}
static MOZ_ALWAYS_INLINE bool
InitElemOperation(JSContext* cx, HandleObject obj, HandleValue idval, HandleValue val)
InitElemOperation(JSContext* cx, jsbytecode* pc, HandleObject obj, HandleValue idval, HandleValue val)
{
MOZ_ASSERT(!val.isMagic(JS_ELEMENTS_HOLE));
MOZ_ASSERT(!obj->getClass()->getProperty);
@ -626,7 +626,8 @@ InitElemOperation(JSContext* cx, HandleObject obj, HandleValue idval, HandleValu
if (!ToPropertyKey(cx, idval, &id))
return false;
return DefineProperty(cx, obj, id, val, nullptr, nullptr, JSPROP_ENUMERATE);
unsigned flags = JSOp(*pc) == JSOP_INITHIDDENELEM ? 0 : JSPROP_ENUMERATE;
return DefineProperty(cx, obj, id, val, nullptr, nullptr, flags);
}
static MOZ_ALWAYS_INLINE bool

View File

@ -1693,11 +1693,6 @@ CASE(JSOP_NOP)
CASE(JSOP_UNUSED14)
CASE(JSOP_BACKPATCH)
CASE(JSOP_UNUSED145)
CASE(JSOP_UNUSED171)
CASE(JSOP_UNUSED172)
CASE(JSOP_UNUSED173)
CASE(JSOP_UNUSED174)
CASE(JSOP_UNUSED175)
CASE(JSOP_UNUSED176)
CASE(JSOP_UNUSED177)
CASE(JSOP_UNUSED178)
@ -3205,7 +3200,9 @@ CASE(JSOP_CALLEE)
END_CASE(JSOP_CALLEE)
CASE(JSOP_INITPROP_GETTER)
CASE(JSOP_INITHIDDENPROP_GETTER)
CASE(JSOP_INITPROP_SETTER)
CASE(JSOP_INITHIDDENPROP_SETTER)
{
MOZ_ASSERT(REGS.stackDepth() >= 2);
@ -3221,7 +3218,9 @@ CASE(JSOP_INITPROP_SETTER)
END_CASE(JSOP_INITPROP_GETTER)
CASE(JSOP_INITELEM_GETTER)
CASE(JSOP_INITHIDDENELEM_GETTER)
CASE(JSOP_INITELEM_SETTER)
CASE(JSOP_INITHIDDENELEM_SETTER)
{
MOZ_ASSERT(REGS.stackDepth() >= 3);
@ -3336,6 +3335,7 @@ CASE(JSOP_INITHIDDENPROP)
END_CASE(JSOP_INITPROP)
CASE(JSOP_INITELEM)
CASE(JSOP_INITHIDDENELEM)
{
MOZ_ASSERT(REGS.stackDepth() >= 3);
HandleValue val = REGS.stackHandleAt(-1);
@ -3343,7 +3343,7 @@ CASE(JSOP_INITELEM)
ReservedRooted<JSObject*> obj(&rootObject0, &REGS.sp[-3].toObject());
if (!InitElemOperation(cx, obj, id, val))
if (!InitElemOperation(cx, REGS.pc, obj, id, val))
goto error;
REGS.sp -= 2;
@ -4326,16 +4326,22 @@ js::InitGetterSetterOperation(JSContext* cx, jsbytecode* pc, HandleObject obj, H
MOZ_ASSERT(val->isCallable());
GetterOp getter;
SetterOp setter;
unsigned attrs = JSPROP_ENUMERATE | JSPROP_SHARED;
unsigned attrs = JSPROP_SHARED;
JSOp op = JSOp(*pc);
if (op == JSOP_INITPROP_GETTER || op == JSOP_INITELEM_GETTER) {
if (!IsHiddenInitOp(op))
attrs |= JSPROP_ENUMERATE;
if (op == JSOP_INITPROP_GETTER || op == JSOP_INITELEM_GETTER ||
op == JSOP_INITHIDDENPROP_GETTER || op == JSOP_INITHIDDENELEM_GETTER)
{
getter = CastAsGetterOp(val);
setter = nullptr;
attrs |= JSPROP_GETTER;
} else {
MOZ_ASSERT(op == JSOP_INITPROP_SETTER || op == JSOP_INITELEM_SETTER);
MOZ_ASSERT(op == JSOP_INITPROP_SETTER || op == JSOP_INITELEM_SETTER ||
op == JSOP_INITHIDDENPROP_SETTER || op == JSOP_INITHIDDENELEM_SETTER);
getter = nullptr;
setter = CastAsSetterOp(val);
attrs |= JSPROP_SETTER;

View File

@ -1744,11 +1744,63 @@
* Stack: =>
*/ \
macro(JSOP_THROWSETALIASEDCONST, 170, "throwsetaliasedconst", NULL, 5, 1, 1, JOF_SCOPECOORD|JOF_NAME|JOF_SET|JOF_DETECTING) \
macro(JSOP_UNUSED171, 171,"unused171", NULL, 1, 0, 0, JOF_BYTE) \
macro(JSOP_UNUSED172, 172,"unused172", NULL, 1, 0, 0, JOF_BYTE) \
macro(JSOP_UNUSED173, 173,"unused173", NULL, 1, 0, 0, JOF_BYTE) \
macro(JSOP_UNUSED174, 174,"unused174", NULL, 1, 0, 0, JOF_BYTE) \
macro(JSOP_UNUSED175, 175,"unused175", NULL, 1, 0, 0, JOF_BYTE) \
/*
* Initialize a non-enumerable getter in an object literal.
*
* Pops the top two values on the stack as 'val' and 'obj', defines
* getter of 'obj' as 'val', pushes 'obj' onto the stack.
* Category: Literals
* Type: Object
* Operands: uint32_t nameIndex
* Stack: obj, val => obj
*/ \
macro(JSOP_INITHIDDENPROP_GETTER, 171, "inithiddenprop_getter", NULL, 5, 2, 1, JOF_ATOM|JOF_PROP|JOF_SET|JOF_DETECTING) \
/*
* Initialize a non-enumerable setter in an object literal.
*
* Pops the top two values on the stack as 'val' and 'obj', defines
* setter of 'obj' as 'val', pushes 'obj' onto the stack.
* Category: Literals
* Type: Object
* Operands: uint32_t nameIndex
* Stack: obj, val => obj
*/ \
macro(JSOP_INITHIDDENPROP_SETTER, 172, "inithiddenprop_setter", NULL, 5, 2, 1, JOF_ATOM|JOF_PROP|JOF_SET|JOF_DETECTING) \
/*
* Initialize a non-enumerable numeric getter in an object literal like
* '{get 2() {}}'.
*
* Pops the top three values on the stack as 'val', 'id' and 'obj', defines
* 'id' getter of 'obj' as 'val', pushes 'obj' onto the stack.
* Category: Literals
* Type: Object
* Operands:
* Stack: obj, id, val => obj
*/ \
macro(JSOP_INITHIDDENELEM_GETTER, 173, "inithiddenelem_getter", NULL, 1, 3, 1, JOF_BYTE|JOF_ELEM|JOF_SET|JOF_DETECTING) \
/*
* Initialize a non-enumerable numeric setter in an object literal like
* '{set 2(v) {}}'.
*
* Pops the top three values on the stack as 'val', 'id' and 'obj', defines
* 'id' setter of 'obj' as 'val', pushes 'obj' onto the stack.
* Category: Literals
* Type: Object
* Operands:
* Stack: obj, id, val => obj
*/ \
macro(JSOP_INITHIDDENELEM_SETTER, 174, "inithiddenelem_setter", NULL, 1, 3, 1, JOF_BYTE|JOF_ELEM|JOF_SET|JOF_DETECTING) \
/*
* Initialize a non-enumerable numeric property in an object literal, like '{1: x}'.
*
* Pops the top three values on the stack as 'val', 'id' and 'obj', defines
* 'id' property of 'obj' as 'val', pushes 'obj' onto the stack.
* Category: Literals
* Type: Object
* Operands:
* Stack: obj, id, val => obj
*/ \
macro(JSOP_INITHIDDENELEM, 175, "inithiddenelem", NULL, 1, 3, 1, JOF_BYTE|JOF_ELEM|JOF_SET|JOF_DETECTING) \
macro(JSOP_UNUSED176, 176,"unused176", NULL, 1, 0, 0, JOF_BYTE) \
macro(JSOP_UNUSED177, 177,"unused177", NULL, 1, 0, 0, JOF_BYTE) \
macro(JSOP_UNUSED178, 178,"unused178", NULL, 1, 0, 0, JOF_BYTE) \