Bug 890729 - Implement the missing CPOW traps. r=dvander
authorTom Schuster <evilpies@gmail.com>
Tue, 09 Jul 2013 22:45:08 -0400
changeset 145526 5b1d4377a538fcdafdc22e7b752e3491961008fe
parent 145525 14de59ee10a93f73f7f097ef9facd4bed9109074
child 145527 0dc84a9f29102d46e9601ea7fdbba86655797ffc
push idunknown
push userunknown
push dateunknown
reviewersdvander
bugs890729
milestone25.0a1
Bug 890729 - Implement the missing CPOW traps. r=dvander
js/ipc/JavaScriptChild.cpp
js/ipc/JavaScriptChild.h
js/ipc/JavaScriptParent.cpp
js/ipc/JavaScriptParent.h
js/ipc/PJavaScript.ipdl
js/src/jsfriendapi.h
js/src/jsobj.cpp
js/src/jsobj.h
--- a/js/ipc/JavaScriptChild.cpp
+++ b/js/ipc/JavaScriptChild.cpp
@@ -246,17 +246,16 @@ JavaScriptChild::AnswerSet(const ObjectI
 
     RootedId internedId(cx);
     if (!convertGeckoStringToId(cx, id, &internedId))
         return fail(cx, rs);
 
     MOZ_ASSERT(obj == receiver);
 
     RootedValue val(cx);
-
     if (!toValue(cx, value, &val))
         return fail(cx, rs);
 
     if (!JS_SetPropertyById(cx, obj, internedId, val.address()))
         return fail(cx, rs);
 
     if (!toVariant(cx, val, result))
         return fail(cx, rs);
@@ -359,16 +358,17 @@ JavaScriptChild::AnswerCall(const Object
         if (!toVariant(cx, vals[i], &variant))
             return fail(cx, rs);
         outparams->ReplaceElementAt(i, JSParam(variant));
     }
 
     return ok(rs);
 }
 
+
 bool
 JavaScriptChild::AnswerInstanceOf(const ObjectId &objId,
                                   const JSIID &iid,
                                   ReturnStatus *rs,
                                   bool *instanceof)
 {
     AutoSafeJSContext cx;
     JSAutoRequest request(cx);
@@ -466,31 +466,61 @@ JavaScriptChild::AnswerGetOwnPropertyDes
 
     if (!fromDescriptor(cx, desc, out))
         return fail(cx, rs);
 
     return ok(rs);
 }
 
 bool
