Bug 761695 - Implement expando traps for ProxyXrayTraits DOMXrayTraits. r=peterv
authorBobby Holley <bobbyholley@gmail.com>
Fri, 05 Oct 2012 18:59:23 +0200
changeset 116290 bc5648cb99722667dc9ea4dca572214504b1c16d
parent 116289 509ebfec55a1cf2006e49b8d7897c4e9d0a949ae
child 116291 d8c15d5aeaa238904349eb285887653f1a191aae
push id239
push userakeybl@mozilla.com
push dateThu, 03 Jan 2013 21:54:43 +0000
treeherdermozilla-release@3a7b66445659 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspeterv
bugs761695, 760095
milestone18.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 761695 - Implement expando traps for ProxyXrayTraits DOMXrayTraits. r=peterv For new DOM proxies, we could probably use the Xray expando machinery for the regular expando object as well, and free up one of the reserved slots. That's more than I want to bite off for the moment, though. I also decided not to block on bug 760095 and just kick the problem of globals with new binding down the road a little bit.
dom/bindings/BindingUtils.cpp
dom/bindings/BindingUtils.h
dom/bindings/Codegen.py
dom/bindings/DOMJSClass.h
dom/bindings/DOMJSProxyHandler.h
dom/workers/Worker.cpp
dom/workers/WorkerScope.cpp
js/xpconnect/src/dombindings.cpp
js/xpconnect/src/dombindings.h
js/xpconnect/wrappers/XrayWrapper.cpp
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -624,10 +624,31 @@ HasPropertyOnPrototype(JSContext* cx, JS
   }
   MOZ_ASSERT(js::IsProxy(proxy) && js::GetProxyHandler(proxy) == handler);
 
   bool found;
   // We ignore an error from GetPropertyOnPrototype.
   return !GetPropertyOnPrototype(cx, proxy, id, &found, NULL) || found;
 }
 
+JSObject*
+GetXrayExpandoChain(JSObject* obj)
+{
+  MOZ_ASSERT(IsDOMObject(obj));
+  JS::Value v = IsDOMProxy(obj) ? js::GetProxyExtra(obj, JSPROXYSLOT_XRAY_EXPANDO)
+                                : js::GetReservedSlot(obj, DOM_XRAY_EXPANDO_SLOT);
+  return v.isUndefined() ? nullptr : &v.toObject();
+}
+
+void
+SetXrayExpandoChain(JSObject* obj, JSObject* chain)
+{
+  MOZ_ASSERT(IsDOMObject(obj));
+  JS::Value v = chain ? JS::ObjectValue(*chain) : JSVAL_VOID;
+  if (IsDOMProxy(obj)) {
+    js::SetProxyExtra(obj, JSPROXYSLOT_XRAY_EXPANDO, v);
+  } else {
+    js::SetReservedSlot(obj, DOM_XRAY_EXPANDO_SLOT, v);
+  }
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -1162,12 +1162,17 @@ Take(nsAutoPtr<T>& smartPtr, T* ptr)
   smartPtr = ptr;
 }
 
 inline void
 MustInheritFromNonRefcountedDOMObject(NonRefcountedDOMObject*)
 {
 }
 
+// Set the chain of expando objects for various consumers of the given object.
+// For Paris Bindings only. See the relevant infrastructure in XrayWrapper.cpp.
+JSObject* GetXrayExpandoChain(JSObject *obj);
+void SetXrayExpandoChain(JSObject *obj, JSObject *chain);
+
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_BindingUtils_h__ */
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -101,24 +101,26 @@ def DOMClass(descriptor):
 
 class CGDOMJSClass(CGThing):
     """
     Generate a DOMJSClass for a given descriptor
     """
     def __init__(self, descriptor):
         CGThing.__init__(self)
         self.descriptor = descriptor
