diff -r a040ded5b0da js/src/jsobj.cpp --- a/js/src/jsobj.cpp Sun Aug 05 16:18:21 2012 +0200 +++ b/js/src/jsobj.cpp Sun Aug 05 22:16:35 2012 +0200 @@ -1371,16 +1371,40 @@ PropDesc::initialize(JSContext *cx, cons return false; } JS_ASSERT_IF(attrs & JSPROP_READONLY, !(attrs & (JSPROP_GETTER | JSPROP_SETTER))); return true; } +void +PropDesc::complete(JSContext *cx) +{ + if (isGenericDescriptor() || isDataDescriptor()) { + if (!hasValue_) { + hasValue_ = true; + value_.setUndefined(); + } + if (!hasWritable_) { + hasWritable_ = true; + attrs |= JSPROP_READONLY; + } + } else { + if (!hasGet_) { + hasGet_ = true; + get_.setUndefined(); + } + if (!hasSet_) { + hasSet_ = true; + set_.setUndefined(); + } + } +} + namespace js { bool Throw(JSContext *cx, jsid id, unsigned errorNumber) { JS_ASSERT(js_ErrorFormatString[errorNumber].argCount == 1); JSString *idstr = IdToString(cx, id); diff -r a040ded5b0da js/src/jsproxy.cpp --- a/js/src/jsproxy.cpp Sun Aug 05 16:18:21 2012 +0200 +++ b/js/src/jsproxy.cpp Sun Aug 05 22:16:35 2012 +0200 @@ -1040,16 +1040,114 @@ class ScriptedDirectProxyHandler : publi virtual bool keys(JSContext *cx, JSObject *proxy, AutoIdVector &props); virtual bool iterate(JSContext *cx, JSObject *proxy, unsigned flags, Value *vp); static ScriptedDirectProxyHandler singleton; }; static int sScriptedDirectProxyHandlerFamily = 0; +/* Aux.1 ToCompletePropertyDescriptor(Obj) */ +static inline bool +ToCompletePropertyDescriptor(JSContext *cx, const Value &v, PropDesc *desc) +{ + /* Aux.1 steps 1-2 */ + if (!desc->initialize(cx, v)) + return false; + + /* Aux.1 steps 3-5 */ + desc->complete(cx); + return true; +} + +/* Aux.2 FromGenericPropertyDescriptor(Desc) */ +static inline bool +FromGenericPropertyDescriptor(JSContext *cx, PropDesc *desc, Value *rval) +{ + /* Aux.2 step 1 */ + if (desc->isUndefined()) { + rval->setUndefined(); + return true; + } + + /* Aux.2 steps 3-9 */ + if (!desc->makeObject(cx)) + return false; + *rval = desc->pd(); + return true; +} + +/* + * Aux.3 NormalizePropertyDescriptor(Attributes) + * + * NOTE: to minimize code duplication, the code for this function is shared with + * that for Aux.4 NormalizeAndCompletePropertyDescriptor (see below). The + * argument complete is used to distinguish between the two. + */ +static inline bool +NormalizePropertyDescriptor(JSContext *cx, Value *vp, bool complete = false) +{ + /* Aux.4 step 1 */ + if (complete && vp->isUndefined()) + return true; + + /* Aux.3 steps 1-2 / Aux.4 steps 2-3 */ + AutoPropDescArrayRooter descs(cx); + PropDesc *desc = descs.append(); + if (!desc || !desc->initialize(cx, *vp)) + return false; + + /* + * Aux.3 step 3 / Aux.4 step 4 + * + * NOTE: Aux.4 step 4 actually specifies FromPropertyDescriptor here. + * However, the way FromPropertyDescriptor is implemented (PropDesc:: + * makeObject) is actually closer to FromGenericPropertyDescriptor, + * and is in fact used to implement the latter, so we might as well call it + * directly. + */ + if (!FromGenericPropertyDescriptor(cx, desc, vp)) + return false; + if (vp->isUndefined()) + return true; + RootedObject descObj(cx, &vp->toObject()); + + /* Aux.3 steps 4-5 / Aux.4 steps 5-6 */ + AutoIdVector props(cx); + if (!GetPropertyNames(cx, descObj, JSITER_OWNONLY, &props)) + return false; + size_t n = props.length(); + for (size_t i = 0; i < n; ++n) { + RootedId id(cx, props[i]); + if (JSID_IS_ATOM(id)) { + JSAtom *atom = JSID_TO_ATOM(id); + const JSAtomState &atomState = cx->runtime->atomState; + if (atom == atomState.valueAtom || atom == atomState.writableAtom || + atom == atomState.getAtom || atom == atomState.setAtom || + atom == atomState.enumerableAtom || atom == atomState.configurableAtom) { + continue; + } + } + + RootedValue v(cx); + if (!descObj->getGeneric(cx, descObj, id, &v)) + return false; + if (!JS_DefinePropertyById(cx, descObj, id, v, NULL, NULL, JSPROP_ENUMERATE)) + return false; + } + return true; +} + +/* Aux.4 NormalizeAndCompletePropertyDescriptor(Attributes) */ +static inline bool +NormalizeAndCompletePropertyDescriptor(JSContext *cx, Value *vp) +{ + return NormalizePropertyDescriptor(cx, vp, true); +} + ScriptedDirectProxyHandler::ScriptedDirectProxyHandler() : DirectProxyHandler(&sScriptedDirectProxyHandlerFamily) { } ScriptedDirectProxyHandler::~ScriptedDirectProxyHandler() { } diff -r a040ded5b0da js/src/vm/ObjectImpl.h --- a/js/src/vm/ObjectImpl.h Sun Aug 05 16:18:21 2012 +0200 +++ b/js/src/vm/ObjectImpl.h Sun Aug 05 22:16:35 2012 +0200 @@ -163,17 +163,19 @@ struct PropDesc { * * If checkAccessors is false, skip steps 7.b and 8.b, which throw a * TypeError if .get or .set is neither a callable object nor undefined. * * (DebuggerObject_defineProperty uses this: the .get and .set properties * are expected to be Debugger.Object wrappers of functions, which are not * themselves callable.) */ - bool initialize(JSContext* cx, const Value &v, bool checkAccessors = true); + bool initialize(JSContext *cx, const Value &v, bool checkAccessors = true); + + void complete(JSContext *cx); /* * 8.10.4 FromPropertyDescriptor(Desc) * * initFromPropertyDescriptor sets pd to undefined and populates all the * other fields of this PropDesc from desc. * * makeObject populates pd based on the other fields of *this, creating a