-JavaScriptChild::AnswerGetOwnPropertyNames(const ObjectId &objId,
-                                           ReturnStatus *rs,
-                                           nsTArray<nsString> *names)
+JavaScriptChild::AnswerDefineProperty(const ObjectId &objId, const nsString &id,
+                                      const PPropertyDescriptor &descriptor, ReturnStatus *rs)
+{
+    AutoSafeJSContext cx;
+    JSAutoRequest request(cx);
+
+    RootedObject obj(cx, findObject(objId));
+    if (!obj)
+        return false;
+
+    JSAutoCompartment comp(cx, obj);
+
+    RootedId internedId(cx);
+    if (!convertGeckoStringToId(cx, id, &internedId))
+        return fail(cx, rs);
+
+    JSPropertyDescriptor desc;
+    if (!toDescriptor(cx, descriptor, &desc))
+        return false;
+
+    RootedValue v(cx, desc.value);
+    if (!js::CheckDefineProperty(cx, obj, internedId, v, desc.getter, desc.setter, desc.attrs) ||
+        !JS_DefinePropertyById(cx, obj, internedId, v, desc.getter, desc.setter, desc.attrs))
+    {
+        return fail(cx, rs);
+    }
+
+    return ok(rs);
+}
+
+bool
+JavaScriptChild::AnswerGetPropertyNames(const ObjectId &objId, const uint32_t &flags,
+                                        ReturnStatus *rs, nsTArray<nsString> *names)
 {
     AutoSafeJSContext cx;
     JSAutoRequest request(cx);
 
     RootedObject obj(cx, findObject(objId));
     if (!obj)
         return false;
 
     JSAutoCompartment comp(cx, obj);
 
     AutoIdVector props(cx);
-    if (!js::GetPropertyNames(cx, obj, JSITER_OWNONLY | JSITER_HIDDEN, &props))
+    if (!js::GetPropertyNames(cx, obj, flags, &props))
         return fail(cx, rs);
 
     for (size_t i = 0; i < props.length(); i++) {
         nsString name;
         if (!convertIdToGeckoString(cx, props.handleAt(i), &name))
             return false;
 
         names->AppendElement(name);
@@ -598,8 +628,38 @@ JavaScriptChild::AnswerPreventExtensions
         return false;
 
     JSAutoCompartment comp(cx, obj);
     if (!JS_PreventExtensions(cx, obj))
         return fail(cx, rs);
 
     return ok(rs);
 }
+
+
+bool
+JavaScriptChild::AnswerDelete(const ObjectId &objId, const nsString &id,
+                              ReturnStatus *rs, bool *success)
+{
+    AutoSafeJSContext cx;
+    JSAutoRequest request(cx);
+
+    JSObject *obj = findObject(objId);
+    if (!obj)
+        return false;
+
+    JSAutoCompartment comp(cx, obj);
+
+    RootedId internedId(cx);
+    if (!convertGeckoStringToId(cx, id, &internedId))
+        return fail(cx, rs);
+
+    RootedValue v(cx);
+    if (!JS_DeletePropertyById2(cx, obj, internedId, v.address()))
+        return fail(cx, rs);
+
+    JSBool b;
+    if (!JS_ValueToBoolean(cx, v, &b))
+        return fail(cx, rs);
+    *success = !!b;
+
+    return ok(rs);
+}
--- a/js/ipc/JavaScriptChild.h
+++ b/js/ipc/JavaScriptChild.h
@@ -53,32 +53,39 @@ class JavaScriptChild
                                      const uint32_t &flags,
                                      ReturnStatus *rs,
                                      PPropertyDescriptor *out);
     bool AnswerGetOwnPropertyDescriptor(const ObjectId &objId,
                                         const nsString &id,
                                         const uint32_t &flags,
                                         ReturnStatus *rs,
                                         PPropertyDescriptor *out);
-    bool AnswerGetOwnPropertyNames(const ObjectId &objId,
-                                   ReturnStatus *rs,
-                                   nsTArray<nsString> *names);
+    bool AnswerDefineProperty(const ObjectId &objId,
+                              const nsString &id,
+                              const PPropertyDescriptor &flags,
+                              ReturnStatus *rs);
+    bool AnswerGetPropertyNames(const ObjectId &objId,
+                                const uint32_t &flags,
+                                ReturnStatus *rs,
+                                nsTArray<nsString> *names);
     bool AnswerKeys(const ObjectId &objId,
                     ReturnStatus *rs,
                     nsTArray<nsString> *names);
     bool AnswerObjectClassIs(const ObjectId &objId,
                              const uint32_t &classValue,
                              bool *result);
     bool AnswerClassName(const ObjectId &objId,
                              nsString *result);
     bool AnswerIsExtensible(const ObjectId &objId,
                             ReturnStatus *rs,
                             bool *result);
     bool AnswerPreventExtensions(const ObjectId &objId,
                                  ReturnStatus *rs);
+    bool AnswerDelete(const ObjectId &objId, const nsString &id,
+                      ReturnStatus *rs, bool *success);
 
   protected:
     JSObject *unwrap(JSContext *cx, ObjectId id);
 
   private:
     bool makeId(JSContext *cx, JSObject *obj, ObjectId *idp);
     bool fail(JSContext *cx, ReturnStatus *rs);
     bool ok(ReturnStatus *rs);
