Bug 746262 - Augment PropDesc so that it can represent the absence of a property by adding an isUndefined() method and bit, and checking it in all the relevant accessors. r=jorendorff

--HG--
extra : rebase_source : 45b29d3f65a9e01119f01d9a30f574038abcaea1
This commit is contained in:
Jeff Walden 2012-04-18 15:06:30 -07:00
parent 21a80f218f
commit f569b84d3f
3 changed files with 66 additions and 41 deletions

View File

@ -1529,6 +1529,7 @@ NewPropertyDescriptorObject(JSContext *cx, const PropertyDescriptor *desc, Value
void
PropDesc::initFromPropertyDescriptor(const PropertyDescriptor &desc)
{
isUndefined_ = false;
pd_.setUndefined();
attrs = uint8_t(desc.attrs);
JS_ASSERT_IF(attrs & JSPROP_READONLY, !(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
@ -1560,6 +1561,8 @@ PropDesc::initFromPropertyDescriptor(const PropertyDescriptor &desc)
bool
PropDesc::makeObject(JSContext *cx)
{
MOZ_ASSERT(!isUndefined());
JSObject *obj = NewBuiltinClassInstance(cx, &ObjectClass);
if (!obj)
return false;
@ -1728,21 +1731,6 @@ HasProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, bool *foundp)
return !!obj->getGeneric(cx, id, vp);
}
PropDesc::PropDesc()
: pd_(UndefinedValue()),
value_(UndefinedValue()),
get_(UndefinedValue()),
set_(UndefinedValue()),
attrs(0),
hasGet_(false),
hasSet_(false),
hasValue_(false),
hasWritable_(false),
hasEnumerable_(false),
hasConfigurable_(false)
{
}
bool
PropDesc::initialize(JSContext *cx, const Value &origval, bool checkAccessors)
{
@ -1758,7 +1746,12 @@ PropDesc::initialize(JSContext *cx, const Value &origval, bool checkAccessors)
/* Make a copy of the descriptor. We might need it later. */
pd_ = v;
/* Start with the proper defaults. */
isUndefined_ = false;
/*
* Start with the proper defaults. XXX shouldn't be necessary when we get
* rid of PropDesc::attributes()
*/
attrs = JSPROP_PERMANENT | JSPROP_READONLY;
bool found;

View File

@ -20,12 +20,27 @@
using namespace js;
PropDesc::PropDesc()
: pd_(UndefinedValue()),
value_(UndefinedValue()),
get_(UndefinedValue()),
set_(UndefinedValue()),
attrs(0),
hasGet_(false),
hasSet_(false),
hasValue_(false),
hasWritable_(false),
hasEnumerable_(false),
hasConfigurable_(false),
isUndefined_(true)
{
}
bool
PropDesc::checkGetter(JSContext *cx)
{
if (hasGet()) {
const Value &get = getterValue();
if (!js_IsCallable(get) && !get.isUndefined()) {
if (hasGet_) {
if (!js_IsCallable(get_) && !get_.isUndefined()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_GET_SET_FIELD,
js_getter_str);
return false;
@ -37,9 +52,8 @@ PropDesc::checkGetter(JSContext *cx)
bool
PropDesc::checkSetter(JSContext *cx)
{
if (hasSet()) {
const Value &set = setterValue();
if (!js_IsCallable(set) && !set.isUndefined()) {
if (hasSet_) {
if (!js_IsCallable(set_) && !set_.isUndefined()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_GET_SET_FIELD,
js_setter_str);
return false;
@ -68,6 +82,8 @@ bool
PropDesc::unwrapDebuggerObjectsInto(JSContext *cx, Debugger *dbg, JSObject *obj,
PropDesc *unwrapped) const
{
MOZ_ASSERT(!isUndefined());
*unwrapped = *this;
if (unwrapped->hasValue()) {
@ -106,6 +122,8 @@ bool
PropDesc::wrapInto(JSContext *cx, JSObject *obj, const jsid &id, jsid *wrappedId,
PropDesc *desc) const
{
MOZ_ASSERT(!isUndefined());
JSCompartment *comp = cx->compartment;
*wrappedId = id;

View File

@ -61,6 +61,9 @@ struct PropDesc {
bool hasEnumerable_ : 1;
bool hasConfigurable_ : 1;
/* Or maybe this represents a property's absence, and it's undefined. */
bool isUndefined_ : 1;
public:
friend class AutoPropDescArrayRooter;
friend void JS::AutoGCRooter::trace(JSTracer *trc);
@ -91,68 +94,79 @@ struct PropDesc {
void initFromPropertyDescriptor(const PropertyDescriptor &desc);
bool makeObject(JSContext *cx);
bool hasGet() const { return hasGet_; }
bool hasSet() const { return hasSet_; }
bool hasValue() const { return hasValue_; }
bool hasWritable() const { return hasWritable_; }
bool hasEnumerable() const { return hasEnumerable_; }
bool hasConfigurable() const { return hasConfigurable_; }
void setUndefined() { isUndefined_ = true; }
Value pd() const { return pd_; }
bool isUndefined() const { return isUndefined_; }
bool hasGet() const { MOZ_ASSERT(!isUndefined()); return hasGet_; }
bool hasSet() const { MOZ_ASSERT(!isUndefined()); return hasSet_; }
bool hasValue() const { MOZ_ASSERT(!isUndefined()); return hasValue_; }
bool hasWritable() const { MOZ_ASSERT(!isUndefined()); return hasWritable_; }
bool hasEnumerable() const { MOZ_ASSERT(!isUndefined()); return hasEnumerable_; }
bool hasConfigurable() const { MOZ_ASSERT(!isUndefined()); return hasConfigurable_; }
Value pd() const { MOZ_ASSERT(!isUndefined()); return pd_; }
void clearPd() { pd_ = UndefinedValue(); }
uint8_t attributes() const { return attrs; }
uint8_t attributes() const { MOZ_ASSERT(!isUndefined()); return attrs; }
/* 8.10.1 IsAccessorDescriptor(desc) */
bool isAccessorDescriptor() const {
return hasGet_ || hasSet_;
return !isUndefined() && (hasGet() || hasSet());
}
/* 8.10.2 IsDataDescriptor(desc) */
bool isDataDescriptor() const {
return hasValue_ || hasWritable_;
return !isUndefined() && (hasValue() || hasWritable());
}
/* 8.10.3 IsGenericDescriptor(desc) */
bool isGenericDescriptor() const {
return !isAccessorDescriptor() && !isDataDescriptor();
return !isUndefined() && !isAccessorDescriptor() && !isDataDescriptor();
}
bool configurable() const {
MOZ_ASSERT(hasConfigurable_);
MOZ_ASSERT(!isUndefined());
MOZ_ASSERT(hasConfigurable());
return (attrs & JSPROP_PERMANENT) == 0;
}
bool enumerable() const {
MOZ_ASSERT(hasEnumerable_);
MOZ_ASSERT(!isUndefined());
MOZ_ASSERT(hasEnumerable());
return (attrs & JSPROP_ENUMERATE) != 0;
}
bool writable() const {
MOZ_ASSERT(hasWritable_);
MOZ_ASSERT(!isUndefined());
MOZ_ASSERT(hasWritable());
return (attrs & JSPROP_READONLY) == 0;
}
const Value & value() const {
MOZ_ASSERT(hasValue_);
MOZ_ASSERT(hasValue());
return value_;
}
JSObject * getterObject() const {
MOZ_ASSERT(hasGet_);
MOZ_ASSERT(!isUndefined());
MOZ_ASSERT(hasGet());
return get_.isUndefined() ? NULL : &get_.toObject();
}
JSObject * setterObject() const {
MOZ_ASSERT(hasSet_);
MOZ_ASSERT(!isUndefined());
MOZ_ASSERT(hasSet());
return set_.isUndefined() ? NULL : &set_.toObject();
}
const Value & getterValue() const {
MOZ_ASSERT(hasGet_);
MOZ_ASSERT(!isUndefined());
MOZ_ASSERT(hasGet());
return get_;
}
const Value & setterValue() const {
MOZ_ASSERT(hasSet_);
MOZ_ASSERT(!isUndefined());
MOZ_ASSERT(hasSet());
return set_;
}