+        # Our current reserved slot situation is unsafe for globals. Fix bug 760095!
+        assert "Window" not in descriptor.interface.identifier.name
     def declare(self):
         return "extern DOMJSClass Class;\n"
     def define(self):
         traceHook = TRACE_HOOK_NAME if self.descriptor.customTrace else 'NULL'
         return """
 DOMJSClass Class = {
   { "%s",
-    JSCLASS_IS_DOMJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(1),
+    JSCLASS_IS_DOMJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(2),
     %s, /* addProperty */
     JS_PropertyStub,       /* delProperty */
     JS_PropertyStub,       /* getProperty */
     JS_StrictPropertyStub, /* setProperty */
     JS_EnumerateStub,
     JS_ResolveStub,
     JS_ConvertStub,
     %s, /* finalize */
--- a/dom/bindings/DOMJSClass.h
+++ b/dom/bindings/DOMJSClass.h
@@ -10,16 +10,21 @@
 #include "jsfriendapi.h"
 
 #include "mozilla/dom/PrototypeList.h" // auto-generated
 
 // We use slot 0 for holding the raw object.  This is safe for both
 // globals and non-globals.
 #define DOM_OBJECT_SLOT 0
 
+// We use slot 1 for holding the expando object. This is not safe for globals
+// until bug 760095 is fixed, so that bug blocks converting Window to new
+// bindings.
+#define DOM_XRAY_EXPANDO_SLOT 1
+
 // All DOM globals must have a slot at DOM_PROTOTYPE_SLOT. We have to
 // start at 1 past JSCLASS_GLOBAL_SLOT_COUNT because XPConnect uses
 // that one.
 #define DOM_PROTOTYPE_SLOT (JSCLASS_GLOBAL_SLOT_COUNT + 1)
 
 // We use these flag bits for the new bindings.
 #define JSCLASS_DOM_GLOBAL JSCLASS_USERBIT1
 
--- a/dom/bindings/DOMJSProxyHandler.h
+++ b/dom/bindings/DOMJSProxyHandler.h
@@ -14,17 +14,18 @@
 #include "mozilla/Likely.h"
 
 #define DOM_PROXY_OBJECT_SLOT js::JSSLOT_PROXY_PRIVATE
 
 namespace mozilla {
 namespace dom {
 
 enum {
-  JSPROXYSLOT_EXPANDO = 0
+  JSPROXYSLOT_EXPANDO = 0,
+  JSPROXYSLOT_XRAY_EXPANDO
 };
 
 template<typename T> struct Prefable;
 
 class DOMProxyHandler : public DOMBaseProxyHandler
 {
 public:
   DOMProxyHandler(const DOMClass& aClass)
--- a/dom/workers/Worker.cpp
+++ b/dom/workers/Worker.cpp
@@ -299,17 +299,17 @@ private:
 MOZ_STATIC_ASSERT(prototypes::MaxProtoChainLength == 3,
                   "The MaxProtoChainLength must match our manual DOMJSClasses");
 
 // When this DOMJSClass is removed and it's the last consumer of
 // sNativePropertyHooks then sNativePropertyHooks should be removed too.
 DOMJSClass Worker::sClass = {
   {
     "Worker",
-    JSCLASS_IS_DOMJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(1) |
+    JSCLASS_IS_DOMJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(2) |
     JSCLASS_IMPLEMENTS_BARRIERS,
     JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
     JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize,
     NULL, NULL, NULL, NULL, Trace
   },
   {
     { prototypes::id::EventTarget_workers, prototypes::id::_ID_Count,
       prototypes::id::_ID_Count },
@@ -424,17 +424,17 @@ private:
 
 MOZ_STATIC_ASSERT(prototypes::MaxProtoChainLength == 3,
                   "The MaxProtoChainLength must match our manual DOMJSClasses");
 
 // When this DOMJSClass is removed and it's the last consumer of
 // sNativePropertyHooks then sNativePropertyHooks should be removed too.
 DOMJSClass ChromeWorker::sClass = {
   { "ChromeWorker",
-    JSCLASS_IS_DOMJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(1) |
+    JSCLASS_IS_DOMJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(2) |
     JSCLASS_IMPLEMENTS_BARRIERS,
     JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
     JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize,
     NULL, NULL, NULL, NULL, Trace,
   },
   {
     { prototypes::id::EventTarget_workers, prototypes::id::_ID_Count,
       prototypes::id::_ID_Count },
--- a/dom/workers/WorkerScope.cpp
+++ b/dom/workers/WorkerScope.cpp
@@ -851,16 +851,18 @@ private:
 
 MOZ_STATIC_ASSERT(prototypes::MaxProtoChainLength == 3,
                   "The MaxProtoChainLength must match our manual DOMJSClasses");
 
 // When this DOMJSClass is removed and it's the last consumer of
 // sNativePropertyHooks then sNativePropertyHooks should be removed too.
 DOMJSClass DedicatedWorkerGlobalScope::sClass = {
   {
+    // We don't have to worry about Xray expando slots here because we'll never
+    // have an Xray wrapper to a worker global scope.
     "DedicatedWorkerGlobalScope",
     JSCLASS_DOM_GLOBAL | JSCLASS_IS_DOMJSCLASS | JSCLASS_IMPLEMENTS_BARRIERS |
     JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(3) | JSCLASS_NEW_RESOLVE,
     JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
     JS_EnumerateStub, reinterpret_cast<JSResolveOp>(Resolve), JS_ConvertStub,
     Finalize, NULL, NULL, NULL, NULL, Trace
   },
   {
--- a/js/xpconnect/src/dombindings.cpp
+++ b/js/xpconnect/src/dombindings.cpp
@@ -23,17 +23,18 @@
 using namespace JS;
 using namespace mozilla::dom;
 
 namespace mozilla {
 namespace dom {
 namespace oldproxybindings {
 
 enum {
-    JSPROXYSLOT_EXPANDO = 0
+    JSPROXYSLOT_EXPANDO = 0,
+    JSPROXYSLOT_XRAY_EXPANDO
 };
 
 static jsid s_prototype_id = JSID_VOID;
 
 static jsid s_length_id = JSID_VOID;
 
 static jsid s_iterator_id = JSID_VOID;
 
@@ -1008,13 +1009,26 @@ JSObject*
 NoBase::getPrototype(JSContext *cx, XPCWrappedNativeScope *scope, JSObject *receiver)
 {
     // We need to pass the object prototype to JS_NewObject. If we pass NULL then the JS engine
     // will look up a prototype on the global by using the class' name and we'll recurse into
     // getPrototype.
     return JS_GetObjectPrototype(cx, receiver);
 }
 
+JSObject*
+GetXrayExpandoChain(JSObject *obj) {
+    MOZ_ASSERT(instanceIsProxy(obj));
+    js::Value v = js::GetProxyExtra(obj, JSPROXYSLOT_XRAY_EXPANDO);
+    return v.isUndefined() ? nullptr : &v.toObject();
+}
+
+void
+SetXrayExpandoChain(JSObject *obj, JSObject *chain) {
+    MOZ_ASSERT(instanceIsProxy(obj));
+    js::Value v = chain ? JS::ObjectValue(*chain) : JSVAL_VOID;
+    js::SetProxyExtra(obj, JSPROXYSLOT_XRAY_EXPANDO, v);
+}
 
 }
 }
 }
 #include "dombindings_gen.cpp"
--- a/js/xpconnect/src/dombindings.h
+++ b/js/xpconnect/src/dombindings.h
@@ -208,15 +208,18 @@ struct nsISupportsResult
 {
     nsISupportsResult()
     {
     }
     nsISupports *mResult;
     nsWrapperCache *mCache;
 };
 
+JSObject* GetXrayExpandoChain(JSObject *obj);
+void SetXrayExpandoChain(JSObject *obj, JSObject *chain);
+
 }
 }
 }
 
 #include "dombindings_gen.h"
 
 #endif /* dombindings_h */
--- a/js/xpconnect/wrappers/XrayWrapper.cpp
+++ b/js/xpconnect/wrappers/XrayWrapper.cpp
@@ -17,16 +17,17 @@
 
 #include "XPCWrapper.h"
 #include "xpcprivate.h"
 
 #include "jsapi.h"
 #include "nsJSUtils.h"
 
 #include "mozilla/dom/BindingUtils.h"
+#include "dombindings.h"
 
 using namespace mozilla::dom;
 
 namespace xpc {
 
 using namespace js;
 
 static const uint32_t JSSLOT_RESOLVING = 0;
@@ -233,21 +234,20 @@ public:
 
     virtual void preserveWrapper(JSObject *target) { };
 
     typedef ResolvingIdDummy ResolvingIdImpl;
 
     virtual JSObject* createHolder(JSContext *cx, JSObject *wrapper);
 
     virtual JSObject* getExpandoChain(JSObject *obj) {
-        MOZ_NOT_REACHED("Expando chain not yet implemented for non-WN objects");
-        return NULL;
+        return mozilla::dom::oldproxybindings::GetXrayExpandoChain(obj);
     }
     virtual void setExpandoChain(JSObject *obj, JSObject *chain) {
-        MOZ_NOT_REACHED("Expando chain not yet implemented for non-WN objects");
+        mozilla::dom::oldproxybindings::SetXrayExpandoChain(obj, chain);
     }
 
     static ProxyXrayTraits singleton;
 };
 
 class DOMXrayTraits : public XrayTraits
 {
 public:
@@ -269,21 +269,20 @@ public:
 
     typedef ResolvingIdDummy ResolvingIdImpl;
 
     virtual void preserveWrapper(JSObject *target);
 
     virtual JSObject* createHolder(JSContext *cx, JSObject *wrapper);
 
     virtual JSObject* getExpandoChain(JSObject *obj) {
-        MOZ_NOT_REACHED("Expando chain not yet implemented for non-WN objects");
-        return NULL;
+        return mozilla::dom::GetXrayExpandoChain(obj);
     }
     virtual void setExpandoChain(JSObject *obj, JSObject *chain) {
-        MOZ_NOT_REACHED("Expando chain not yet implemented for non-WN objects");
+        mozilla::dom::SetXrayExpandoChain(obj, chain);
     }
 
     static DOMXrayTraits singleton;
 };
 
 XPCWrappedNativeXrayTraits XPCWrappedNativeXrayTraits::singleton;
 ProxyXrayTraits ProxyXrayTraits::singleton;
 DOMXrayTraits DOMXrayTraits::singleton;