--- a/js/ipc/JavaScriptParent.cpp
+++ b/js/ipc/JavaScriptParent.cpp
@@ -73,18 +73,16 @@ class CPOWProxyHandler : public BaseProx
 
     virtual bool has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) MOZ_OVERRIDE;
     virtual bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) MOZ_OVERRIDE;
     virtual bool get(JSContext *cx, HandleObject proxy, HandleObject receiver,
                      HandleId id, MutableHandleValue vp) MOZ_OVERRIDE;
     virtual bool set(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
                      JS::HandleId id, bool strict, JS::MutableHandleValue vp) MOZ_OVERRIDE;
     virtual bool keys(JSContext *cx, HandleObject proxy, AutoIdVector &props) MOZ_OVERRIDE;
-    virtual bool iterate(JSContext *cx, HandleObject proxy, unsigned flags,
-                         MutableHandleValue vp) MOZ_OVERRIDE;
 
     virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args) MOZ_OVERRIDE;
     virtual void finalize(JSFreeOp *fop, JSObject *proxy) MOZ_OVERRIDE;
     virtual bool objectClassIs(HandleObject obj, js::ESClassValue classValue, JSContext *cx) MOZ_OVERRIDE;
     virtual const char* className(JSContext *cx, HandleObject proxy) MOZ_OVERRIDE;
     virtual bool preventExtensions(JSContext *cx, HandleObject proxy) MOZ_OVERRIDE;
     virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) MOZ_OVERRIDE;
 
@@ -146,87 +144,96 @@ JavaScriptParent::getOwnPropertyDescript
 
     return toDescriptor(cx, result, desc);
 }
 
 bool
 CPOWProxyHandler::defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
                                  PropertyDescriptor *desc)
 {
-    MOZ_CRASH("unimplemented");
+    return ParentOf(proxy)->defineProperty(cx, proxy, id, desc);
+}
+
+bool
+JavaScriptParent::defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
+                                 PropertyDescriptor *desc)
+{
+    ObjectId objId = idOf(proxy);
+
+    nsString idstr;
+    if (!convertIdToGeckoString(cx, id, &idstr))
+        return false;
+
+    PPropertyDescriptor descriptor;
+    if (!fromDescriptor(cx, *desc, &descriptor))
+        return false;
+
+    ReturnStatus status;
+    if (!CallDefineProperty(objId, idstr, descriptor, &status))
+        return ipcfail(cx);
+
+    return ok(cx, status);
 }
 
 bool
 CPOWProxyHandler::getOwnPropertyNames(JSContext *cx, HandleObject proxy, AutoIdVector &props)
 {
     return ParentOf(proxy)->getOwnPropertyNames(cx, proxy, props);
 }
 
 bool
 JavaScriptParent::getOwnPropertyNames(JSContext *cx, HandleObject proxy, AutoIdVector &props)
 {
-    ObjectId objId = idOf(proxy);
-
-    ReturnStatus status;
-    InfallibleTArray<nsString> names;
-    if (!CallGetOwnPropertyNames(objId, &status, &names))
-        return ipcfail(cx);
-    if (!ok(cx, status))
-        return false;
-
-    RootedId name(cx);
-    for (size_t i = 0; i < names.Length(); i++) {
-        if (!convertGeckoStringToId(cx, names[i], &name))
-            return false;
-        if (!props.append(name))
-            return false;
-    }
-
-    return true;
+    return getPropertyNames(cx, proxy, JSITER_OWNONLY | JSITER_HIDDEN, props);
 }
 
 bool
 CPOWProxyHandler::keys(JSContext *cx, HandleObject proxy, AutoIdVector &props)
 {
     return ParentOf(proxy)->keys(cx, proxy, props);
 }
 
 bool
 JavaScriptParent::keys(JSContext *cx, HandleObject proxy, AutoIdVector &props)
 {
-    ObjectId objId = idOf(proxy);
-
-    ReturnStatus status;
-    InfallibleTArray<nsString> names;
-    if (!CallKeys(objId, &status, &names))
-        return ipcfail(cx);
-    if (!ok(cx, status))
-        return false;
+    return getPropertyNames(cx, proxy, JSITER_OWNONLY, props);
+}
 
