--- a/js/src/jsscope.cpp
+++ b/js/src/jsscope.cpp
@@ -860,16 +860,40 @@ JSObject::addPropertyInternal(JSContext
return shape;
}
CHECK_SHAPE_CONSISTENCY(this);
METER(addFails);
return NULL;
}
+/*
+ * Check and adjust the new attributes for the shape to make sure that our
+ * slot access optimizations are sound. It is responsibility of the callers to
+ * enforce all restrictions from ECMA-262 v5 8.12.9 [[DefineOwnProperty]].
+ */
+inline bool
+CheckCanChangeAttrs(JSContext *cx, JSObject *obj, const Shape *shape, uintN *attrsp)
+{
+ if (shape->configurable())
+ return true;
+
+ /* A permanent property must stay permanent. */
+ *attrsp |= JSPROP_PERMANENT;
+
+ /* Reject attempts to remove a slot from the permanent data property. */
+ if (shape->isDataDescriptor() && shape->hasSlot() &&
+ (*attrsp & (JSPROP_GETTER | JSPROP_SETTER | JSPROP_SHARED))) {
+ obj->reportNotConfigurable(cx, shape->id);
+ return false;
+ }
+
+ return true;
+}
+
const Shape *
JSObject::putProperty(JSContext *cx, jsid id,
PropertyOp getter, PropertyOp setter,
uint32 slot, uintN attrs,
uintN flags, intN shortid)
{
JS_ASSERT(!JSID_IS_VOID(id));
@@ -905,16 +929,19 @@ JSObject::putProperty(JSContext *cx, jsi
return NULL;
}
return new_shape;
}
/* Property exists: search must have returned a valid *spp. */
JS_ASSERT(!SHAPE_IS_REMOVED(*spp));
+ if (!CheckCanChangeAttrs(cx, this, shape, &attrs))
+ return NULL;
+
/*
* If the caller wants to allocate a slot, but doesn't care which slot,
* copy the existing shape's slot into slot so we can match shape, if all
* other members match.
*/
bool hadSlot = !shape->isAlias() && shape->hasSlot();
uint32 oldSlot = shape->slot;
if (!(attrs & JSPROP_SHARED) && slot == SHAPE_INVALID_SLOT && hadSlot)
@@ -1061,16 +1088,20 @@ JSObject::changeProperty(JSContext *cx,
/* Don't allow method properties to be changed to have a getter. */
JS_ASSERT_IF(getter != shape->rawGetter, !shape->isMethod());
if (getter == PropertyStub)
getter = NULL;
if (setter == PropertyStub)
setter = NULL;
+
+ if (!CheckCanChangeAttrs(cx, this, shape, &attrs))
+ return NULL;
+
if (shape->attrs == attrs && shape->getter() == getter && shape->setter() == setter)
return shape;
const Shape *newShape;
/*
* Dictionary-mode objects exclusively own their mutable shape structs, so
* we simply modify in place.