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
Родитель c86091dc20
Коммит a97bbc022d
3 изменённых файлов: 66 добавлений и 41 удалений

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

@ -1529,6 +1529,7 @@ NewPropertyDescriptorObject(JSContext *cx, const PropertyDescriptor *desc, Value
void void
PropDesc::initFromPropertyDescriptor(const PropertyDescriptor &desc) PropDesc::initFromPropertyDescriptor(const PropertyDescriptor &desc)
{ {
isUndefined_ = false;
pd_.setUndefined(); pd_.setUndefined();
attrs = uint8_t(desc.attrs); attrs = uint8_t(desc.attrs);
JS_ASSERT_IF(attrs & JSPROP_READONLY, !(attrs & (JSPROP_GETTER | JSPROP_SETTER))); JS_ASSERT_IF(attrs & JSPROP_READONLY, !(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
@ -1560,6 +1561,8 @@ PropDesc::initFromPropertyDescriptor(const PropertyDescriptor &desc)
bool bool
PropDesc::makeObject(JSContext *cx) PropDesc::makeObject(JSContext *cx)
{ {
MOZ_ASSERT(!isUndefined());
JSObject *obj = NewBuiltinClassInstance(cx, &ObjectClass); JSObject *obj = NewBuiltinClassInstance(cx, &ObjectClass);
if (!obj) if (!obj)
return false; return false;
@ -1728,21 +1731,6 @@ HasProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, bool *foundp)
return !!obj->getGeneric(cx, id, vp); 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 bool
PropDesc::initialize(JSContext *cx, const Value &origval, bool checkAccessors) 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. */ /* Make a copy of the descriptor. We might need it later. */
pd_ = v; 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; attrs = JSPROP_PERMANENT | JSPROP_READONLY;
bool found; bool found;

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

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

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

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