-    RootedId name(cx);
-    for (size_t i = 0; i < names.Length(); i++) {
-        if (!convertGeckoStringToId(cx, names[i], &name))
-            return false;
-        if (!props.append(name))
-            return false;
-    }
+bool
+CPOWProxyHandler::enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props)
+{
+    return ParentOf(proxy)->enumerate(cx, proxy, props);
+}
 
-    return true;
+bool
+JavaScriptParent::enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props)
+{
+    return getPropertyNames(cx, proxy, 0, props);
 }
 
 bool
 CPOWProxyHandler::delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
 {
-    MOZ_CRASH("unimplemented");
+    return ParentOf(proxy)->delete_(cx, proxy, id, bp);
 }
 
 bool
-CPOWProxyHandler::enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props)
+JavaScriptParent::delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
 {
-    MOZ_CRASH("unimplemented");
+    ObjectId objId = idOf(proxy);
+
+    nsString idstr;
+    if (!convertIdToGeckoString(cx, id, &idstr))
+        return false;
+
+    ReturnStatus status;
+    if (!CallDelete(objId, idstr, &status, bp))
+        return ipcfail(cx);
+
+    return ok(cx, status);
 }
 
 bool
 CPOWProxyHandler::preventExtensions(JSContext *cx, HandleObject proxy)
 {
     return ParentOf(proxy)->preventExtensions(cx, proxy);
 }
 
@@ -362,23 +369,16 @@ JavaScriptParent::set(JSContext *cx, JS:
 
     if (!ok(cx, status))
         return false;
 
     return toValue(cx, result, vp);
 }
 
 bool
-CPOWProxyHandler::iterate(JSContext *cx, HandleObject proxy, unsigned flags,
-                          MutableHandleValue vp)
-{
-    MOZ_CRASH("unimplemented");
-}
-
-bool
 CPOWProxyHandler::call(JSContext *cx, HandleObject proxy, const CallArgs &args)
 {
     return ParentOf(proxy)->call(cx, proxy, args);
 }
 
 bool
 JavaScriptParent::call(JSContext *cx, HandleObject proxy, const CallArgs &args)
 {
@@ -520,16 +520,39 @@ JavaScriptParent::makeId(JSContext *cx, 
         JS_ReportError(cx, "cannot ipc non-cpow object");
         return false;
     }
 
     *idp = idOf(obj);
     return true;
 }
 
+bool
+JavaScriptParent::getPropertyNames(JSContext *cx, HandleObject proxy, uint32_t flags, AutoIdVector &props)
+{
+    ObjectId objId = idOf(proxy);
+
+    ReturnStatus status;
+    InfallibleTArray<nsString> names;
+    if (!CallGetPropertyNames(objId, flags, &status, &names))
+        return ipcfail(cx);
+    if (!ok(cx, status))
+        return false;
+
+    for (size_t i = 0; i < names.Length(); i++) {
+        RootedId name(cx);
+        if (!convertGeckoStringToId(cx, names[i], &name))
+            return false;
+        if (!props.append(name))
+            return false;
+    }
+
+    return true;
+}
+
 JSObject *
 JavaScriptParent::unwrap(JSContext *cx, ObjectId objId)
 {
     if (JSObject *obj = findObject(objId)) {
         if (!JS_WrapObject(cx, &obj))
             return NULL;
         return obj;
     }
--- a/js/ipc/JavaScriptParent.h
+++ b/js/ipc/JavaScriptParent.h
@@ -36,18 +36,22 @@ class JavaScriptParent
              JS::HandleId id, JS::MutableHandleValue vp);
     bool set(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
              JS::HandleId id, bool strict, JS::MutableHandleValue vp);
     bool call(JSContext *cx, JS::HandleObject proxy, const JS::CallArgs &args);
     bool getPropertyDescriptor(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
                                JSPropertyDescriptor *desc, unsigned flags);
     bool getOwnPropertyDescriptor(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
                                   JSPropertyDescriptor *desc, unsigned flags);
