Bug 838691 part 1. Add support in Prefable for calling a function to determine whether a property should be exposed in a WebIDL binding. r=peterv
authorBoris Zbarsky <bzbarsky@mit.edu>
Tue, 19 Feb 2013 11:54:40 -0500
changeset 128769 83952a3e9b74a352497137c10e1c3927c92f7b31
parent 128768 f71e6d7c7ea373856006668e7aff187c2b066328
child 128770 35231869058aa71ac66801158f7a9fbe4b508313
push id3582
push userbbajaj@mozilla.com
push dateMon, 01 Apr 2013 20:50:56 +0000
treeherdermozilla-aurora@400370bbc9fa [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspeterv
bugs838691
milestone21.0a1
Bug 838691 part 1. Add support in Prefable for calling a function to determine whether a property should be exposed in a WebIDL binding. r=peterv
dom/bindings/BindingUtils.cpp
dom/bindings/Codegen.py
dom/bindings/DOMJSClass.h
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -180,17 +180,17 @@ Define(JSContext* cx, JSObject* obj, Con
 template<typename T>
 bool
 DefinePrefable(JSContext* cx, JSObject* obj, Prefable<T>* props)
 {
   MOZ_ASSERT(props);
   MOZ_ASSERT(props->specs);
   do {
     // Define if enabled
-    if (props->enabled) {
+    if (props->isEnabled(cx, obj)) {
       if (!Define(cx, obj, props->specs)) {
         return false;
       }
     }
   } while ((++props)->specs);
   return true;
 }
 
@@ -693,22 +693,22 @@ XrayResolveOwnProperty(JSContext* cx, JS
     GetNativePropertyHooks(cx, obj, type);
 
   return type != eInstance || !nativePropertyHooks->mResolveOwnProperty ||
          nativePropertyHooks->mResolveOwnProperty(cx, wrapper, obj, id, desc,
                                                   flags);
 }
 
 static bool
-XrayResolveAttribute(JSContext* cx, JSObject* wrapper, jsid id,
+XrayResolveAttribute(JSContext* cx, JSObject* wrapper, JSObject* obj, jsid id,
                      Prefable<JSPropertySpec>* attributes, jsid* attributeIds,
                      JSPropertySpec* attributeSpecs, JSPropertyDescriptor* desc)
 {
   for (; attributes->specs; ++attributes) {
-    if (attributes->enabled) {
+    if (attributes->isEnabled(cx, obj)) {
       // Set i to be the index into our full list of ids/specs that we're
       // looking at now.
       size_t i = attributes->specs - attributeSpecs;
       for ( ; attributeIds[i] != JSID_VOID; ++i) {
         if (id == attributeIds[i]) {
           JSPropertySpec& attrSpec = attributeSpecs[i];
           // Because of centralization, we need to make sure we fault in the
           // JitInfos as well. At present, until the JSAPI changes, the easiest
@@ -742,17 +742,17 @@ XrayResolveAttribute(JSContext* cx, JSOb
         }
       }
     }
   }
   return true;
 }
 
 static bool
-XrayResolveProperty(JSContext* cx, JSObject* wrapper, jsid id,
+XrayResolveProperty(JSContext* cx, JSObject* wrapper, JSObject* obj, jsid id,
                     JSPropertyDescriptor* desc, DOMObjectType type,
                     const NativeProperties* nativeProperties)
 {
   Prefable<JSFunctionSpec>* methods;
   jsid* methodIds;
   JSFunctionSpec* methodsSpecs;
   if (type == eInterface) {
     methods = nativeProperties->staticMethods;
@@ -761,17 +761,17 @@ XrayResolveProperty(JSContext* cx, JSObj
   } else {
     methods = nativeProperties->methods;
     methodIds = nativeProperties->methodIds;
     methodsSpecs = nativeProperties->methodsSpecs;
   }
   if (methods) {
     Prefable<JSFunctionSpec>* method;
     for (method = methods; method->specs; ++method) {
-      if (method->enabled) {
+      if (method->isEnabled(cx, obj)) {
         // Set i to be the index into our full list of ids/specs that we're
         // looking at now.
         size_t i = method->specs - methodsSpecs;
         for ( ; methodIds[i] != JSID_VOID; ++i) {
           if (id == methodIds[i]) {
             JSFunctionSpec& methodSpec = methodsSpecs[i];
             JSFunction *fun = JS_NewFunctionById(cx, methodSpec.call.op,
                                                  methodSpec.nargs, 0,
@@ -790,56 +790,56 @@ XrayResolveProperty(JSContext* cx, JSObj
           }
         }
       }
     }
   }
 
   if (type == eInterface) {
     if (nativeProperties->staticAttributes) {
-      if (!XrayResolveAttribute(cx, wrapper, id,
+      if (!XrayResolveAttribute(cx, wrapper, obj, id,
                                 nativeProperties->staticAttributes,
                                 nativeProperties->staticAttributeIds,
                                 nativeProperties->staticAttributeSpecs, desc)) {
         return false;
       }
       if (desc->obj) {
         return true;
       }
     }
   } else {
     if (nativeProperties->attributes) {
-      if (!XrayResolveAttribute(cx, wrapper, id,
+      if (!XrayResolveAttribute(cx, wrapper, obj, id,
                                 nativeProperties->attributes,
                                 nativeProperties->attributeIds,
                                 nativeProperties->attributeSpecs, desc)) {
         return false;
       }
       if (desc->obj) {
         return true;
       }
     }
     if (nativeProperties->unforgeableAttributes) {
-      if (!XrayResolveAttribute(cx, wrapper, id,
+      if (!XrayResolveAttribute(cx, wrapper, obj, id,
                                 nativeProperties->unforgeableAttributes,
                                 nativeProperties->unforgeableAttributeIds,
                                 nativeProperties->unforgeableAttributeSpecs,
                                 desc)) {
         return false;
       }
       if (desc->obj) {
         return true;
       }
     }
   }
 
   if (nativeProperties->constants) {
     Prefable<ConstantSpec>* constant;
     for (constant = nativeProperties->constants; constant->specs; ++constant) {
-      if (constant->enabled) {
+      if (constant->isEnabled(cx, obj)) {
         // Set i to be the index into our full list of ids/specs that we're
         // looking at now.
         size_t i = constant->specs - nativeProperties->constantSpecs;
         for ( ; nativeProperties->constantIds[i] != JSID_VOID; ++i) {
           if (id == nativeProperties->constantIds[i]) {
             desc->attrs = JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT;
             desc->obj = wrapper;
             desc->value = nativeProperties->constantSpecs[i].value;
@@ -896,25 +896,25 @@ XrayResolveNativeProperty(JSContext* cx,
                                          nativePropertyHooks->mConstructorID,
                                          0, desc);
   }
 
   const NativePropertiesHolder& nativeProperties =
     nativePropertyHooks->mNativeProperties;
 
   if (nativeProperties.regular &&
-      !XrayResolveProperty(cx, wrapper, id, desc, type,
+      !XrayResolveProperty(cx, wrapper, obj, id, desc, type,
                            nativeProperties.regular)) {
     return false;
   }
 
   if (!desc->obj &&
       nativeProperties.chromeOnly &&
       xpc::AccessCheck::isChrome(js::GetObjectCompartment(wrapper)) &&
-      !XrayResolveProperty(cx, wrapper, id, desc, type,
+      !XrayResolveProperty(cx, wrapper, obj, id, desc, type,
                            nativeProperties.chromeOnly)) {
     return false;
   }
 
   return true;
 }
 
 bool
@@ -946,39 +946,41 @@ XrayResolveNativeProperty(JSContext* cx,
     return true;
   }
 
   return XrayResolveNativeProperty(cx, wrapper, nativePropertyHooks, type, obj,
                                    id, desc);
 }
 
 bool
-XrayEnumerateAttributes(Prefable<JSPropertySpec>* attributes,
+XrayEnumerateAttributes(JSContext* cx, JSObject* wrapper, JSObject* obj,
+                        Prefable<JSPropertySpec>* attributes,
                         jsid* attributeIds, JSPropertySpec* attributeSpecs,
                         unsigned flags, JS::AutoIdVector& props)
 {
   for (; attributes->specs; ++attributes) {
-    if (attributes->enabled) {
+    if (attributes->isEnabled(cx, obj)) {
       // Set i to be the index into our full list of ids/specs that we're
       // looking at now.
       size_t i = attributes->specs - attributeSpecs;
       for ( ; attributeIds[i] != JSID_VOID; ++i) {
         if (((flags & JSITER_HIDDEN) ||
              (attributeSpecs[i].flags & JSPROP_ENUMERATE)) &&
             !props.append(attributeIds[i])) {
           return false;
         }
       }
     }
   }
   return true;
 }
 
 bool
-XrayEnumerateProperties(unsigned flags, JS::AutoIdVector& props,
+XrayEnumerateProperties(JSContext* cx, JSObject* wrapper, JSObject* obj,
+                        unsigned flags, JS::AutoIdVector& props,
                         DOMObjectType type,
                         const NativeProperties* nativeProperties)
 {
   Prefable<JSFunctionSpec>* methods;
   jsid* methodIds;
   JSFunctionSpec* methodsSpecs;
   if (type == eInterface) {
     methods = nativeProperties->staticMethods;
@@ -987,60 +989,63 @@ XrayEnumerateProperties(unsigned flags, 
   } else {
     methods = nativeProperties->methods;
     methodIds = nativeProperties->methodIds;
     methodsSpecs = nativeProperties->methodsSpecs;
   }
   if (methods) {
     Prefable<JSFunctionSpec>* method;
     for (method = methods; method->specs; ++method) {
-      if (method->enabled) {
+      if (method->isEnabled(cx, obj)) {
         // Set i to be the index into our full list of ids/specs that we're
         // looking at now.
         size_t i = method->specs - methodsSpecs;
         for ( ; methodIds[i] != JSID_VOID; ++i) {
           if (((flags & JSITER_HIDDEN) ||
                (methodsSpecs[i].flags & JSPROP_ENUMERATE)) &&
               !props.append(methodIds[i])) {
             return false;
           }
         }
       }
     }
   }
 
   if (type == eInterface) {
     if (nativeProperties->staticAttributes &&
-        !XrayEnumerateAttributes(nativeProperties->staticAttributes,
+        !XrayEnumerateAttributes(cx, wrapper, obj,
+                                 nativeProperties->staticAttributes,
                                  nativeProperties->staticAttributeIds,
                                  nativeProperties->staticAttributeSpecs,
                                  flags, props)) {
       return false;
     }
   } else {
     if (nativeProperties->attributes &&
-        !XrayEnumerateAttributes(nativeProperties->attributes,
+        !XrayEnumerateAttributes(cx, wrapper, obj,
+                                 nativeProperties->attributes,
                                  nativeProperties->attributeIds,
                                  nativeProperties->attributeSpecs,
                                  flags, props)) {
       return false;
     }
     if (nativeProperties->unforgeableAttributes &&
-        !XrayEnumerateAttributes(nativeProperties->unforgeableAttributes,
+        !XrayEnumerateAttributes(cx, wrapper, obj,
+                                 nativeProperties->unforgeableAttributes,
                                  nativeProperties->unforgeableAttributeIds,
                                  nativeProperties->unforgeableAttributeSpecs,
                                  flags, props)) {
       return false;
     }
   }
 
   if (nativeProperties->constants) {
     Prefable<ConstantSpec>* constant;
     for (constant = nativeProperties->constants; constant->specs; ++constant) {
-      if (constant->enabled) {
+      if (constant->isEnabled(cx, obj)) {
         // Set i to be the index into our full list of ids/specs that we're
         // looking at now.
         size_t i = constant->specs - nativeProperties->constantSpecs;
         for ( ; nativeProperties->constantIds[i] != JSID_VOID; ++i) {
           if (!props.append(nativeProperties->constantIds[i])) {
             return false;
           }
         }
@@ -1069,23 +1074,25 @@ XrayEnumerateNativeProperties(JSContext*
       !AddStringToIDVector(cx, props, "constructor")) {
     return false;
   }
 
   const NativePropertiesHolder& nativeProperties =
     nativePropertyHooks->mNativeProperties;
 
   if (nativeProperties.regular &&
-      !XrayEnumerateProperties(flags, props, type, nativeProperties.regular)) {
+      !XrayEnumerateProperties(cx, wrapper, obj, flags, props, type,
+                               nativeProperties.regular)) {
     return false;
   }
 
   if (nativeProperties.chromeOnly &&
       xpc::AccessCheck::isChrome(js::GetObjectCompartment(wrapper)) &&
-      !XrayEnumerateProperties(flags, props, type, nativeProperties.chromeOnly)) {
+      !XrayEnumerateProperties(cx, wrapper, obj, flags, props, type,
+                               nativeProperties.chromeOnly)) {
     return false;
   }
 
   return true;
 }
 
 bool
 XrayEnumerateProperties(JSContext* cx, JSObject* wrapper, JSObject* obj,
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -1081,17 +1081,17 @@ class PropertyDefiner:
         # pref control is added to members while still allowing us to define all
         # the members in the smallest number of JSAPI calls.
         assert(len(array) is not 0)
         lastPref = getPref(array[0]) # So we won't put a specTerminator
                                      # at the very front of the list.
         specs = []
         prefableSpecs = []
 
-        prefableTemplate = '  { true, &%s[%d] }'
+        prefableTemplate = '  { true, nullptr, &%s[%d] }'
         prefCacheTemplate = '&%s[%d].enabled'
         def switchToPref(props, pref):
             # Remember the info about where our pref-controlled
             # booleans live.
             if pref is not None:
                 props.prefCacheData.append(
                     (pref, prefCacheTemplate % (name, len(prefableSpecs)))
                     )
--- a/dom/bindings/DOMJSClass.h
+++ b/dom/bindings/DOMJSClass.h
@@ -57,20 +57,32 @@ typedef bool
                            JS::AutoIdVector& props);
 
 struct ConstantSpec
 {
   const char* name;
   JS::Value value;
 };
 
+typedef bool (*PropertyEnabled)(JSContext* cx, JSObject* global);
+
 template<typename T>
 struct Prefable {
+  inline bool isEnabled(JSContext* cx, JSObject* obj) {
+    return enabled &&
+      (!enabledFunc ||
+       enabledFunc(cx, js::GetGlobalForObjectCrossCompartment(obj)));
+  }
+
   // A boolean indicating whether this set of specs is enabled
   bool enabled;
+  // A function pointer to a function that can say the property is disabled
+  // even if "enabled" is set to true.  If the pointer is null the value of
+  // "enabled" is used as-is.
+  PropertyEnabled enabledFunc;
   // Array of specs, terminated in whatever way is customary for T.
   // Null to indicate a end-of-array for Prefable, when such an
   // indicator is needed.
   T* specs;
 };
 
 struct NativeProperties
 {