Bug 1142828 - Refactor to avoid having [[Set]]-specific weird cases in the [[DefineOwnProperty]] code. r=Waldo.

NativeSetExistingDataProperty is only moved in this changeset; its body is not modified.

--HG--
extra : rebase_source : 413ad14802b8deb6bffef81897cd61ee004d35e2
This commit is contained in:
Jason Orendorff 2015-03-23 14:32:28 -05:00
Родитель 5bb0f20d04
Коммит 39dccf0118
1 изменённых файлов: 74 добавлений и 70 удалений

Просмотреть файл

@ -1102,14 +1102,10 @@ UpdateShapeTypeAndValue(ExclusiveContext* cx, NativeObject* obj, Shape* shape, c
return true;
}
static bool
NativeSetExistingDataProperty(JSContext* cx, HandleNativeObject obj, HandleShape shape,
HandleValue v, HandleValue receiver, ObjectOpResult& result);
static inline bool
DefinePropertyOrElement(ExclusiveContext* cx, HandleNativeObject obj, HandleId id,
GetterOp getter, SetterOp setter, unsigned attrs, HandleValue value,
bool callSetterAfterwards, ObjectOpResult& result)
ObjectOpResult& result)
{
MOZ_ASSERT(getter != JS_PropertyStub);
MOZ_ASSERT(setter != JS_StrictPropertyStub);
@ -1192,16 +1188,6 @@ DefinePropertyOrElement(ExclusiveContext* cx, HandleNativeObject obj, HandleId i
if (!CallAddPropertyHook(cx, obj, shape, value))
return false;
if (callSetterAfterwards && setter) {
MOZ_ASSERT(!(attrs & JSPROP_GETTER));
MOZ_ASSERT(!(attrs & JSPROP_SETTER));
if (!cx->shouldBeJSContext())
return false;
RootedValue receiver(cx, ObjectValue(*obj));
return NativeSetExistingDataProperty(cx->asJSContext(), obj, shape, value, receiver,
result);
}
return result.succeed();
}
@ -1467,8 +1453,7 @@ js::NativeDefineProperty(ExclusiveContext* cx, HandleNativeObject obj, HandleId
// cleared the IGNORE flags by now. Since we can never get here with JSPROP_IGNORE_VALUE
// relevant, just clear it.
attrs = ApplyOrDefaultAttributes(attrs) & ~JSPROP_IGNORE_VALUE;
return DefinePropertyOrElement(cx, obj, id, getter, setter,
attrs, updateValue, false, result);
return DefinePropertyOrElement(cx, obj, id, getter, setter, attrs, updateValue, result);
}
MOZ_ASSERT(shape);
@ -1953,6 +1938,55 @@ MaybeReportUndeclaredVarAssignment(JSContext* cx, JSString* propname)
JSMSG_UNDECLARED_VAR, bytes.ptr());
}
/*
* Finish assignment to a shapeful data property of a native object obj. This
* conforms to no standard and there is a lot of legacy baggage here.
*/
static bool
NativeSetExistingDataProperty(JSContext* cx, HandleNativeObject obj, HandleShape shape,
HandleValue v, HandleValue receiver, ObjectOpResult& result)
{
MOZ_ASSERT(obj->isNative());
MOZ_ASSERT(shape->isDataDescriptor());
if (shape->hasDefaultSetter()) {
if (shape->hasSlot()) {
// The common path. Standard data property.
// Global properties declared with 'var' will be initially
// defined with an undefined value, so don't treat the initial
// assignments to such properties as overwrites.
bool overwriting = !obj->is<GlobalObject>() || !obj->getSlot(shape->slot()).isUndefined();
obj->setSlotWithType(cx, shape, v, overwriting);
return result.succeed();
}
// Bizarre: shared (slotless) property that's writable but has no
// JSSetterOp. JS code can't define such a property, but it can be done
// through the JSAPI. Treat it as non-writable.
return result.fail(JSMSG_GETTER_ONLY);
}
MOZ_ASSERT(!obj->is<DynamicWithObject>()); // See bug 1128681.
uint32_t sample = cx->runtime()->propertyRemovals;
RootedId id(cx, shape->propid());
RootedValue value(cx, v);
if (!CallJSSetterOp(cx, shape->setterOp(), obj, id, &value, result))
return false;
// Update any slot for the shape with the value produced by the setter,
// unless the setter deleted the shape.
if (shape->hasSlot() &&
(MOZ_LIKELY(cx->runtime()->propertyRemovals == sample) ||
obj->contains(cx, shape)))
{
obj->setSlot(shape->slot(), value);
}
return true; // result is populated by CallJSSetterOp above.
}
/*
* When a [[Set]] operation finds no existing property with the given id
* or finds a writable data property on the prototype chain, we end up here.
@ -2019,13 +2053,32 @@ js::SetPropertyByDefining(JSContext* cx, HandleObject obj, HandleId id, HandleVa
JSSetterOp setter = clasp->setProperty;
MOZ_ASSERT(getter != JS_PropertyStub);
MOZ_ASSERT(setter != JS_StrictPropertyStub);
if (!receiver->is<NativeObject>())
return DefineProperty(cx, receiver, id, v, getter, setter, attrs, result);
if (!DefineProperty(cx, receiver, id, v, getter, setter, attrs, result))
return false;
// If the receiver is native, there is one more legacy wrinkle: the class
// JSSetterOp is called after defining the new property.
Rooted<NativeObject*> nativeReceiver(cx, &receiver->as<NativeObject>());
return DefinePropertyOrElement(cx, nativeReceiver, id, getter, setter, attrs, v, true, result);
if (setter && receiver->is<NativeObject>()) {
if (!result)
return true;
Rooted<NativeObject*> nativeReceiver(cx, &receiver->as<NativeObject>());
if (!cx->shouldBeJSContext())
return false;
RootedValue receiverValue(cx, ObjectValue(*receiver));
// This lookup is a bit unfortunate, but not nearly the most
// unfortunate thing about Class getters and setters. Since the above
// DefineProperty call succeeded, receiver is native, and the property
// has a setter (and thus can't be a dense element), this lookup is
// guaranteed to succeed.
RootedShape shape(cx, nativeReceiver->lookup(cx, id));
MOZ_ASSERT(shape);
return NativeSetExistingDataProperty(cx->asJSContext(), nativeReceiver, shape, v,
receiverValue, result);
}
return true;
}
// When setting |id| for |receiver| and |obj| has no property for id, continue
@ -2100,55 +2153,6 @@ SetDenseOrTypedArrayElement(JSContext* cx, HandleNativeObject obj, uint32_t inde
return result.succeed();
}
/*
* Finish assignment to a shapeful data property of a native object obj. This
* conforms to no standard and there is a lot of legacy baggage here.
*/
static bool
NativeSetExistingDataProperty(JSContext* cx, HandleNativeObject obj, HandleShape shape,
HandleValue v, HandleValue receiver, ObjectOpResult& result)
{
MOZ_ASSERT(obj->isNative());
MOZ_ASSERT(shape->isDataDescriptor());
if (shape->hasDefaultSetter()) {
if (shape->hasSlot()) {
// The common path. Standard data property.
// Global properties declared with 'var' will be initially
// defined with an undefined value, so don't treat the initial
// assignments to such properties as overwrites.
bool overwriting = !obj->is<GlobalObject>() || !obj->getSlot(shape->slot()).isUndefined();
obj->setSlotWithType(cx, shape, v, overwriting);
return result.succeed();
}
// Bizarre: shared (slotless) property that's writable but has no
// JSSetterOp. JS code can't define such a property, but it can be done
// through the JSAPI. Treat it as non-writable.
return result.fail(JSMSG_GETTER_ONLY);
}
MOZ_ASSERT(!obj->is<DynamicWithObject>()); // See bug 1128681.
uint32_t sample = cx->runtime()->propertyRemovals;
RootedId id(cx, shape->propid());
RootedValue value(cx, v);
if (!CallJSSetterOp(cx, shape->setterOp(), obj, id, &value, result))
return false;
// Update any slot for the shape with the value produced by the setter,
// unless the setter deleted the shape.
if (shape->hasSlot() &&
(MOZ_LIKELY(cx->runtime()->propertyRemovals == sample) ||
obj->contains(cx, shape)))
{
obj->setSlot(shape->slot(), value);
}
return true; // result is populated by CallJSSetterOp above.
}
/*
* Finish the assignment `receiver[id] = v` when an existing property (shape)
* has been found on a native object (pobj). This implements ES6 draft rev 32