+    bool defineProperty(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
+                        JSPropertyDescriptor *desc);
     bool getOwnPropertyNames(JSContext *cx, JS::HandleObject proxy, js::AutoIdVector &props);
     bool keys(JSContext *cx, JS::HandleObject proxy, js::AutoIdVector &props);
+    bool enumerate(JSContext *cx, JS::HandleObject proxy, js::AutoIdVector &props);
+    bool delete_(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, bool *bp);
     bool objectClassIs(JSContext *cx, JS::HandleObject obj, js::ESClassValue classValue);
     const char* className(JSContext *cx, JS::HandleObject proxy);
     bool preventExtensions(JSContext *cx, JS::HandleObject proxy);
     bool isExtensible(JSContext *cx, JS::HandleObject proxy, bool *extensible);
 
     void decref();
     void incref();
     void destroyFromContent();
@@ -59,16 +63,17 @@ class JavaScriptParent
 
     nsresult instanceOf(JSObject *obj, const nsID *id, bool *bp);
 
   protected:
     JSObject *unwrap(JSContext *cx, ObjectId objId);
 
   private:
     bool makeId(JSContext *cx, JSObject *obj, ObjectId *idp);
+    bool getPropertyNames(JSContext *cx, JS::HandleObject proxy, uint32_t flags, js::AutoIdVector &props);
     ObjectId idOf(JSObject *obj);
 
     // Catastrophic IPC failure.
     bool ipcfail(JSContext *cx);
 
     // Check whether a return status is okay, and if not, propagate its error.
     bool ok(JSContext *cx, const ReturnStatus &status);
 
--- a/js/ipc/PJavaScript.ipdl
+++ b/js/ipc/PJavaScript.ipdl
@@ -27,21 +27,22 @@ child:
     urgent HasOwn(uint64_t objId, nsString id) returns (ReturnStatus rs, bool has);
     urgent Get(uint64_t objId, uint64_t receiverId, nsString id) returns (ReturnStatus rs, JSVariant result);
     urgent Set(uint64_t objId, uint64_t receiverId, nsString id, bool strict, JSVariant value) returns (ReturnStatus rs, JSVariant result);
     urgent Call(uint64_t objId, JSParam[] argv) returns (ReturnStatus rs, JSVariant result, JSParam[] outparams);
 
     urgent InstanceOf(uint64_t objId, JSIID iid) returns (ReturnStatus rs, bool instanceof);
     urgent GetPropertyDescriptor(uint64_t objId, nsString id, uint32_t flags) returns (ReturnStatus rs, PPropertyDescriptor result);
     urgent GetOwnPropertyDescriptor(uint64_t objId, nsString id, uint32_t flags) returns (ReturnStatus rs, PPropertyDescriptor result);
-    urgent GetOwnPropertyNames(uint64_t objId) returns (ReturnStatus rs, nsString[] names);
-    urgent Keys(uint64_t objId) returns (ReturnStatus rs, nsString[] names);
+    urgent DefineProperty(uint64_t objId, nsString id, PPropertyDescriptor descriptor) returns (ReturnStatus rs);
+    urgent GetPropertyNames(uint64_t objId, uint32_t flags) returns (ReturnStatus rs, nsString[] names);
     urgent ObjectClassIs(uint64_t objId, uint32_t classValue) returns (bool result);
     urgent ClassName(uint64_t objId) returns (nsString name);
     urgent IsExtensible(uint64_t objId) returns (ReturnStatus rs, bool result);
     urgent PreventExtensions(uint64_t objId) returns (ReturnStatus rs);
