Make Xrays work correctly with WebIDL global objects.
authorPeter Van der Beken <peterv@propagandism.org>
Sat, 15 Feb 2014 22:12:34 +0100
changeset 171901 59786cc49f53bdf4fabc1f3c38aa45f232fdb046
parent 171900 027b4b685504735a7519082894cf803f7757a8cf
child 171902 15f214a30db78cc872c6667a1a88735995d07fe4
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
milestone30.0a1
Make Xrays work correctly with WebIDL global objects.
dom/bindings/BindingUtils.cpp
dom/bindings/BindingUtils.h
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -873,19 +873,22 @@ QueryInterface(JSContext* cx, unsigned a
 bool
 ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp)
 {
   return ThrowErrorMessage(cx, MSG_ILLEGAL_CONSTRUCTOR);
 }
 
 inline const NativePropertyHooks*
 GetNativePropertyHooks(JSContext *cx, JS::Handle<JSObject*> obj,
-                       DOMObjectType& type)
+                       DOMObjectType& type, bool& isGlobal)
 {
-  const DOMClass* domClass = GetDOMClass(obj);
+  const js::Class* clasp = js::GetObjectClass(obj);
+  isGlobal = (clasp->flags & JSCLASS_DOM_GLOBAL) != 0;
+
+  const DOMClass* domClass = GetDOMClass(clasp);
   if (domClass) {
     type = eInstance;
     return domClass->mNativeHooks;
   }
 
   if (JS_ObjectIsFunction(cx, obj)) {
     MOZ_ASSERT(JS_IsNativeFunction(obj, Constructor));
     type = eInterface;
@@ -921,24 +924,34 @@ XrayResolveNativeProperty(JSContext* cx,
                           JS::MutableHandle<JSPropertyDescriptor> desc);
 
 bool
 XrayResolveOwnProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
                        JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
                        JS::MutableHandle<JSPropertyDescriptor> desc, unsigned flags)
 {
   DOMObjectType type;
+  bool isGlobal;
   const NativePropertyHooks *nativePropertyHooks =
-    GetNativePropertyHooks(cx, obj, type);
+    GetNativePropertyHooks(cx, obj, type, isGlobal);
 
-  if (type != eInstance) {
+  if (type != eInstance || isGlobal) {
     // For prototype objects and interface objects, just return their
-    // normal set of properties.
-    return XrayResolveNativeProperty(cx, wrapper, nativePropertyHooks, type,
-                                     obj, id, desc);
+    // normal set of properties. For global objects the WebIDL properties live
+    // on the instance objects, so resolve those here too.
+    if (!XrayResolveNativeProperty(cx, wrapper, nativePropertyHooks, type,
+                                   obj, id, desc)) {
+      return false;
+    }
+
+    // For non-global objects there are no other properties, so return here
+    // whether we resolved the property or not.
+    if (!isGlobal || desc.object()) {
+      return true;
+    }
   }
 
   // Check for unforgeable properties before doing mResolveOwnProperty weirdness
   const NativePropertiesHolder& nativeProperties =
     nativePropertyHooks->mNativeProperties;
   if (!XrayResolveUnforgeableProperty(cx, wrapper, obj, id, desc,
                                       nativeProperties.regular)) {
     return false;
@@ -1193,25 +1206,36 @@ XrayResolveNativeProperty(JSContext* cx,
 }
 
 bool
 XrayResolveNativeProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
                           JS::Handle<JSObject*> obj,
                           JS::Handle<jsid> id, JS::MutableHandle<JSPropertyDescriptor> desc)
 {
   DOMObjectType type;
+  bool isGlobal;
   const NativePropertyHooks* nativePropertyHooks =
-    GetNativePropertyHooks(cx, obj, type);
+    GetNativePropertyHooks(cx, obj, type, isGlobal);
 
   if (type == eInstance) {
+    if (isGlobal &&
+        !(nativePropertyHooks = nativePropertyHooks->mProtoHooks)) {
+      return true;
+    }
+
     // Force the type to be eInterfacePrototype, since we need to walk the
     // prototype chain.
     type = eInterfacePrototype;
   }
 
+  if (!XrayResolveNativeProperty(cx, wrapper, nativePropertyHooks, type,
+                                 obj, id, desc)) {
+    return false;
+  }
+
   if (type == eInterfacePrototype) {
     do {
       if (!XrayResolveNativeProperty(cx, wrapper, nativePropertyHooks, type,
                                      obj, id, desc)) {
         return false;
       }
 
       if (desc.object()) {
@@ -1388,27 +1412,28 @@ XrayEnumerateNativeProperties(JSContext*
 }
 
 bool
 XrayEnumerateProperties(JSContext* cx, JS::Handle<JSObject*> wrapper,
                         JS::Handle<JSObject*> obj,
                         unsigned flags, JS::AutoIdVector& props)
 {
   DOMObjectType type;
+  bool isGlobal;
   const NativePropertyHooks* nativePropertyHooks =
-    GetNativePropertyHooks(cx, obj, type);
+    GetNativePropertyHooks(cx, obj, type, isGlobal);
 
   if (type == eInstance) {
     if (nativePropertyHooks->mEnumerateOwnProperties &&
         !nativePropertyHooks->mEnumerateOwnProperties(cx, wrapper, obj,
                                                       props)) {
       return false;
     }
 
-    if (flags & JSITER_OWNONLY) {
+    if (!isGlobal && (flags & JSITER_OWNONLY)) {
       return true;
     }
 
     // Force the type to be eInterfacePrototype, since we need to walk the
     // prototype chain.
     type = eInterfacePrototype;
   }
 
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -171,23 +171,25 @@ UnwrapDOMObject(JSObject* obj)
   MOZ_ASSERT(IsDOMClass(js::GetObjectClass(obj)),
              "Don't pass non-DOM objects to this function");
 
   JS::Value val = js::GetReservedSlot(obj, DOM_OBJECT_SLOT);
   return static_cast<T*>(val.toPrivate());
 }
 
 inline const DOMClass*
+GetDOMClass(const js::Class* clasp)
+{
+  return IsDOMClass(clasp) ? &DOMJSClass::FromJSClass(clasp)->mClass : nullptr;
+}
+
+inline const DOMClass*
 GetDOMClass(JSObject* obj)
 {
-  const js::Class* clasp = js::GetObjectClass(obj);
-  if (IsDOMClass(clasp)) {
-    return &DOMJSClass::FromJSClass(clasp)->mClass;
-  }
-  return nullptr;
+  return GetDOMClass(js::GetObjectClass(obj));
 }
 
 inline nsISupports*
 UnwrapDOMObjectToISupports(JSObject* aObject)
 {
   const DOMClass* clasp = GetDOMClass(aObject);
   if (!clasp || !clasp->mDOMObjectIsISupports) {
     return nullptr;