diff -r 370ea18e73f5 js/src/jsproxy.cpp --- a/js/src/jsproxy.cpp Mon Apr 23 22:28:15 2012 -0400 +++ b/js/src/jsproxy.cpp Mon Apr 23 23:46:06 2012 -0400 @@ -385,16 +385,93 @@ ProxyHandler::finalize(JSFreeOp *fop, JS { } void ProxyHandler::trace(JSTracer *trc, JSObject *proxy) { } +AbstractProxyHandler::AbstractProxyHandler(void *family) : ProxyHandler(family) +{ +} + +bool +AbstractProxyHandler::getPropertyDescriptor(JSContext *cx, JSObject *proxy, + jsid id, bool set, + PropertyDescriptor *desc) +{ + return JS_GetPropertyDescriptorById(cx, GetProxyTargetObject(proxy), id, + JSRESOLVE_QUALIFIED, desc); +} + +static bool +GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, unsigned flags, + JSPropertyDescriptor *desc) +{ + // If obj is a proxy, we can do better than just guessing. This is + // important for certain types of wrappers that wrap other wrappers. + if (obj->isProxy()) + return Proxy::getOwnPropertyDescriptor(cx, obj, id, + flags & JSRESOLVE_ASSIGNING, + desc); + + if (!JS_GetPropertyDescriptorById(cx, obj, id, flags, desc)) + return false; + if (desc->obj != obj) + desc->obj = NULL; + return true; +} + +bool +AbstractProxyHandler::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, + jsid id, bool set, + PropertyDescriptor *desc) +{ + return GetOwnPropertyDescriptor(cx, GetProxyTargetObject(proxy), id, + JSRESOLVE_QUALIFIED, desc); +} + +bool +AbstractProxyHandler::defineProperty(JSContext *cx, JSObject *proxy, jsid id, + PropertyDescriptor *desc) +{ + return JS_DefinePropertyById(cx, GetProxyTargetObject(proxy), id, + desc->value, desc->getter, desc->setter, + desc->attrs); +} + +bool +AbstractProxyHandler::getOwnPropertyNames(JSContext *cx, JSObject *proxy, + AutoIdVector &props) +{ + return GetPropertyNames(cx, GetProxyTargetObject(proxy), + JSITER_OWNONLY | JSITER_HIDDEN, &props); +} + +bool +AbstractProxyHandler::delete_(JSContext *cx, JSObject *proxy, jsid id, bool *bp) +{ + Value v; + if (!JS_DeletePropertyById2(cx, GetProxyTargetObject(proxy), id, &v)) + return false; + JSBool b; + if (!JS_ValueToBoolean(cx, v, &b)) + return false; + *bp = !!b; + return true; +} + +bool +AbstractProxyHandler::enumerate(JSContext *cx, JSObject *proxy, + AutoIdVector &props) +{ + return GetPropertyNames(cx, GetProxyTargetObject(proxy), 0, &props); +} + static bool GetTrap(JSContext *cx, JSObject *handler, JSAtom *atom, Value *fvalp) { JS_CHECK_RECURSION(cx, return false); return handler->getGeneric(cx, ATOM_TO_JSID(atom), fvalp); } diff -r 370ea18e73f5 js/src/jsproxy.h --- a/js/src/jsproxy.h Mon Apr 23 22:28:15 2012 -0400 +++ b/js/src/jsproxy.h Mon Apr 23 23:46:06 2012 -0400 @@ -95,16 +95,34 @@ class JS_FRIEND_API(ProxyHandler) { return false; } inline void *family() { return mFamily; } }; +class JS_PUBLIC_API(AbstractProxyHandler) : public ProxyHandler { +public: + explicit AbstractProxyHandler(void *family); + + /* ES5 Harmony fundamental proxy traps. */ + virtual bool getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, + bool set, PropertyDescriptor *desc); + virtual bool getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, + jsid id, bool set, + PropertyDescriptor *desc); + virtual bool defineProperty(JSContext *cx, JSObject *proxy, jsid id, + PropertyDescriptor *desc); + virtual bool getOwnPropertyNames(JSContext *cx, JSObject *proxy, + AutoIdVector &props); + virtual bool delete_(JSContext *cx, JSObject *proxy, jsid id, bool *bp); + virtual bool enumerate(JSContext *cx, JSObject *proxy, AutoIdVector &props); +}; + /* Dispatch point for handlers that executes the appropriate C++ or scripted traps. */ class Proxy { public: /* ES5 Harmony fundamental proxy traps. */ static bool getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set, PropertyDescriptor *desc); static bool getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set, Value *vp); static bool getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set, @@ -185,16 +203,23 @@ GetProxyHandler(const JSObject *obj) inline const Value & GetProxyPrivate(const JSObject *obj) { JS_ASSERT(IsProxy(obj)); return GetReservedSlot(obj, JSSLOT_PROXY_PRIVATE); } +inline JSObject * +GetProxyTargetObject(const JSObject *obj) +{ + JS_ASSERT(IsProxy(obj)); + return GetProxyPrivate(obj).toObjectOrNull(); +} + inline const Value & GetProxyExtra(const JSObject *obj, size_t n) { JS_ASSERT(IsProxy(obj)); return GetReservedSlot(obj, JSSLOT_PROXY_EXTRA + n); } inline void