+    urgent Delete(uint64_t objId, nsString id) returns (ReturnStatus rs, bool successful);
 
 parent:
     async __delete__();
 };
 
 }
 }
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -1753,16 +1753,32 @@ SetObjectMetadata(JSContext *cx, JS::Han
 
 JS_FRIEND_API(JSObject *)
 GetObjectMetadata(JSObject *obj);
 
 /* ES5 8.12.8. */
 extern JS_FRIEND_API(JSBool)
 DefaultValue(JSContext *cx, JS::HandleObject obj, JSType hint, MutableHandleValue vp);
 
+/*
+ * Helper function. To approximate a call to the [[DefineOwnProperty]] internal
+ * method described in ES5, first call this, then call JS_DefinePropertyById.
+ *
+ * JS_DefinePropertyById by itself does not enforce the invariants on
+ * non-configurable properties when obj->isNative(). This function performs the
+ * relevant checks (specified in ES5 8.12.9 [[DefineOwnProperty]] steps 1-11),
+ * but only if obj is native.
+ *
+ * The reason for the messiness here is that ES5 uses [[DefineOwnProperty]] as
+ * a sort of extension point, but there is no hook in js::Class,
+ * js::ProxyHandler, or the JSAPI with precisely the right semantics for it.
+ */
+extern JS_FRIEND_API(bool)
+CheckDefineProperty(JSContext *cx, HandleObject obj, HandleId id, HandleValue value,
+                    PropertyOp getter, StrictPropertyOp setter, unsigned attrs);
 
 } /* namespace js */
 
 extern JS_FRIEND_API(JSBool)
 js_DefineOwnProperty(JSContext *cx, JSObject *objArg, jsid idArg,
                      const js::PropertyDescriptor& descriptor, JSBool *bp);
 
 extern JS_FRIEND_API(JSBool)
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -548,17 +548,17 @@ Reject(JSContext *cx, HandleId id, unsig
     *rval = false;
     return true;
 }
 
 // See comments on CheckDefineProperty in jsobj.h.
 //
 // DefinePropertyOnObject has its own implementation of these checks.
 //
-bool
+JS_FRIEND_API(bool)
 js::CheckDefineProperty(JSContext *cx, HandleObject obj, HandleId id, HandleValue value,
                         PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
 {
     if (!obj->isNative())
         return true;
 
     // ES5 8.12.9 Step 1. Even though we know obj is native, we use generic
     // APIs for shorter, more readable code.
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -1548,28 +1548,11 @@ GetFirstArgumentAsObject(JSContext *cx, 
 
 /* Helpers for throwing. These always return false. */
 extern bool
 Throw(JSContext *cx, jsid id, unsigned errorNumber);
 
 extern bool
 Throw(JSContext *cx, JSObject *obj, unsigned errorNumber);
 
-/*
- * Helper function. To approximate a call to the [[DefineOwnProperty]] internal
- * method described in ES5, first call this, then call JS_DefinePropertyById.
- *
- * JS_DefinePropertyById by itself does not enforce the invariants on
- * non-configurable properties when obj->isNative(). This function performs the
- * relevant checks (specified in ES5 8.12.9 [[DefineOwnProperty]] steps 1-11),
- * but only if obj is native.
- *
- * The reason for the messiness here is that ES5 uses [[DefineOwnProperty]] as
- * a sort of extension point, but there is no hook in js::Class,
- * js::ProxyHandler, or the JSAPI with precisely the right semantics for it.
- */
-extern bool
-CheckDefineProperty(JSContext *cx, HandleObject obj, HandleId id, HandleValue value,
-                    PropertyOp getter, StrictPropertyOp setter, unsigned attrs);
-
 }  /* namespace js */
 
 #endif /* jsobj_h */