Bug 890729 - Implement the missing CPOW traps. r=dvander
authorTom Schuster <evilpies@gmail.com>
Tue, 09 Jul 2013 22:45:08 -0400
changeset 150232 5b1d4377a538fcdafdc22e7b752e3491961008fe
parent 150231 14de59ee10a93f73f7f097ef9facd4bed9109074
child 150233 0dc84a9f29102d46e9601ea7fdbba86655797ffc
push id2859
push userakeybl@mozilla.com
push dateMon, 16 Sep 2013 19:14:59 +0000
treeherdermozilla-beta@87d3c51cd2bf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdvander
bugs890729
milestone25.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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 */